【问题标题】:Delete exact dups from a table with dups based on all columns except one从具有基于除一列之外的所有列的重复数据的表中删除精确的重复数据
【发布时间】:2018-03-06 01:52:49
【问题描述】:

我想从保留一个表中删除确切的重复记录。但是,我不能使用中间表方法,因为 dups 在除 ID 列之外的所有列上。例如:

ID,
COL1,
Col2,
col3,
col4
The dups are on col1, col2, col3, col4

Below some samples:

ID  COL1 COL2  COL3 COL4
123 ABC  4RTFD  FGY  12346
234 ABC  4RTFD  FGY  12346
586 ABC  4RTFD  FGY  12346

这里只有Id列不同,其余四列是重复的。我只想保留最大 ID 列行。

我可以在这里使用什么方法?

谢谢, 阿米特

【问题讨论】:

标签: sql teradata


【解决方案1】:

尝试在所有列以及 ID 不同的地方将表连接到自身...

    CREATE TABLE Dups
(
    ID int IDENTITY(1,1) PRIMARY KEY,
    Col1 int NOT NULL,
    Col2 date NOT NULL,
    Col3 char(1) NOT NULL,
    Col4 char(1) NOT NULL
 )
 INSERT dbo.Dups (Col1,Col2,Col3,Col4)
 VALUES ('1','20170925','A','Z'), ('1','20170925','A','Z'), ('1','20170925','A','Z'), ('2','20170925','A','Z'), ('2','20170925','A','Z'), ('2','20170925','A','Z'), ('3','20170925','A','Z');

 SELECT * FROM Dups;

 -- This solution to retain the first ID found that is duplicated...
 DELETE FROM Dups
 WHERE ID IN (
                SELECT ID
                FROM (
                        SELECT d1.ID,
                                row_number() OVER (ORDER BY d1.ID) AS DupSeq
                        FROM dbo.Dups AS d1
                        INNER JOIN dbo.Dups AS d2 ON d2.Col1 = d1.Col1 AND d2.Col2 = d1.Col2 AND d2.Col3 = d1.Col3 AND d2.Col4 = d1.Col4
                        WHERE d1.ID <> d2.ID
                    ) AS t
                WHERE DupSeq > 1
            );

 -- This solution to retain the last ID found that is duplicated...
 DELETE FROM Dups
 WHERE ID NOT IN (
                SELECT DISTINCT
                       max(t.ID) OVER(PARTITION BY t.Col1,t.Col2,t.Col3,t.Col4 ORDER BY WindowOrder) AS KeepID
                FROM (
                        SELECT d1.ID,
                                d1.Col1,
                                d1.Col2,
                                d1.Col3,
                                d1.Col4,
                                1 AS WindowOrder
                        FROM dbo.Dups AS d1
                        LEFT OUTER JOIN dbo.Dups AS d2 ON  d2.Col1 = d1.Col1 
                                                       AND d2.Col2 = d1.Col2 
                                                       AND d2.Col3 = d1.Col3 
                                                       AND d2.Col4 = d1.Col4
                                                       AND d1.ID <> d2.ID
                    ) AS t
            );


 SELECT * FROM Dups;

DROP TABLE dbo.Dups

您需要在第一个解决方案中使用 row_number(),因为显然 ID1 将匹配 ID3,因此 ID3 也将匹配 ID1。

在第二种解决方案中,连接是 LEFT OUTER 以保留那些不重复的值。

