2010-12-10 25 views
2

我正在使用Postgresql。我有一个项目表,一个标签表,以及一个将多个标签链接到一个项目的表格。我需要选择匹配2个(或更多)给定标签的项目。选择连接表中的多个值与给定集匹配的位置

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

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

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)); 
+1

请参阅http://stackoverflow.com/questions/2161588/what-mysql-query-should-i-use-to-select-a-category-that-matches-all-my-criteria – 2010-12-10 07:07:00

+1

我不想一想`WHERE x IN ALL(y,z)`在MySQL中做什么。你能提供一个MySQL的例子,所以我们可以确切地看到你在想什么吗? – 2010-12-10 07:53:10

+0

如果添加一些表格定义作为表格/列的命名有点令人困惑 – 2010-12-10 08:51:23

回答

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); 
0

我不确定我是否理解,但也许你可以简单地写:

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

它会改善问题,返回零结果。正在针对where条件进行测试的行将不符合这两个条件。 – 2010-12-10 07:13:29

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

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

相关问题