Выбор, где более чем одно значение из объединенной таблицы соответствует данному набору - PullRequest
2 голосов
/ 10 декабря 2010

Я использую Postgresql.У меня есть таблица элементов, таблица тегов и таблица, которая связывает множество тегов с элементом.Мне нужно выбрать элементы, которые соответствуют 2 (или более) заданным тегам.

Я могу выбрать элементы, которые соответствуют 1 или более с WHERE tag.name IN ('tag1', 'tag2') В MySQL, я думаю, я мог бы сказать WHERE x IN ALL (y, z), но это не работает, pgsql, похоже

Пока лучшее, что у меня есть, - это объединить две таблицы дважды, используя подзапрос.Очевидно, что это не будет соответствовать многим тегам, и я уверен, что это не самый эффективный подход.работает лучше, чем моя предыдущая попытка

SELECT item.id, count(tag2) AS relevance
FROM item
JOIN tagged tagged1 ON tagged1.item=item.id
JOIN tag tag1 ON (tag1.id=tagged1.tag AND tag1.name='tag1')
JOIN tagged tagged2 ON tagged2.item=item.id
JOIN tag tag2 ON (tag2.id=tagged2.tag)
WHERE tag2.name IN ('tag2', 'tag3')
GROUP BY item.id

В соответствии с просьбой, вот некоторые определения таблиц для пояснения:

CREATE TABLE item (id serial, [...]);
CREATE TABLE tag (id serial, name string UNIQUE);
CREATE TABLE taged (tag int references tag(id), item int references item(id));

Ответы [ 3 ]

4 голосов
/ 10 декабря 2010

Вот 3 (из многих) возможных подходов:

select * 
from item 
where id in ( select tagged.item
              from tagged join tag on(tag.id=taged.tag)
              where tag.name in('tagOne', 'tagTwo')
              group by tagged.item
              having count(*)=2 );

select * 
from item join ( select tagged.item, count(*) as numtags 
                 from tagged join tag on(tag.id=taged.tag)
                 where tag.name in('tagOne', 'tagTwo')
                 group by tagged.item ) using (id)
where numtags=2;

select *
from item
where id in ( select tagged.item
              from tagged join tag on(tag.id=taged.tag)
              where tag.name='tagOne'
              intersect
              select tagged.item
              from tagged join tag on(tag.id=taged.tag)
              where tag.name='tagTwo' );

если вам просто нужно 2 или более совпадений, но вы не возражаете против того, какие теги совпадают:

select * 
from item 
where id in ( select item
              from tagged
              group by item
              having count(*)>=2 );
0 голосов
/ 10 декабря 2010

Мне нравится использовать форму:

SELECT *
FROM item
WHERE EXISTS (SELECT 1 FROM tagged JOIN tag ON tag.id = tagged.tag
              WHERE tag.name = 'tag1')
      AND
      EXISTS (SELECT 1 FROM tagged JOIN tag ON tag.id = tagged.tag
              WHERE tag.name = 'tag2')

Вы утверждаете, что "это очевидно не будет соответствовать масштабам по многим тегам, и я уверен, что это не самый эффективный подход" - ноэто звучит так, как будто ты угадаешь?

0 голосов
/ 10 декабря 2010

Я не уверен, что понял, но, может быть, вы можете просто написать:

WHERE tag.name IN (y) AND tag.name IN (z)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...