Удаление повторяющихся строк (на основе значений из нескольких столбцов) из таблицы 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 Customer). Каждый из нормальных клиентов и обычных клиентов-2 имеет только 1 запись с одним 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-тестовый клиент). Следовательно, если я могу использовать все результаты запроса 1 в над запросом (query-2), тогда я могу получить желаемые одиночные записи для клиентов с более чем одной записью. Это может быть объединено с результатами из точки (1) для достижения желаемого конечного результата.

опять же, это может быть проще, чем подойти я. Пожалуйста, дайте мне знать, как я могу это сделать.

[Примечание: я должен сделать это, используя только SQL-запросы. Я не могу использовать хранимые процедуры, поскольку я собираюсь выполнить эту вещь, наконец, используя "Scribe Insight", который позволяет мне только писать запросы.]

4 ответов


пример 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 query вместо Select и change Where в RN > 1. пример 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 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

С 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

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 конечно используется для определения того, как подсчет должен идти, и требуется в