Принимая эти таблицы:
- Сообщений: идентификатор, автор, дата, содержание
- Теги: идентификатор, имя
- PostTags: post_id, tag_id
Последняя таблица часто называется таблицей соединений и облегчает отношения «многие ко многим» между сообщениями и тегами.
SELECT p.*
FROM posts p
JOIN posttags pt ON p.id = pt.post_id
JOIN tags t ON pt.tag_id = t.id
WHERE t.name = 'sql'
По сути, представьте себе множествоотношение-ко-многим как два отношения один-ко-многим, потому что именно так они реализованы в обычных РСУБД.Таким образом, в приведенном выше запросе есть соединение «один ко многим» из сообщений в PostTags и другого из тегов в PostTags.
Созданная мной таблица PostTags имеет составной первичный ключ , равный (post_id, tag_id)
,Эта комбинация будет уникальной.Многие не одобряют составные ключи, поэтому вы часто будете видеть людей, создающих столбец первичного ключа:
- PostTags: id, post_id, tag_id
Любой метод хорош.Во многом это философское различие.
Обновление: , если вы хотите выбрать все сообщения, имеющие определенный тег, и все теги, которые эти сообщения имеют:
SELECT p.*
FROM posts p
JOIN posttags pt ON p.id = pt.post_id
JOIN tags t ON pt.tag_id = t.id
WHERE p.id IN
(SELECT post_id
FROM PostTags pt
JOIN tags t ON pt.tag_id = t.id
WHERE t.name = 'xyz')
Еще один способ сделать это:
SELECT p.*
FROM posts p
JOIN posttags pt ON p.id = pt.post_id
JOIN tags t ON pt.tag_id = t.id
WHERE EXISTS
(SELECT post_id
FROM PostTags pt
JOIN tags t ON pt.tag_id = t.id
WHERE t.name = 'xyz'
AND pt.post_id = p.id)
Что лучше работает, нужно будет проверить и может варьироваться в зависимости от поставщика базы данных и версии.Хороший оптимизатор (например, Oracle), вероятно, оптимизирует их, чтобы выполнить то же самое.Другие могут этого не делать.
Теперь это вернет вам строки примерно так:
Post 1, tag 1
Post 1, tag 2
Post 3, tag 2
Post 3, tag 3
, поэтому вам нужно будет объединять их, желательно в логике приложения, а не в SQL.Некоторые РСУБД имеют специфичные для поставщика расширения для такого рода вещей, как, например, функция MySQL GROUP_CONCAT()
.