合并连接并存在于连接 table

Combine join and exists on join table

我一直在解决这个 sql 难题,我几乎想通了,但最后一部分有点挑战性。

我有一个活动 table 和一个用户 table

活动的状态为:有效/无效。

最重要的是,活动和用户之间存在连接 table:campaign_users。此 table 用于专门将活动分配给一部分用户。

鉴于此数据:

Campaigns
id  name        status
1   campaign_a  active
2   campaign_b  active
3   campaign_c  active
4   campaign_d  inactive

Users
id  name
1   user_a
2   user_b
3   user_c

Campaign_users
id  campaign_id     user_id
1   2               1
2   3               2
3   4               1

我想进行一个结合几个 'facets' 的查询。正如我所说,我卡在了最后一部分,这是我的步骤:

第 1 步:Select 个活动活动:

SELECT campaigns.* 
FROM campaigns 
WHERE campaigns.status = 'active'

output
campaign: 1,2,3

第2步:(and)不独占分配给任何人:

SELECT campaigns.* 
FROM campaigns 
WHERE campaigns.status = 'active'
WHERE NOT EXISTS(select * FROM campaign_users WHERE campaign_users.campaign_id = campaigns.id)

output:
campaign: 1

第3步:(and)独占分配给passed_inuser_id(1).

SELECT campaigns.* 
FROM campaigns 
WHERE campaigns.status = 'active' 
INNER JOIN campaign_users ON campaign_users.campaign_id = campaigns.id 
AND campaign_users.user_id = 1

output:
campaign: 2

最后一步:

这是我卡住的部分。

将所有 'facets' 组合在一起的查询:仅不排他(分配给任何人)并且不排他传入 user_id 的活动活动。

写这个感觉有点自相矛盾,但内部联接仅存在于联接 table 中的 returns 个活动,但它跳过了 'non exclusive' 个活动。

expected output:

with passed_in user_id of 1

campaign: 1,2 (Active & non exclusive and exclusively assigned to user 2)

with passed_in user_id of 2

campaign: 1,3 (Active & non exclusive and exclusively assigned to user 2)

with passed_in user_id of 3

campaign: 3 (Active & non exclusive but no exclusive assigned to user 3)

您可以UNION第 2 步和第 3 步的查询以获得所需的结果,例如:

SELECT campaign_id
FROM campaigns 
WHERE campaigns.status = 'active'
WHERE NOT EXISTS(select * FROM campaign_users WHERE campaign_users.campaign_id = campaigns.id)

UNION 

SELECT campaign_id
FROM campaigns 
WHERE campaigns.status = 'active' 
INNER JOIN campaign_users ON campaign_users.campaign_id = campaigns.id 
AND campaign_users.user_id = ?

您可以使用一个简单的技巧:将所有 campaign_users 外连接到 campaigns。对于独家广告系列,您将获得针对每个广告系列和用户的一行,对于非独家广告系列,您将获得一行用户为空的行。为相关用户(比如用户 1)或所有用户(用户 null)保留所有活动。

select c.*
from campaigns c
left join campaign_users cu on cu.campaign_id = c.id
where c. status = 'active' and (cu.user_id = 1 or cu.user_id is null);