我想检索所有符合多个加入条件的用户。
这是此数据库的简化示例:
create table users(id int, name varchar);
insert into users values(1, "caroline");
insert into users values(2, "simon");
insert into users values(3, "jose");
insert into users values(4, "robert");
create table tags(value varchar, user_id integer);
insert into tags values("a", 1); insert into tags values("b", 1);
insert into tags values("a", 2);insert into tags values("b", 3);
insert into tags values("c", 4);
我想让用户拥有标签“ a”和标签“ b”(caroline)。
如果我运行以下查询:
SELECT * from users INNER JOIN tags ON users.id = tags.user_id WHERE tags.value IN ('a', 'b');
它返回与两个条件之一匹配的所有用户:
1|caroline|a|1
1|caroline|b|1
2|simon|a|2
3|jose|b|3
如果我运行此查询:
SELECT * FROM users where users.id IN (
SELECT users.id from users INNER JOIN tags ON users.id = tags.user_id WHERE tags.value = 'a'
INTERSECT
SELECT users.id from users INNER JOIN tags ON users.id = tags.user_id WHERE tags.value = 'b');
有效。只有卡罗琳才回来。
但是在这种情况下,它是3个选择查询。但这是实际用法,如果我要搜索5个标签,它将是6个选择查询。
是否有更好的解决方案来创建子查询?
答案 0 :(得分:2)
您可以使用聚合:
select u.id, u.name
from users u
inner join tags t on u.id = t.user_id
where t.value in ('a', 'b')
group by u.id, u.name
having count(distinct t.value) = 2
该查询将同一用户的所有tags
记录分组,对标记值列表进行过滤,并确保它们都存在。
如果要检查6个标签,则可以执行以下操作:
select u.id, u.name
from users u
inner join tags t on u.id = t.user_id
where t.value in ('a', 'b', 'c', 'd', 'e', 'f')
group by u.id, u.name
having count(distinct t.value) = 6
答案 1 :(得分:1)
一种方法使用聚合来查找同时具有两个所需标签的用户。然后,加入users
表以输入实际的用户名。
SELECT
u.id,
u.name
FROM users u
INNER JOIN
(
SELECT user_id
FROM tags
WHERE value IN ('a', 'b')
GROUP BY user_id
HAVING MIN(value) <> MAX(value)
) t
ON u.id = t.user_id;
使用自我加入的另一种选择:
SELECT
u.id,
u.name
FROM users u
INNER JOIN tags t1
ON u.id = t1.user_id
INNER JOIN tags t2
ON u.id = t2.user_id
WHERE
t1.value = 'a' AND
t2.value = 'b';
答案 2 :(得分:1)
有多种解决方案。 一种可能是对需要检查的每个标签使用标签表上的联接:
SELECT u.id, u.name FROM users u
INNER JOIN tags t1 ON (u.id = t1.user_id AND t1.value = 'a')
INNER JOIN tags t2 ON (u.id = t2.user_id AND t2.value = 'b');
另一个可能是使用group_concat:
SELECT u.id, u.name, GROUP_CONCAT(t.value ORDER BY t.value)
FROM users u
JOIN tags t on u.id = t.user_id
GROUP BY u.id, u.name
HAVING GROUP_CONCAT(t.value) = 'a,b'
为确保获得与a和b以外的其他标签匹配的用户,可以使用以下方式更改having子句:
HAVING GROUP_CONCAT(t.value) LIKE '%a%b%'
答案 3 :(得分:0)
您也可以多次针对同一张表
SELECT users.name FROM users
INNER JOIN tags t1 ON users.id = t1.user_id AND t1.value = 'a'
INNER JOIN tags t2 ON users.id = t1.user_id AND t1.value = 'b'
WHERE t1.user_id=t2.user_id
AND users.id=t1.user_id
不确定哪个答案更有效?
答案 4 :(得分:0)
您可以根据需要更改cn > 1
。 (例如:如果要搜索5个标签,则cn > 4
)
SELECT * FROM (
SELECT name, count(*) cn FROM users
INNER JOIN tags ON
users.id = tags.user_id
WHERE tags.value IN ('a', 'b')
group by name
) WHERE cn > 1;