选择联接表中多个值与给定集匹配的位置

时间:2010-12-10 07:01:55

标签: sql postgresql join

我正在使用Postgresql。我有一个项目表,一个标签表和一个将许多标签链接到一个项目的表。我需要选择与2个(或更多)给定标签匹配的项目。

我可以选择与WHERE tag.name IN ('tag1', 'tag2')匹配1或更多的项目在MySQL中我想我可以说WHERE x IN ALL (y, z),但这似乎不起作用pgsql。

到目前为止,我所拥有的最好的是使用子查询将两个表连接两次。这显然不会扩展到许多标签上的匹配,我确信这不是最有效的方法。

SELECT * 
FROM item 
JOIN (SELECT item.id FROM item 
      JOIN tagged on tagged.item=item.id 
      JOIN tag ON tag.id=taged.tag 
      WHERE tag.name='tagOne') p ON p.id=item.id
JOIN tagged ON tagged.item=item.id
JOIN tag ON tag.id=tagged.tag
WHERE tag.name='tagTwo'`

编辑:我还在测试一下,但在子查询中使用它比我上面的尝试效果更好

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 个答案:

答案 0 :(得分:4)

这里有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 );

答案 1 :(得分:0)

我不确定我是否明白,但也许你可以简单地写一下:

WHERE tag.name IN (y) AND tag.name IN (z)

答案 2 :(得分:0)

我喜欢使用表格:

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')

你断言“这显然不会扩展到许多标签上的匹配,我确信这不是最有效的方法” - 但这听起来像你在猜测?