Mysql SQL-连接更多表而不是(子查询)
我有一个users表-包含id\u user和一些其他列…然后还有一些其他表存储用户连接,这些连接总是与结构id\u user\u one、id\u user\u two、active一起使用,其中用户可以是id\u user\u one或id\u user\u two。还请注意,在每个连接表中,两个用户之间可以有连接,例如,朋友表中的一条记录和家庭表中的一条记录 这里有一个表,表中有posts id\u post,id\u user,…其他一些列 所以现在我想获取特定用户和与他相关的用户的所有帖子 到目前为止,我知道213是一个特殊的id_用户,示例连接表是朋友和家人,但可能会有更多Mysql SQL-连接更多表而不是(子查询),mysql,sql,Mysql,Sql,我有一个users表-包含id\u user和一些其他列…然后还有一些其他表存储用户连接,这些连接总是与结构id\u user\u one、id\u user\u two、active一起使用,其中用户可以是id\u user\u one或id\u user\u two。还请注意,在每个连接表中,两个用户之间可以有连接,例如,朋友表中的一条记录和家庭表中的一条记录 这里有一个表,表中有posts id\u post,id\u user,…其他一些列 所以现在我想获取特定用户和与他相关的用户的所有
SELECT * FROM posts NATURAL JOIN users
WHERE id_user IN (
SELECT * FROM(
(SELECT 213 as id_user)
UNION
(SELECT id_user FROM friends WHERE (id_user_one=213 OR id_user_two=213) AND active=1)
UNION
(SELECT id_user FROM family WHERE (id_user_one=213 OR id_user_two=213) AND active=1)
) idList
)
这是可行的,但我的问题是如何使用联接而不是INsubquery来实现这一点
或者,对于这种情况,使用INsubquery是一种更有效的方法吗
编辑:我在原始查询中出错:
(SELECT id_user FROM friends WHERE (id_user_one=213 OR id_user_two=213) AND active=1)
应该是:
(SELECT id_user_two as id_user FROM kontakty WHERE id_user_one=213 AND active=1)
UNION
(SELECT id_user_one as id_user FROM kontakty WHERE id_user_two=213 AND active=1)
……家庭部分也是如此……因此,了解了这一点,并根据公认的答案,我成功地进行了最后的查询,我想分享这些知识,以便:
以下是我的最终解决方案:
只需为查询指定一个名称:
SELECT *
FROM posts
NATURAL JOIN users
JOIN (SELECT * FROM(
(SELECT 213 as id_user)
UNION
(SELECT id_user FROM friends WHERE (id_user_one=213 OR id_user_two=213) AND active=1)
UNION
(SELECT id_user FROM family WHERE (id_user_one=213 OR id_user_two=213) AND active=1)
) idList ON idList.id_user = users.id_user
以下是一个mpre高效查询:
SELECT *
FROM posts p JOIN
users u
on p.id_user = u.id_user
WHERE u.id_user = 213 or
exists (select 1
from friends f
where (f.id_user_one=213 OR f.id_user_two=213) and f.active = 1 and
u.id_user = f.id_user
) or
exists (select 1
from family f
where (f.id_user_one = 213 OR f.id_user_two = 213) and f.active = 1 and
u.id_user = f.id_user
);
然后,在friendsid_user、active、id_user_one、id_user_two上有一个索引,在family上有一个类似的索引,这个查询将更加高效。这些索引覆盖了查询,因此不需要原始数据页,只需要索引
在where子句中切换到ors而不是union会给您带来一些好处。首先,不必返回整个结果即可获得匹配。第二,条件短路,因此第一个匹配条件结束比较。第三,也是最重要的一点,引擎可以利用表上的索引
我认为,如果表被正确地索引,那么尝试创建联接不会更好
将自然联接更改为联接不会影响性能。我只是不喜欢自然连接,因为你看不到连接条件——随着时间的推移,会导致代码维护问题
编辑:
我怀疑这就是您想要的查询:
SELECT *
FROM posts p JOIN
users u
on p.id_user = u.id_user
WHERE u.id_user = 213 or
exists (select 1
from friends f
where (f.id_user_one=213 OR f.id_user_two=213) and f.active = 1 and
(u.id_user = f.id_user_one or u.id_user = f.id_user_two)
) or
exists (select 1
from family f
where (f.id_user_one = 213 OR f.id_user_two = 213) and f.active = 1 and
(u.id_user = f.id_user_one or u.id_user = f.id_user_two)
);
哪里有。。。顺便说一句:UNION返回唯一的结果。因为除了IN子句之外,您没有将这些结果用于其他任何内容,所以没有理由不使用UNION ALL,这应该会快一点。@Mureinik所以您认为在IN中有重复项比先删除这些重复项更快?@jave.web如果IN实现正确并且在第一次出现时提前返回,那么应该是这样的。话虽如此,我并没有在任何最新的MySQL版本上对此进行基准测试。我修改了内部查询-联合,但@Gordon Linoff的回答涵盖了实际问题,但仍然非常感谢。你可能是对的!我在那里输入了一个错误-id\u用户从朋友中选择应该是id\u用户作为id\u用户-无论如何你是对的,这是错误的-应该有一个联盟覆盖其他可能性这不会正常工作,而且我不确定其他事情是否是由我添加的额外查询引起的,至于答案,这是对这个问题的回答:对你的编辑:是的,有点像那样,但有点不同-见我的编辑:,PS:删除无用的评论
SELECT *
FROM posts p JOIN
users u
on p.id_user = u.id_user
WHERE u.id_user = 213 or
exists (select 1
from friends f
where (f.id_user_one=213 OR f.id_user_two=213) and f.active = 1 and
(u.id_user = f.id_user_one or u.id_user = f.id_user_two)
) or
exists (select 1
from family f
where (f.id_user_one = 213 OR f.id_user_two = 213) and f.active = 1 and
(u.id_user = f.id_user_one or u.id_user = f.id_user_two)
);