SQL Как я могу запросить отношения многие ко многим - PullRequest
2 голосов
/ 03 августа 2010

если у меня есть много-много взаимосвязей между постами и тегами, как мне выбрать посты, содержащие определенный тег?

обновление:

Проблема, с которой я столкнулся, заключается в том, что из-за где tag.name = 'xxx' выбран только этот тег.я хочу выбрать все сообщения с указанным тегом, tgt со всеми их тегами, например,

Post 1 -> tag1, tag2
Post 2 -> tag1, tag3
Post 3 -> tag2, tag3

в настоящее время я получаю

Post 1 -> tag2 // missing tag1
Post 3 -> tag2 // missing tag3 

1 Ответ

4 голосов
/ 03 августа 2010

Принимая эти таблицы:

  • Сообщений: идентификатор, автор, дата, содержание
  • Теги: идентификатор, имя
  • 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().

...