2015-05-14 26 views
7

重复行(基于从多个列中的值)我具有以下SQL表:卸下从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行属于同一个客户(测试客户),他们有不同的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; 

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

如果我做这样的事情:

[查询2]

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

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

再次,这可能比我所遵循的方法更容易。请让我知道我该怎么做。我不得不使用SQL查询来做这个。我不能使用存储过程,因为我将最终使用'Scribe Insight'来执行这个事情,它只允许我写查询。]

+0

可能重复的[如何删除sql server中的重复行?](http://stackoverflow.com/questions/18390574/how-to-delete-duplicate-rows-in-sql-server) –

回答

14

Sample SQL FIDDLE

1)使用CTE根据ARDivisionNo获得最大船代码价值记录,客户编号为 ,每个C ustomers

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)删除记录使用删除查询,而不是选择和更改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; 
+0

非常感谢答案和示例SQL FIDDLES! :) – Vikram

+0

所有其他答案由我(和我下面的评论)upvoted帮助我解决了我的问题。我将此标记为答案,因为Piyush努力创建并发布Sample SQL FIDDLES。我希望我也可以将其他人标记为答案(或者至少有一个由Hart CO提供的解释),但是stackoverflow只能让我选择一个! – Vikram

+0

Thanks..Vikram ...希望你能解决问题!我也喜欢@哈尔CO: - 解释 – HaveNoDisplayName

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 
+0

非常感谢为了答案! :) – Vikram

2

随着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 
+0

非常感谢您的答案! :) – Vikram

+0

纠正一点:它应该是'ARDivisionNo,CustomerNo'的分区,而不是'CustomerNo'的分区,用于我问的特定问题。 – Vikram

3

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是可选的,但是用于开始给定字段或字段组中的每个值的编号,即:如果对于每个唯一日期值,编号将从1开始。当然,ORDER BY用于定义计数应该去,并且在ROW_NUMBER()函数中是必需的。

+0

非常感谢您的回答和详细的解释! :) – Vikram

+1

纠正一点:它应该是由ARDivisionNo,CustomerNo'进行分区,而不是由CustomerNo进行分区,用于我问的特定示例。 – Vikram

+0

@Vikram据此更新。, –