запрос многие ко многим - PullRequest
3 голосов
/ 28 апреля 2010

У меня есть проблема, и я не знаю, что является лучшим решением. Хорошо, у меня есть 2 таблицы: posts (id, title), posts_tags (post_id, tag_id). У меня есть следующая задача: необходимо выбрать сообщения с тегами идентификаторов, например, 4, 10 и 11. Не совсем, пост может иметь любые другие теги одновременно. Итак, как я могу сделать это более оптимизированным? Создание временной таблицы в каждом запросе? Или может быть какая-то хранимая процедура? В будущем пользователь может попросить скрипт выбрать сообщения с любым количеством тегов (это может быть только 1 тег или 10 одновременно), и я должен быть уверен, что метод, который я выберу, будет лучшим методом для моей проблемы. Извините за мой английский, спасибо за внимание.

Ответы [ 5 ]

3 голосов
/ 28 апреля 2010

Это решение предполагает, что (post_id, tag_id) в post_tags должно быть УНИКАЛЬНЫМ:

 SELECT id, title FROM posts
    INNER JOIN post_tag ON post_tag.post_id = posts.id
    WHERE tag_id IN (4, 6, 10)
    GROUP BY id, title
    HAVING COUNT(*) = 3

Хотя это не решение для всех возможных комбинаций тегов, его легко создать в виде динамического SQL. Чтобы изменить другие наборы тегов, измените список IN (), чтобы иметь все теги, и COUNT (*) =, чтобы проверить количество указанных тегов. Преимущество этого решения по сравнению с каскадным соединением нескольких JOIN заключается в том, что вам не нужно добавлять JOIN или даже дополнительные условия WHERE при изменении запроса.

1 голос
/ 28 апреля 2010
select id, title
from posts p, tags t
where p.id = t.post_id
and tag_id in ( 4,10,11 ) ;

0 голосов
/ 28 апреля 2010

Выбирает все сообщения, имеющие любой тегов (4, 10, 11):

select distinct id, title from posts  
where exists ( 
  select * from posts_tags  
  where  
    post_id = id and 
    tag_id in (4, 10, 11)) 

Или вы можете использовать это:

select distinct id, title from posts   
join posts_tags on post_id = id 
where tag_id in (4, 10, 11) 

(оба будут оптимизированы одинаково).

Выбирает все сообщения, имеющие все тегов (4, 10, 11):

select distinct id, title from posts
where not exists ( 
  select * from posts_tags t1 
  where 
    t1.tag_id in (4, 10, 11) and
    not exists (
      select * from posts_tags as t2
      where 
        t1.tag_id = t2.tag_id and
        id = t2.post_id))

Список тегов в предложении in - это то, что динамически изменяется (во всех случаях).

Но этот последний запрос не очень быстрый, поэтому вы можете использовать что-то вроде этого:

 create temporary table target_tags (tag_id int);
 insert into target_tags values(4),(10),(11);
 select id, title from posts 
   join posts_tags on post_id = id 
   join target_tags on target_tags.tag_id = posts_tags.tag_id
   group by id, title 
   having count(*) = (select count(*) from target_tags);
 drop table target_tags;

Часть, которая изменяется динамически, теперь находится во втором операторе (вставка).

0 голосов
/ 28 апреля 2010

Вы можете сделать компромисс между хранением времени, сохранив однонаправленный хэш имен тегов поста, отсортированных в алфавитном порядке.

Когда сообщение помечено, выполните select t.name from tags t inner join post_tags pt where pt.post_id = [ID_of_tagged_post] order by t.name. Объедините все имена тегов, создайте хэш с использованием алгоритма MD5 и вставьте значение в столбец рядом с вашим сообщением (или в другую таблицу, к которой присоединяется внешний ключ, если вы предпочитаете).

Если вы хотите найти определенную комбинацию тегов, просто выполните (не забывая сортировать имена тегов) select from posts p where p.taghash = MD5([concatenated_tag_string]).

0 голосов
/ 28 апреля 2010

Это работает?

select *
from posts
where post.post_id in
    (select post_id
    from post_tags
    where tag_id = 4
    and post_id in (select post_id
                    from post_tags
                    where tag_id = 10
                    and post_id in (select post_id
                                    from post_tags
                                    where tag_id = 11)))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...