我有下表:
ID (int)
EMAIL (varchar(50))
CAMPAIGNID (int)
isSubscribe (bit)
isActionByUser (bit)
此表存储针对用户的广告系列的所有订阅和取消订阅操作。这些操作可以由用户自己(isActionByUser = true)或管理台(isActionByUser = false)完成。
我需要获取最后一个操作来确定用户是订阅还是取消订阅。但请记住,当用户从广告系列中取消订阅操作时,管理台将优先处理其他订阅操作。
我找到了nice solution来获取按EMAIL和CAMPAIGNID分组的最新记录。但我无法弄清楚我是如何结合isActionByUser = true的要求,对isActionByUser = false的记录具有绝对优先级。 另外:当管理台执行取消订阅操作时,它将优先于(isSubscribe = true和isActionByUser)的记录。
示例数据:
ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER
-----------------------------------------------------------
1 a@aa.com 1 1 0
2 b@bb.com 1 1 0
3 c@cc.com 1 1 0
4 a@aa.com 1 0 1
5 a@aa.com 1 1 0
6 c@cc.com 1 1 1
7 c@cc.com 1 0 0
预期结果将是:
ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER
-----------------------------------------------------------
2 b@bb.com 1 1 0
4 a@aa.com 1 0 1
7 c@cc.com 1 0 0
使用以下查询
select cs1.*
from
[TABLE] cs1
left join
[TABLE] cs2
on
cs1.EM_EMAIL = cs2.EM_EMAIL
and
cs1.EM_CAMPAIGNID = cs2.EM_CAMPAIGNID
and
cs1.id < cs2.id
where cs2.id is null
我的结果如下:
ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER
-----------------------------------------------------------
2 b@bb.com 1 1 0
5 a@aa.com 1 1 0
7 c@cc.com 1 0 0
另一种方法:
SELECT *
FROM [TABLE] cs
WHERE id in
(
SELECT top 1 id
FROM [TABLE] ss
WHERE
cs.EMAIL = ss.EMAIL
and
cs.CAMPAIGNID = ss.CAMPAIGNID
and ISSUBSCRIBE = (
select top 1 min(convert(int, ISSUBSCRIBE))
FROM [TABLE] sss
WHERE
cs.EMAIL = sss.EMAIL
and
cs.CAMPAIGNID = sss.CAMPAIGNID
)
and ISACTIONBYUSER= (
select top 1 max(convert(int, ISACTIONBYUSER))
FROM [TABLE] ssss
WHERE
cs.EMAIL = ssss.EMAIL
and
cs.CAMPAIGNID = ssss.CAMPAIGNID
)
)
这将产生以下结果:
ID EMAIL CAMPAIGNID ISSUBSCRIBE ISACTIONBYUSER
-----------------------------------------------------------
2 b@bb.com 1 1 0
4 a@aa.com 1 0 1
6 c@cc.com 1 1 1
哪个也不正确。而且我担心这种方法会对性能产生很大的影响。
那么我有什么想法可以解决这个问题?
答案 0 :(得分:3)
好的,请尝试以下查询:
SELECT DISTINCT B.*
FROM YourTable A
OUTER APPLY (SELECT TOP 1 *
FROM YourTable
WHERE Email = A.Email AND CampaignId = A.CampaignId
ORDER BY CASE WHEN ISSUBSCRIBE = 0 THEN 1 ELSE 2 END,
CASE WHEN ISACTIONBYUSER = 1 THEN 1 ELSE 2 END,
ID DESC) B
答案 1 :(得分:2)
试试这个:[更新以处理取消订阅和订阅的用户]
declare @test table (id int, email varchar(100), CAMPAIGNID int, ISSUBSCRIBE bit, ISACTIONBYUSER bit)
INSERT INTO @test
SELECT 1,'a@aa.com',1,1,0 UNION
SELECT 2,'b@bb.com',1,1,0 UNION
SELECT 3,'c@cc.com',1,1,0 UNION
SELECT 4,'a@aa.com',1,0,1 UNION
SELECT 5,'a@aa.com',1,1,0 UNION
SELECT 6,'c@cc.com',1,1,1 UNION
SELECT 7,'c@cc.com',1,0,0 UNION
select 8, 'd@dd.com', 1, 1, 1 UNION
select 9, 'd@dd.com', 1, 0, 1 UNION
select 10, 'd@dd.com', 1, 1, 1
;WITh CTE AS
(
select s.*,
ROW_NUMBER() OVER (PARTITION BY email,campaignid
ORDER BY
case
when ISSUBSCRIBE = 0 AND ISACTIONBYUSER = 0 THEN 1
when ISSUBSCRIBE = 0 AND ISACTIONBYUSER = 1 THEN 1
when ISSUBSCRIBE = 1 AND ISACTIONBYUSER = 1 THEN 1 ELSE 2 END, ID DESC) Rn1
from @test s
)
SELECT * FROM CTE WHERE Rn1 = 1
order by id
答案 2 :(得分:1)
这是一些标准的SQL可能会让你在那里,虽然它不是最漂亮的:
<强>更新强>
select s.*
from Subscriptions s
join (
-- Apply the user unsubscribe logic to get the proper ID
select case when b.ID is not null and a.ISACTIONBYUSER = 0 then b.ID else a.ID end as ID
from (
-- Latest overall
select ID, EMAIL, CAMPAIGNID,
(select ISACTIONBYUSER from Subscriptions where ID = z.ID) as ISACTIONBYUSER
from (
select max(ID) as ID, EMAIL, CAMPAIGNID
from Subscriptions a
group by EMAIL, CAMPAIGNID
) as z
) as a
left join (
-- Latest user unsubscribe
select max(ID) as ID, EMAIL, CAMPAIGNID, 1 as ISACTIONBYUSER
from Subscriptions
where ISSUBSCRIBE = 0
and ISACTIONBYUSER = 1
group by EMAIL, CAMPAIGNID
) as b on a.EMAIL = b.EMAIL
and a.CAMPAIGNID = b.CAMPAIGNID
) as i on s.ID = i.ID
为了解决这个问题,我已对此进行了更新:
insert into Subscriptions select 8, 'd@dd.com', 1, 1, 1
insert into Subscriptions select 9, 'd@dd.com', 1, 0, 1
insert into Subscriptions select 10, 'd@dd.com', 1, 1, 1