MySQL: Как выбрать группы, имеющие определенные значения?
Вопрос
Скажем, есть такой стол:
mysql> SELECT * FROM tags;
+---------+--------+
| post_id | tag_id |
+---------+--------+
| 1 | 2 |
| 1 | 3 |
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
+---------+--------+
5 rows in set (0.00 sec)
Имена полей довольно объяснительные. Я хочу выбрать post_id
S, что имеет как 1 и 3 tag_id
S, так в этом примере это только 1
. Отказ Я думал о чем-то вродеSELECT post_id FROM tags GROUP BY post_id HAVING ...
После того, как я хотел бы перечислить tag_id
S, которые присутствуют в этой группе. Как я могу это сделать?
Решение
Если нет никаких уникальных ограничений, попробуйте:
SELECT post_id
FROM tags
WHERE tag_id = 1 OR tag_id = 3
GROUP BY post_id
HAVING count(DISTINCT tag_id) = 2;
Или использовать это HAVING
пункт, если пытаться обнаружить только два tag_id
ценности:
HAVING MIN(tag_id) <> MAX(tag_id)
Если Post_ID и TAG_ID имеют уникальное ограничение, это должно работать тоже:
SELECT post_id
FROM tags
WHERE tag_id = 1 OR tag_id = 3
GROUP BY post_id
HAVING count(*) = 2;
Другие советы
Вы можете попробовать я вступать в систему (n tag_id -> n присоединиться), но, вероятно, не будет быстро
SELECT t1.post_id
FROM tags t1 INNER JOIN tags t2 ON t1.post_id = t2.post_id
WHERE t1.tag_id = 1 AND t2.tag_id = 3
Я сделал несколько предположений о ваших других таблицах. (т.е. у вас есть таблица для постов, которые я позвонил posts
и один с tag_id в качестве pk, который я позвонил tag_table
Чтобы избежать Nameclash с столбами / тегами, которую я могу видеть, вы уже звоните tags
)
Вы хотите посты, где нет тегов в списке {1,3}, для которых не существует совпадающая запись с соответствующей записью_ид / tag_id, чтобы вы могли использовать двойную не существующую конструкцию, как показано ниже.
SELECT post_id
FROM posts p
WHERE NOT EXISTS
(SELECT * FROM tag_table tt
WHERE tag_id IN (1,3)
AND NOT EXISTS
(SELECT * FROM tags t
WHERE t.tag_id = tt.tag_id and
p.post_id = t.post_id)
)
Другим альтернативным подходом является использование группы по и счетчикам. Обзор подходов к этой проблеме здесь.
SELECT post_id
FROM ( SELECT post_id,
count(tag_id) AS counter
FROM tags
WHERE tag_id IN (1,3)
GROUP BY post_id
)
WHERE counter = 2
Используйте group_concat () для второй части вашего вопроса
SELECT post_id,
GROUP_CONCAT(tag_id ORDER BY tag_id ASC SEPARATOR ',')
FROM tags
Как насчет
SELECT *
FROM tags
WHERE post_id in
(SELECT post_id AS pid
FROM tags
WHERE 1 IN (SELECT tag_id FROM tags WHERE post_id = pid)
AND 3 IN (SELECT tag_id FROM tags WHERE post_id = pid)
);
Где версия решения @ хранитель
SELECT DISTINCT t1.post_id
FROM tags t1, tags t2
WHERE
t1.post_id = t2.post_id AND
t1.tag_id = 1 AND t2.tag_id = 3