LINUX.ORG.RU

Составить SQL-запрос (объекты -> теги)


0

0

Упрощённо есть три таблицы:

table objects ( id => bigserial, 'name' => varchar(200) );

table tags ( id => bigserial, 'tagname' => varchar(200) );

table objects_tags ( 'object_id' => bigint, 'tag_id' => bigint );

Соответственно, объекты и теги связаны как «многие ко многим» через таблицу objects_tags

Что нужно: выбрать объекты, у которых есть теги «tag1», «tag2», «tag3». При этом не один из трёх, а точно три. Не четыре, не два, а именно эти три тега с этими именами. Следующая выборка может быть уже по двум тегам.. следующая - по шести... то есть, один запрос как нечто вроде

... WHERE 'tags'.'tagname' IN ('tag1', 'tag2', 'tag3')

но тут один из... а надо все :)

Ткните в манул, плиз.

★★★★★

Последнее исправление: Slavaz (всего исправлений: 2)

а просто написать tags.tagname='tag1' and tags.tagname='tag2' and tags.tagname='tag3' не кошерно ?

anonymous
()
Ответ на: комментарий от anonymous

нет, не кошерно, к сожалению. Ибо это будет применено к одному и тому же полю и только к одной записи, а не ко всем записям сразу.

Slavaz ★★★★★
() автор топика
select * 
  from objects o 
 where exists
         (select null
            from objects_tags ot, tags t
           where ot.object_id = o.object_id
             and ot.tag_id = t.tag_id
             and t.tagname  = 'tag1')
   and exists
         (select null
            from objects_tags ot, tags t
           where ot.object_id = o.object_id
             and ot.tag_id = t.tag_id
             and t.tagname  = 'tag2')
   and exists
         (select null
            from objects_tags ot, tags t
           where ot.object_id = o.object_id
             and ot.tag_id = t.tag_id
             and t.tagname  = 'tag3')
aydar ★★★★★
()
Ответ на: комментарий от aydar
and not exists (select null 
            from objects_tags ot, tags t 
           where ot.object_id = o.object_id 
             and ot.tag_id = t.tag_id 
             and t.tagname not in ('tag1', 'tag2', 'tag3'))
Legioner ★★★★★
()
Ответ на: комментарий от aydar
select *
  from objects o
  where object_id in

          (select ot.object_id
             from objects_tags ot, tags t
            where ot.tag_id = t.tag_id
              and t.tagname = 'tag1'
          intersect
          select ot.object_id
            from objects_tags ot, tags t
           where ot.tag_id = t.tag_id
             and t.tagname = 'tag2'
          intersect
          select ot.object_id
            from objects_tags ot, tags t
           where ot.tag_id = t.tag_id
             and t.tagname = 'tag3')
          
aydar ★★★★★
()

далеко не факт, что оптимально, т.к. есть лишние действия. + лень тестировать и только идея

SELECT id, count(o.id) cc
    FROM OBJECTS o 
    INNER JOIN object_tags ot ON o.id = ot.object_id
    INNER JOIN tags t  ON t.id = ot.tag_id
    WHERE t.name IN ('tag1','tag2','tag3') 
    GROUP BY o.id
    HAVING cc='3';
qnikst ★★★★★
()

Коллеги, огромное спасибо за потраченное на меня время. Вопрос решён - взял за основу вариант с пересечениями... но если будет что-нибудь пооптимальнее - приму на вооружение :)

Дальше можно рассматривать этот топик как гимнастику для ума - и уму хорошо и мне неплохо... ;)

Slavaz ★★★★★
() автор топика
Ответ на: комментарий от aydar

Вариант qnikst чертовски неплох. :)

Slavaz ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.