我有三个表:user,user_tag和tag。其中最基本的要素转载如下。
用户使用中间user_tag表链接到标签。每个用户都可以拥有零个或多个标签。我很想找到那些拥有一个或多个匹配标签的用户。
用户
Column | Type | Modifiers
-------------+--------------------------------+---------------------------------
id | integer | not null
name | character varying(150) | not null
user_tag
Column | Type | Modifiers
------------+--------------------------------+-----------
id | integer | not null
user_id | integer |
tag_id | integer |
标签
Column | Type | Modifiers
-------------+--------------------------------+---------------------------------
id | integer | not null
name | character varying(64) | not null
因此,查找具有单个标记的用户很简单:
select u.id,u.name,g.name
from user u
join user_tag t on t.user_id = u.id
join tag g on g.id = t.tag_id
where g.name='TAGX';
我的问题是,如何匹配两个或更多标签?
做类似以下的事情并不起作用。
select u.id,u.name,g.name
from user u
join user_tag t on t.user_id = u.id
join tag g on g.id = t.tag_id
where (g.name='TAGX' and g.name='TAGY');
感觉我需要进行第二次加入来匹配第二个标签......?
答案 0 :(得分:3)
首先,改变你的状况:
where (g.name='TAGX' and g.name='TAGY')
为:
where (g.name='TAGX' OR g.name='TAGY')
或:
where g.name in ('TAGX', 'TAGY')
您想要标记TAGX
和TAGY
现在你的输出应该是这样的:
+----+--------+------+
| ID | Name | Tag |
+----+--------+------+
| 1 | User 1 | TAGX |
| 1 | User 1 | TAGY |
| 3 | User 3 | TAGX |
| 4 | User 4 | TAGY |
+----+--------+------+
正如您所提到的,您只想要拥有2个或更多标签的用户,而用户3和4在结果中是入侵者。 为了获得它们,你将不得不:
像这样:
select u.id,u.name
from user u
join user_tag t on t.user_id = u.id
join tag g on g.id = t.tag_id
where g.name in ('TAGX', 'TAGY')
group by u.id,u.name
having count(u.id) < 2;
你的输出应该是:
+----+--------+
| ID | Name |
+----+--------+
| 1 | User 1 |
+----+--------+
如果要检查条件是否正确过滤,可以通过显示计数列并删除HAVING
子句来进行可视验证。
像这样:
select u.id,u.name, count(u.id)
from user u
join user_tag t on t.user_id = u.id
join tag g on g.id = t.tag_id
where g.name in ('TAGX', 'TAGY')
group by u.id,u.name;
我们应该告诉你:
+----+--------+-------+
| ID | Name | count |
+----+--------+-------+
| 1 | User 1 | 2 |
| 3 | User 3 | 1 |
| 4 | User 4 | 1 |
+----+--------+-------+
答案 1 :(得分:2)
如果您想查找具有这两个标记中的任何一个的用户,那么Tarik的答案将按照您的意愿执行,但如果您要查找同时包含这两个标记的用户(可能还有其他标记),则此查询将执行此操作:
select u.id, u.name
from user u
join user_tag t on t.user_id = u.id
join tag g on g.id = t.tag_id
where g.name in ('TAGX', 'TAGY')
group by u.id, u.name
having count(distinct g.name) = 2;
上面的查询将返回至少包含标签TAGX和TAGY的用户,但可以包含更多标签。如果你想要拥有这两个标签的用户,那么一个解决方案就是做一个相关的不存在的查询,如下所示:
select u.id, u.name, g.name
from user u
join user_tag t on t.user_id = u.id
join tag g on g.id = t.tag_id
where not exists (
select 1
from user_tag join tag on user_tag.tag_id = tag.id
where tag.name not in ('TAGX', 'TAGY')
and user_tag.user_id = u.id
)