从 SQL table 中删除重复行(基于多列的值)
Removing duplicate rows (based on values from multiple columns) from SQL table
我关注SQL table:
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)
形成此 table 的主键。
如果您注意到前 3 行属于同一客户(测试客户),他们具有不同的 ShipToCodes:1、2 和 3。第二个客户(ARACODE 客户)的情况类似。 Normal Customer 和 Normal Customer-2 各只有 1 条记录,且为 ShipToCode
。
现在,我想查询此 table 的结果,每个客户只有 1 条记录。因此,对于任何有超过 1 条记录的客户,我想保留 ShipToCode
.
的最高值记录
我尝试了各种方法:
(1) table.
中只有一条记录就可以轻松获取客户列表
(2) 通过下面的查询,我可以得到在 table.
中有多个记录的所有客户的列表
[查询-1]
SELECT ARDivisionNo, CustomerNo
FROM AR_Customer_ShipTo
GROUP BY ARDivisionNo, CustomerNo
HAVING COUNT(*) > 1;
(3) 现在,为了 select 正确 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-测试客户)的相应记录。因此,如果我可以在上述查询 (query-2) 中使用来自 query-1 的所有结果,那么我可以为具有多个记录的客户获取所需的单个记录。这可以与第 (1) 点的结果相结合以获得所需的最终结果。
同样,这比我采用的方法更容易。请告诉我该怎么做。
[注意:我必须仅使用 SQL 查询来执行此操作。我不能使用存储过程,因为我最终将使用 'Scribe Insight' 执行此操作,它只允许我编写查询。]
您没有指定 SQL 服务器的版本,但可能支持 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
具有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
1) 使用CTE根据ARDivisionNo, CustomerNo获取最大ship code值记录
每个客户
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) 要删除记录,请使用删除查询而不是 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;
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
当然是用来定义计数应该如何进行,并且在 ROW_NUMBER()
函数中是必需的。
您也可以使用分组。
SELECT ARDivisionNo,
CustomerNo,
max(ShipToCode) as ShipToCode
FROM AR_Customer_ShipTo
GROUP BY ARDivisionNo, CustomerNo
我关注SQL table:
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)
形成此 table 的主键。
如果您注意到前 3 行属于同一客户(测试客户),他们具有不同的 ShipToCodes:1、2 和 3。第二个客户(ARACODE 客户)的情况类似。 Normal Customer 和 Normal Customer-2 各只有 1 条记录,且为 ShipToCode
。
现在,我想查询此 table 的结果,每个客户只有 1 条记录。因此,对于任何有超过 1 条记录的客户,我想保留 ShipToCode
.
我尝试了各种方法:
(1) table.
中只有一条记录就可以轻松获取客户列表(2) 通过下面的查询,我可以得到在 table.
中有多个记录的所有客户的列表[查询-1]
SELECT ARDivisionNo, CustomerNo
FROM AR_Customer_ShipTo
GROUP BY ARDivisionNo, CustomerNo
HAVING COUNT(*) > 1;
(3) 现在,为了 select 正确 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-测试客户)的相应记录。因此,如果我可以在上述查询 (query-2) 中使用来自 query-1 的所有结果,那么我可以为具有多个记录的客户获取所需的单个记录。这可以与第 (1) 点的结果相结合以获得所需的最终结果。
同样,这比我采用的方法更容易。请告诉我该怎么做。
[注意:我必须仅使用 SQL 查询来执行此操作。我不能使用存储过程,因为我最终将使用 'Scribe Insight' 执行此操作,它只允许我编写查询。]
您没有指定 SQL 服务器的版本,但可能支持 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
具有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
1) 使用CTE根据ARDivisionNo, CustomerNo获取最大ship code值记录 每个客户
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) 要删除记录,请使用删除查询而不是 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;
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
当然是用来定义计数应该如何进行,并且在 ROW_NUMBER()
函数中是必需的。
您也可以使用分组。
SELECT ARDivisionNo,
CustomerNo,
max(ShipToCode) as ShipToCode
FROM AR_Customer_ShipTo
GROUP BY ARDivisionNo, CustomerNo