【问题标题】:Delete duplicate row based on condition in Oracle根据Oracle中的条件删除重复行
【发布时间】:2017-11-23 17:02:41
【问题描述】:

我想根据条件从表中删除重复的行。

例如, 表 ABC:

ID  Name    Pin Status
111 Pope    909 New
222 Jazz    909 New
333 Volk    767 Assigned
444 Audi    767 New
555 Pink    435 New

我想根据以下条件删除具有相同“Pin”的重复记录:

  1. 如果两个相同的 Pin 记录的状态为新建 – 删除其中任何一个。
  2. 如果相同 Pin 记录之一的状态为“新”,而另一个“已分配”状态 - 删除“新”状态记录。

我编写了以下 SQL,但我想知道是否有更好的方法来使用 PK 来处理这个问题。

对于 1:

DELETE FROM ABC WHERE ID IN (
SELECT
  a.id
FROM ABC a
WHERE a.rowid <
  (SELECT max(rowid)
  FROM  ABC  b
  WHERE b.pin = a.pin
  AND a.status  = b.status
  AND b.status  in ('New')
  )
);

对于 2:

DELETE FROM ABC WHERE ID IN (
SELECT
  a.id
FROM ABC a
WHERE a.rowid <
  (SELECT max(rowid)
  FROM  ABC  b
  WHERE b.pin = a.pin
  AND a.status  <> b.status
  AND a.status  in ('New')
  AND b.status  in ('Assigned')
  )
);

【问题讨论】:

  • 如果一个 pin 有多个分配和多个新行怎么办?
  • 如果两行都具有相同的引脚且两者均已分配状态 - 什么也不做。

标签: sql database oracle duplicates sql-delete


【解决方案1】:

你可以试试这个。

--Query 1:
DELETE FROM ABC
WHERE ID NOT IN (SELECT MIN(ID)
                 FROM ABC 
                 GROUP BY Pin
                 HAVING COUNT(*)=COUNT(CASE WHEN status = 'New' THEN 1 END)
                );

--Query 2:
DELETE FROM ABC
WHERE ID IN (SELECT ID
             FROM ABC A
             WHERE status = 'New'
             AND EXISTS (SELECT 1 FROM ABC B 
                         WHERE A.Pin=B.Pin AND B.status='Assigned')

            );

【讨论】:

    【解决方案2】:

    如果每个pin最多有两条记录:

    DELETE FROM ABC
    WHERE rowid IN (SELECT MIN(CASE WHEN a.status = 'NEW' then rowid END) 
                    FROM ABC a
                    WHERE abc.pin = a.pin AND
                          a.status IN ('New', 'Assigned'
                    GROUP BY a.pin
                    HAVING COUNT(*) > 1
                   );
    

    【讨论】:

      【解决方案3】:

      试试这个查询--

      -- Select ID, Name, Pin, Status
      Delete
      From (
          Select  
              ID, Name, Pin, Status,
              Row_Number() Over(Partition By Pin Order By Pin) As PinRowNum,
              Row_Number() Over(Partition By Pin, Status Order By Status) As 
          StatusRowNum
      From ABC
      ) As D Where StatusRowNum > 1 Or (PinRowNum > 1 And StatusRowNum = 1)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-02-17
        • 2021-04-02
        • 1970-01-01
        • 1970-01-01
        • 2022-01-14
        • 1970-01-01
        • 2021-12-20
        • 2019-04-19
        相关资源
        最近更新 更多