在PostgreSQL中有条件地删除部分行

问题描述

亲爱的Postgresql专家,

我对sql中的这个有趣的要求感到困惑。

Table : EmpBonus
id               long,empid            long,bonuspaid        date,paidby           string

奖金可能每年支付。 paidby列可以具有以下两个值之一(userA,userB)。

我必须使用SQL查询并没有存储过程或函数来满足以下两个要求

  • 如果某位员工同时获得了userA和userB的奖金,请删除所有由userB支付奖金的条目
  • 如果仅由userB支付员工奖金,则删除除第一个外的所有条目。

我尝试使用两个常见的表表达式

  • 选择所有的empid,其中mpid的行数> 1
  • 两个选择所有未由userB支付奖金的empids
  • 将这两个与原始表结合在一起,在empid上会给我一个行列表,我可以将其用于删除所需的行。但是我被困在这一点上。

谢谢您的帮助。

编辑

这是答案的副本,但做了一些修改

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)
          );