Как сопоставить несколько условий по запросу JOIN - PullRequest
1 голос
/ 05 ноября 2019

Я хочу получить всех пользователей, которые соответствуют нескольким условиям объединения.

Вот упрощенный пример с этой базой данных:

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' (каролина).

Если я выполню этот запрос: 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 ]

2 голосов
/ 05 ноября 2019

Вы можете использовать агрегацию:

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 голос
/ 05 ноября 2019

Есть несколько решений. Можно использовать объединения в таблице тегов для каждого тега, который необходимо проверить:

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 GROUP_CONCAT(t.value) LIKE '%a%b%'
1 голос
/ 05 ноября 2019

Один подход использует агрегацию, чтобы найти пользователей, имеющих оба желаемых тега. Затем присоединитесь к таблице 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';
0 голосов
/ 05 ноября 2019

Вы можете изменить 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;
0 голосов
/ 05 ноября 2019

Вы также можете присоединиться к одной и той же таблице несколько раз

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

Не уверены, какой из ответов будет более эффективным?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...