【讨论】:

  • 谢谢尼克,我的要求略有不同。添加了一些样本。让我看看建议的那个是否有效。
  • 啊,我看到您想保留最后一个副本并删除其余部分....我将使用修改后的解决方案更新我的答案。
  • 好的..非常感谢尼克!!
  • 嗨尼克,出现错误,如子查询中不允许的基于订单的聚合和订单分析函数! :(
  • 可能与 teradata 有关,在 SQL Server 中工作而不是子查询,然后将其结果插入临时表并在删除的子查询中使用它,例如`其中 ID 不在(从 @temptable 中选择 ID)
【解决方案2】:

您可以做到,许多其他人以前在 SQL-Server(和 Teradata)中做过的事情,请参阅此处 How to delete duplicate rows in sql server? 或者即使没有像 CTE 这样的 CTE,您也可以做到

DELETE FROM (
  SELECT ROW_NUMBER()
  OVER (PARTITION BY col1,col1,col3,col4
        ORDER BY ID DESC) rn
  FROM tbl  -- tbl is "your" table ...
) t1 WHERE rn>1

它适用于 SQL,尚未在 teradata 上对其进行测试,但是,由于 ROW_NUMBER() 也存在那里,我希望它可以工作......

【讨论】:

  • 嗨 Cars10m,我不认为这对我有用。在此处添加了一些示例。谢谢。
【解决方案3】:

您可以使用correlated subquerymax 函数来实现您想要的结果,如下所示。

DELETE
FROM table1 t1
WHERE t1.Id <> (
        SELECT max(t2.Id)
        FROM table1 t2
        WHERE t1.col1 = t2.col1
            AND t1.col2 = t2.col2
            AND t1.col3 = t2.col3
            AND t1.col4 = t2.col4
        );

上述查询假定table1 作为您的表名。

select * from table1;

结果:

ID  Col1    Col2    Col3    Col4
---------------------------------
586 ABC    4RTFD    FGY    12,346

您可以查看演示*here

更新:

下面的行被添加到样本数据集中。

id  col1    col2    col3    col4
----------------------------------
345 XYZ    4FTFD    FGY     12346
745 XYZ    4FTFD    FGY     12346
945 XYZ    4FTFD    FGY     12346

结果:

id   col1    col2   col3    col4
-----------------------------------
586  ABC    4RTFD   FGY     12346
945  XYZ    4FTFD   FGY     12346

DEMO

*注意: 由于 teradata 在线演示工具不可用,因此使用 PostgreSQL 演示,因为 PostgreSQL 支持关联子查询。查询也在本地 teradata 环境中进行了模拟。

【讨论】:

  • 谢谢 Zarruq,让我试试这个!!
  • 嗨@Zarruq,这不起作用,因为我想要基于 Nick 提到的某些分区的 max(id),这给了我在 Teradata 中的错误
  • @user3901666:什么分区?因为我在有问题的演示中添加了另一组示例记录,并且它给出了与“尼克”查询相同的结果。另外,您在 teradata 中遇到了什么错误,因为我已经在本地 TD DB 实例上成功模拟了它。 PFAscreenshot
  • @dnoeth:你在吗?请发表评论:-)
  • 嗨 Zarruq,我只需要根据所有列的分区选择最大 id,不包括我需要删除所有记录的最大 id。通过你的代码,我只得到最大 id
【解决方案4】:

这不是分组功能的简单用法吗?

select max(ID) ID, COL1, COL2, COL3
from tableA
group by 2,3,4

并将其保存到新表中。如果需要从现有表中删除重复的行,您可以执行以下删除语句:

delete from tableA as a1
    where (
        select 1 from (
            select max(ID) ID, COL1, COL2, COL3 from tableA group by 2,3,4) a2
        where a1.ID = a2.ID
            and a1.COL1 = a2.COL1
            and a1.COL2 = a2.COL2
            and a1.COL3 = a2.COL3
         ) is null

【讨论】:

  • 这将产生错误,例如子查询中不允许的基于订单的聚合和订单分析功能。我已经实现了使用相关查询(存在子句)
  • @user3901666 没错,有序的分析函数是不允许的,这个解决方案只使用分组,这是允许的。我在我的系统(Teradata 14.10.07.17)上测试了这段代码,它的工作方式与预期一样。
  • 好的..谢谢@Markusn让我检查一次..会回复你的。:)
猜你喜欢
  • 2021-04-28
  • 2011-12-20
  • 1970-01-01
  • 2019-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 1970-01-01
相关资源
最近更新 更多