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

Vik*_*ram 20 sql t-sql sql-server join duplicate-removal

我有以下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 |
+--------------+------------+-------------------+------------+
Run Code Online (Sandbox Code Playgroud)

(ARDivisionNo, CustomerNo,ShipToCode) 形成此表的主键.

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

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

我试过各种各样的事情

(1)我可以轻松获得表中只有一条记录的客户列表.

(2)通过以下查询,我可以获得在表中有多个记录的所有客户的列表.

[查询-1]

SELECT ARDivisionNo, CustomerNo
FROM AR_Customer_ShipTo 
GROUP BY ARDivisionNo, CustomerNo
HAVING COUNT(*) > 1;
Run Code Online (Sandbox Code Playgroud)

(3)现在,为了选择适合ShipToCode上述查询返回的每条记录,我无法弄清楚如何迭代上述查询返回的所有记录.

如果我这样做:

[查询-2]

SELECT TOP 1 ARDivisionNo, CustomerNo, CustomerName, ShipToCode  
FROM AR_Customer_ShipTo 
WHERE ARDivisionNo = '00' and CustomerNo = '1234567'
ORDER BY ShipToCode DESC
Run Code Online (Sandbox Code Playgroud)

然后我可以获得(00-1234567-测试客户)的相应记录.因此,如果我可以在上面的查询(query-2)中使用来自query-1的所有结果,那么我可以为具有多个记录的客户获得所需的单个记录.这可以与点(1)的结果组合以实现期望的最终结果.

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

[注意:我必须仅使用SQL查询来执行此操作.我不能使用存储过程,因为我最终将使用'Scribe Insight'执行此操作,它只允许我编写查询.

Hav*_*ame 35

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
Run Code Online (Sandbox Code Playgroud)

2)要删除记录,请使用删除查询而不是选择并将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;
Run Code Online (Sandbox Code Playgroud)


Gio*_*uri 7

具有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
Run Code Online (Sandbox Code Playgroud)


dno*_*eth 6

您没有指定 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
Run Code Online (Sandbox Code Playgroud)


Har*_* CO 6

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
Run Code Online (Sandbox Code Playgroud)

您提到删除重复项,如果您愿意,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
Run Code Online (Sandbox Code Playgroud)

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