在postgresql中有条件地删除部分行
Deleting partial rows conditionally in postgresql
亲爱的 postgresql 大师,
我在 SQL 中遇到了这个有趣的要求。
Table : EmpBonus
id long,
empid long,
bonuspaid date,
paidby string
奖金可以每年支付。 paidby 列可以具有这两个值之一 (userA, userB)。
我必须使用 SQL 查询而不使用存储过程或函数来满足以下两个要求
- 如果某员工已被用户A和用户B支付过奖金,则删除所有由用户B支付过奖金的条目
- 如果一个员工只得到了用户B的奖金,则删除除第一个以外的所有条目。
我尝试使用两个常见的 table 表达式,
- 一个到 select mpid 的行数 > 1 的所有 empids
- 两个到 select 用户 B 未支付奖金的所有 empids
- 在 empid 上将这两个与原始 table 相结合,为我提供了一个行列表,我可以使用这些行来删除我需要的内容。但是我卡在了这一点上。
提前感谢您的帮助。
编辑
这是经过少许修改的答案副本
SELECT eb.id, eb.empId, eb.bonuspaid, eb.paidby, eb2.seqnum, eb2.a_paid
FROM empbonus eb
JOIN (SELECT eb2.*
,COUNT(*) FILTER (WHERE paidby = 'A') OVER (PARTITION BY empid) AS a_paid
,row_number() OVER (PARTITION BY empid ORDER BY id) AS seqnum
FROM empbonus eb2
) eb2
ON eb.id = eb2.id
WHERE (
(eb2.a_paid > 0 AND eb.paidby = 'B') OR
(eb2.a_paid = 0 AND eb.paidby = 'B' AND seqnum > 1)
)
ORDER BY eb.empId, eb.id ;
嗯。 . .您可以使用子查询来计算您需要的附加信息。然后你可以在 delete
:
中“加入”这个
delete empbonus eb
from (select eb2.*,
count(*) filter (where paidby = 'A') over (partition by empid) as a_paid,
row_number() over (partition by empid, b_paid order by id) as seqnum
from empbonus eb2
) eb2
where eb.id = eb2.id and
( (eb2.a_paid > 0 and eb.paidby = 'B') or
(eb2.a_paid = 0 and eb.paidby = 'B' and seqnum = 1)
);
亲爱的 postgresql 大师,
我在 SQL 中遇到了这个有趣的要求。
Table : EmpBonus
id long,
empid long,
bonuspaid date,
paidby string
奖金可以每年支付。 paidby 列可以具有这两个值之一 (userA, userB)。
我必须使用 SQL 查询而不使用存储过程或函数来满足以下两个要求
- 如果某员工已被用户A和用户B支付过奖金,则删除所有由用户B支付过奖金的条目
- 如果一个员工只得到了用户B的奖金,则删除除第一个以外的所有条目。
我尝试使用两个常见的 table 表达式,
- 一个到 select mpid 的行数 > 1 的所有 empids
- 两个到 select 用户 B 未支付奖金的所有 empids
- 在 empid 上将这两个与原始 table 相结合,为我提供了一个行列表,我可以使用这些行来删除我需要的内容。但是我卡在了这一点上。
提前感谢您的帮助。
编辑
这是经过少许修改的答案副本
SELECT eb.id, eb.empId, eb.bonuspaid, eb.paidby, eb2.seqnum, eb2.a_paid
FROM empbonus eb
JOIN (SELECT eb2.*
,COUNT(*) FILTER (WHERE paidby = 'A') OVER (PARTITION BY empid) AS a_paid
,row_number() OVER (PARTITION BY empid ORDER BY id) AS seqnum
FROM empbonus eb2
) eb2
ON eb.id = eb2.id
WHERE (
(eb2.a_paid > 0 AND eb.paidby = 'B') OR
(eb2.a_paid = 0 AND eb.paidby = 'B' AND seqnum > 1)
)
ORDER BY eb.empId, eb.id ;
嗯。 . .您可以使用子查询来计算您需要的附加信息。然后你可以在 delete
:
delete empbonus eb
from (select eb2.*,
count(*) filter (where paidby = 'A') over (partition by empid) as a_paid,
row_number() over (partition by empid, b_paid order by id) as seqnum
from empbonus eb2
) eb2
where eb.id = eb2.id and
( (eb2.a_paid > 0 and eb.paidby = 'B') or
(eb2.a_paid = 0 and eb.paidby = 'B' and seqnum = 1)
);