[英]Postgres exclusive tag search
我正在嘗試返回與與所有查詢的“標簽”相關聯的用戶相關聯的所有行。 我的表結構和所需的輸出如下:
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查詢感到困惑。 我已經用左反聯接進行了幾次嘗試,但是似乎無法獲得預期的結果。
派生表中的查詢將為您提供具有所有指定標簽的用戶的用戶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
解決所有類型的關系划分問題的標准雙重否定方法:(我將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
)
)
;
使用關聯的子選擇來計算用戶的不同標簽的數量,使用不關聯的子選擇來計算不同標簽的數量:
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)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.