我正在尝试返回与所有查询的“标记”相关联的用户关联的所有行。我的表结构和所需的输出如下:
admin.tags:
user_id | tag | detail | date
2 | apple | blah... | 2015/07/14
3 | apple | blah. | 2015/07/17
1 | grape | blah.. | 2015/07/23
2 | pear | blahblah | 2015/07/23
2 | apple | blah, blah | 2015/07/25
2 | grape | blahhhhh | 2015/07/28
system.users:
id | email
1 | joe@test.com
2 | jane@test.com
3 | bob@test.com
queried tags:
'apple', 'pear'
desired output:
user_id | tag | detail | date | email
2 | apple | blah... | 2015/07/14 | jane@test.com
2 | pear | blahblah | 2015/07/23 | jane@test.com
2 | apple | blah, blah | 2015/07/25 | jane@test.com
由于user_id 2与'apple'和'pear'相关联,因此返回每个'apple'和'pear'行,加入system.users
以便还返回她的电子邮件。
我对如何正确设置这个postgresql查询感到困惑。我用左反连接做了几次尝试,但似乎无法获得理想的结果。
答案 0 :(得分:2)
派生表中的查询为您提供具有所有指定标记的用户的用户ID,外部查询将为您提供详细信息。
select *
from "system.users" s
join "admin.tags" a on s.id = a.user_id
join (
select user_id
from "admin.tags"
where tag in ('apple', 'pear')
group by user_id
having count(distinct tag) = 2
) t on s.id = t.user_id;
请注意,此查询将包含同时具有您搜索的两个标记的用户,但只要他们至少具有指定的两个标记,就可以包含其他标记。
使用您的样本数据,输出将是:
| id | email | user_id | tag | detail | date | user_id |
|----|---------------|---------|-------|------------|------------------------|---------|
| 2 | jane@test.com | 2 | grape | blahhhhh | July, 28 2015 00:00:00 | 2 |
| 2 | jane@test.com | 2 | apple | blah, blah | July, 25 2015 00:00:00 | 2 |
| 2 | jane@test.com | 2 | pear | blahblah | July, 23 2015 00:00:00 | 2 |
| 2 | jane@test.com | 2 | apple | blah... | July, 14 2015 00:00:00 | 2 |
如果您想要使用grape
排除行,只需在外部查询中添加where tag in ('apple', 'pear')
。
如果您只想要只拥有搜索过的标签且没有其他用户(例如精确分割)的用户,您可以将派生表中的查询更改为:
select user_id
from "admin.tags"
group by user_id
having sum(case when tag = 'apple' then 1 else 0 end) >= 1
and sum(case when tag = 'pear' then 1 else 0 end) >= 1
and sum(case when tag not in ('apple','pear') then 1 else 0 end) = 0
由于用户2也有 grape
,因此不会返回任何给定样本数据的内容答案 1 :(得分:2)
必须拥有所有类型的关系除法问题的标准双重否定方法:(我将date
重命名为zdate
以避免使用关键字作为标识符)
-- For convenience: put search arguments into a temp table or CTE
-- I cheat by extracting this from the admin_tags table
-- (in fact, there should be a table with all possible tags somwhere)
-- WITH needed_tags AS (
-- SELECT DISTINCT tag
-- FROM admin_tags
-- WHERE tag IN ('apple' , 'pear' )
-- )
-- Even better: directly use a VALUES() as a constructor
-- (thanks to @jpw )
WITH needed_tags(tag) AS (
VALUES ('apple' ) , ( 'pear' )
)
SELECT at.user_id , at.tag , at.detail , at.zdate
, su.email
FROM admin_tags at
JOIN system_users su ON su.id = at.user_id
WHERE NOT EXISTS (
SELECT * FROM needed_tags nt
WHERE NOT EXISTS (
SELECT * FROM admin_tags nx
WHERE nx.user_id = at.user_id
AND nx.tag = nt.tag
)
)
;
答案 2 :(得分:0)
使用相关子选择来计算用户的不同标签数量,使用不相关的子选择来计算不同标签的数量:
select at.user_id, at.tag, at.detail, at.date, su.email
from admin.tags at
join system.users su on at.user_id = su.id
where (select count(distinct tag) from admin.tags at2
where at2.user_id = at.user_id)
= (select count(distinct tag) from admin.tag)