从 SQL 表中删除重复的行(基于多列的值)

Posted

技术标签:

【中文标题】从 SQL 表中删除重复的行(基于多列的值)【英文标题】:Removing duplicate rows (based on values from multiple columns) from SQL table 【发布时间】:2015-07-26 11:02:07 【问题描述】:

我有以下 SQL 表:

AR_Customer_ShipTo

+--------------+------------+-------------------+------------+
| ARDivisionNo | CustomerNo |   CustomerName    | ShipToCode |
+--------------+------------+-------------------+------------+
|           00 | 1234567    | Test Customer     |          1 |
|           00 | 1234567    | Test Customer     |          2 |
|           00 | 1234567    | Test Customer     |          3 |
|           00 | ARACODE    | ARACODE Customer  |          1 |
|           00 | ARACODE    | ARACODE Customer  |          2 |
|           01 | CBE1EX     | Normal Customer   |          1 |
|           02 | ZOCDOC     | Normal Customer-2 |          1 |
+--------------+------------+-------------------+------------+

(ARDivisionNo, CustomerNo,ShipToCode) 构成该表的主键。

如果您注意到前 3 行属于同一客户(测试客户),他们具有不同的 ShipToCode:1、2 和 3。第二个客户(ARACODE 客户)的情况类似。普通客户和普通客户 2 中的每一个都只有 1 条记录,带有一个 ShipToCode

现在,我想在此表上查询结果,每个客户只有 1 条记录。因此,对于任何有超过 1 条记录的客户,我希望将价值最高的记录保留为 ShipToCode

我尝试了各种方法:

(1) 表格中只有一条记录,我可以轻松获取客户列表。

(2) 通过以下查询,我可以获得所有客户的列表,这些客户在表中拥有多条记录。

[Query-1]

SELECT ARDivisionNo, CustomerNo
FROM AR_Customer_ShipTo 
GROUP BY ARDivisionNo, CustomerNo
HAVING COUNT(*) > 1;

(3) 现在,为了为上述查询返回的每条记录选择正确的ShipToCode,我无法弄清楚如何遍历上述查询返回的所有记录。

如果我这样做:

[Query-2]

SELECT TOP 1 ARDivisionNo, CustomerNo, CustomerName, ShipToCode  
FROM AR_Customer_ShipTo 
WHERE ARDivisionNo = '00' and CustomerNo = '1234567'
ORDER BY ShipToCode DESC

然后我可以获得(00-1234567-Test Customer)的相应记录。因此,如果我可以在上述查询 (query-2) 中使用来自 query-1 的所有结果,那么我可以获得具有多个记录的客户所需的单个记录。这可以与第 (1) 点的结果相结合,以获得所需的最终结果。

同样,这比我所遵循的方法更容易。请让我知道我该怎么做。

[注意:我必须仅使用 SQL 查询来执行此操作。我不能使用存储过程,因为我最终将使用“Scribe Insight”来执行这个东西,它只允许我编写查询。]

【问题讨论】:

How to delete duplicate rows in sql server?的可能重复 【参考方案1】:

Sample SQL FIDDLE

1) 使用 CTE 根据 ARDivisionNo, CustomerNo 获取最大船码值记录 每个客户

WITH cte AS (
  SELECT*, 
     row_number() OVER(PARTITION BY ARDivisionNo, CustomerNo ORDER BY ShipToCode desc) AS [rn]
  FROM t
)
Select * from cte WHERE [rn] = 1

2) 要删除记录,请使用 Delete 查询而不是 Select 并将 Where 子句更改为 rn > 1. Sample SQL FIDDLE

WITH cte AS (
  SELECT*, 
     row_number() OVER(PARTITION BY ARDivisionNo, CustomerNo ORDER BY ShipToCode desc) AS [rn]
  FROM t
)
Delete from cte WHERE [rn] > 1;

select * from t;

【讨论】:

非常感谢您的回答和示例 SQL FIDDLES! :) 我提出的所有其他答案(以及我在其下方的评论)都帮助了我并解决了我的问题。我将此标记为答案,因为 Piyush 努力创建和发布 Sample SQL FIDDLES。我希望我也可以将其他人标记为答案(或至少一个由 Hart CO 提供的解释),但 *** 只允许我选择一个! 谢谢..维克拉姆...希望你能解决你的问题!!我也喜欢@Hart CO :- 解释【参考方案2】:

ROW_NUMBER() 非常适合:

;WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY ARDivisionNo,CustomerNo ORDER BY ShipToCode DESC) AS RN 
              FROM AR_Customer_ShipTo
              )
SELECT * 
FROM  cte
WHERE RN = 1

您提到删除重复项,如果您想DELETE,您可以简单地:

;WITH cte AS (SELECT *,ROW_NUMBER() OVER(PARTITION BY ARDivisionNo,CustomerNo ORDER BY ShipToCode DESC) AS RN 
              FROM AR_Customer_ShipTo
              )
DELETE cte
WHERE RN > 1

ROW_NUMBER() 函数为每一行分配一个数字。 PARTITION BY 是可选的,但用于为给定字段或字段组中的每个值重新编号,即:如果您 PARTITION BY Some_Date 则对于每个唯一日期值,编号将从 1 开始。ORDER BY of course 用于定义计数应该如何进行,并且在ROW_NUMBER() 函数中是必需的。

【讨论】:

非常感谢您的回答和详细的解释! :) 一点更正:对于我提出的问题中的特定示例,它应该是 partition by ARDivisionNo, CustomerNo 而不是 partition by CustomerNo @Vikram 已相应更新。,【参考方案3】:

您没有指定 SQL Server 的版本,但可能支持 ROW_NUMBER:

select *
from
 (
  select ...
     ,row_number() 
      over (partition by ARDivisionNo, CustomerNo
            order by ShipToCode desc) as rn 
  from tab
 ) as dt
where rn = 1

【讨论】:

非常感谢您的回答! :)【参考方案4】:

带有row_number功能:

SELECT * FROM(
              SELECT ARDivisionNo, CustomerNo, CustomerName, ShipToCode,
              row_number() over(partition by CustomerNo order by ShipToCode desc) rn
              FROM AR_Customer_ShipTo) t
WHERE rn = 1

【讨论】:

非常感谢您的回答! :) 一点更正:对于我提出的问题中的特定示例,它应该是 partition by ARDivisionNo, CustomerNo 而不是 partition by CustomerNo【参考方案5】:

您也可以使用分组。

SELECT ARDivisionNo, 
       CustomerNo,
       max(ShipToCode) as ShipToCode  
FROM AR_Customer_ShipTo 
GROUP BY ARDivisionNo, CustomerNo

【讨论】:

以上是关于从 SQL 表中删除重复的行(基于多列的值)的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SQL Server 中的表中删除重复行 [重复]

基于具有列表值的多列删除数据框中的重复行[重复]

从 sqlite 数据库中删除重复的行

sql 表中删除字段重复的行

基于Javascript中的一列从多列中删除重复项

如何从mysql中的表中删除重复的行