如何在JOIN查询中匹配多个条件

时间:2019-11-05 09:31:53

标签: sql sqlite

我想检索所有符合多个加入条件的用户。

这是此数据库的简化示例:

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个选择查询。

是否有更好的解决方案来创建子查询?

5 个答案:

答案 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;