web-dev-qa-db-fra.com

Suppression de lignes en double (basées sur les valeurs de plusieurs colonnes) de la table SQL

J'ai le tableau SQL suivant:

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) forme une clé primaire pour cette table.

Si vous remarquez que les 3 premières lignes appartiennent au même client (client test), qui a des ShipToCodes différents: 1, 2 et 3. Il en va de même pour le deuxième client (client ARACODE). Chacun des clients Normal et Client Normal-2 ne possède qu'un seul enregistrement avec un seul ShipToCode.

Maintenant, je voudrais obtenir des résultats sur cette table, où je n'aurai qu'un seul enregistrement par client. Donc, pour tout client, où il y a plus d'un enregistrement, je voudrais conserver l'enregistrement avec la valeur la plus élevée pour ShipToCode.

J'ai essayé différentes choses:

(1) Je peux facilement obtenir la liste des clients avec un seul enregistrement dans le tableau.

(2) Avec la requête suivante, je peux obtenir la liste de tous les clients qui ont plus d'un enregistrement dans le tableau.

[Requête-1]

SELECT ARDivisionNo, CustomerNo
FROM AR_Customer_ShipTo 
GROUP BY ARDivisionNo, CustomerNo
HAVING COUNT(*) > 1;

(3) Maintenant, afin de sélectionner le ShipToCode approprié pour chaque enregistrement renvoyé par la requête ci-dessus, je ne suis pas en mesure de comprendre comment parcourir tous les enregistrements renvoyés par la requête ci-dessus.

Si je fais quelque chose comme:

[Requête-2]

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

Ensuite, je peux obtenir l'enregistrement approprié pour (00-1234567-Test Client). Par conséquent, si je peux utiliser tous les résultats de la requête-1 dans la requête ci-dessus (requête-2), alors je peux obtenir les enregistrements uniques souhaités pour les clients avec plusieurs enregistrements. Ceci peut être combiné avec les résultats du point (1) pour atteindre le résultat final souhaité.

Encore une fois, cela peut être plus facile que l'approche que je suis en train de suivre. Veuillez me faire savoir comment procéder.

[Remarque: je dois le faire en utilisant uniquement des requêtes SQL. Je ne peux pas utiliser de procédures stockées, car je vais enfin exécuter cette chose en utilisant 'Scribe Insight', qui ne me permet que d'écrire des requêtes.]

19
Vikram

Sample SQL FIDDLE

1) Utilisez CTE pour obtenir un enregistrement de valeur de code de navire max basé sur ARDivisionNo, CustomerNo pour chaque client

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) Pour supprimer l'enregistrement, utilisez Supprimer la requête au lieu de Sélectionner et remplacez la clause Where par 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;
33

Vous n'avez pas spécifié la version de SQL Server, mais ROW_NUMBER est probablement pris en charge:

select *
from
 (
  select ...
     ,row_number() 
      over (partition by ARDivisionNo, CustomerNo
            order by ShipToCode desc) as rn 
  from tab
 ) as dt
where rn = 1
4
dnoeth

ROW_NUMBER() est idéal pour cela:

;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

Vous mentionnez la suppression des doublons, si vous voulez DELETE vous pouvez simplement:

;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

La fonction ROW_NUMBER() attribue un numéro à chaque ligne. PARTITION BY Est facultatif, mais utilisé pour recommencer la numérotation pour chaque valeur dans un champ ou un groupe de champs donné, c'est-à-dire: si vous PARTITION BY Some_Date Alors pour chaque valeur de date unique, la numérotation recommencerait à 1. ORDER BY Est bien sûr utilisé pour définir le déroulement du comptage, et est requis dans la fonction ROW_NUMBER().

4
Hart CO

Avec row_number une fonction:

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
3
Giorgi Nakeuri