Удаление повторяющихся строк (на основе значений из нескольких столбцов) из таблицы 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 ответов
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
конечно используется для определения того, как подсчет должен идти, и требуется в