sql >> Database teknologi >  >> RDS >> Sqlserver

7 måder at finde duplikerede rækker i SQL Server, mens du ignorerer enhver primær nøgle

Her er syv muligheder for at finde duplikerede rækker i SQL Server, når disse rækker har en primær nøgle eller en anden unik identifikatorkolonne.

Tabellen indeholder med andre ord to eller flere rækker, der deler nøjagtig de samme værdier på tværs af alle kolonner undtagen dens unikke identifikatorkolonne.

Eksempeldata

Antag, at vi har en tabel med følgende data:

SELECT * FROM Dogs;

Resultat:

+---------+-------------+------------+
| DogId   | FirstName   | LastName   |
|---------+-------------+------------|
| 1       | Bark        | Smith      |
| 2       | Bark        | Smith      |
| 3       | Woof        | Jones      |
| 4       | Ruff        | Robinson   |
| 5       | Wag         | Johnson    |
| 6       | Wag         | Johnson    |
| 7       | Wag         | Johnson    |
+---------+-------------+------------+

Vi kan se, at de første to rækker er dubletter (undtagen DogId kolonne, som indeholder en unik værdi på tværs af alle rækker og kan bruges som tabellens primære nøglekolonne). Vi kan også se, at de sidste tre rækker er dubletter (undtagen DogId kolonne).

Den unikke ID-kolonne sikrer, at der ikke er duplikerede rækker, hvilket normalt er et meget ønskeligt træk i RDBMS'er. Men i dette tilfælde har det potentiale til at forstyrre vores evne til at finde dubletter. Per definition sikrer den unikke ID-kolonne, at der ikke er dubletter. Heldigvis kan vi løse dette problem ganske let, som de følgende eksempler viser.

Valgmulighed 1

Sandsynligvis den nemmeste/simpelste måde at gøre det på er med en simpel forespørgsel, der bruger GROUP BY klausul:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;

Resultat:

+-------------+------------+---------+
| FirstName   | LastName   | Count   |
|-------------+------------+---------|
| Wag         | Johnson    | 3       |
| Woof        | Jones      | 1       |
| Ruff        | Robinson   | 1       |
| Bark        | Smith      | 2       |
+-------------+------------+---------+

Vi var i stand til at ekskludere den primære nøgle/det unikke ID-kolonne ved at udelade den fra vores forespørgsel.

Resultatet fortæller os, at der er tre rækker indeholdende Wag Johnson og to rækker indeholdende Bark Smith. Disse er dubletter (eller triplikater i tilfælde af Wag Johnson).

Valgmulighed 2

Vi kan ekskludere ikke-duplikater fra resultatet ved at inkludere HAVING klausul i vores forespørgsel:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;

Resultat:

+-------------+------------+---------+
| FirstName   | LastName   | Count   |
|-------------+------------+---------|
| Wag         | Johnson    | 3       |
| Bark        | Smith      | 2       |
+-------------+------------+---------+

Valgmulighed 3

Vi kan også kontrollere for dubletter på sammenkædede kolonner. For eksempel kan vi bruge CONCAT() funktion til at sammenkæde vores to kolonner:

SELECT
    DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
    COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);

Resultat:

+---------------+---------+
| DogName       | Count   |
|---------------+---------|
| Bark Smith    | 2       |
| Ruff Robinson | 1       |
| Wag Johnson   | 3       |
| Woof Jones    | 1       |
+---------------+---------+

Valgmulighed 4

Vi kan bruge ROW_NUMBER() funktion med PARTITION BY klausul for at oprette en ny kolonne med et rækkenummer, der stiger hver gang der er en dublet, men nulstilles igen, når der er en unik række:

SELECT 
    *,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS Row_Number
FROM Dogs;

Resultat:

+---------+-------------+------------+--------------+
| DogId   | FirstName   | LastName   | Row_Number   |
|---------+-------------+------------+--------------|
| 1       | Bark        | Smith      | 1            |
| 2       | Bark        | Smith      | 2            |
| 4       | Ruff        | Robinson   | 1            |
| 5       | Wag         | Johnson    | 1            |
| 6       | Wag         | Johnson    | 2            |
| 7       | Wag         | Johnson    | 3            |
| 3       | Woof        | Jones      | 1            |
+---------+-------------+------------+--------------+

En fordel ved denne metode er, at vi kan se hver eneste dubletrække sammen med dens unikke identifikatorkolonne på grund af det faktum, at vi ikke grupperer resultaterne.

Valgmulighed 5

Vi kan også bruge det foregående eksempel som et almindeligt tabeludtryk i en større forespørgsel:

WITH cte AS 
    (
        SELECT 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Resultat:

+---------+-------------+------------+--------------+
| DogId   | FirstName   | LastName   | Row_Number   |
|---------+-------------+------------+--------------|
| 2       | Bark        | Smith      | 2            |
| 6       | Wag         | Johnson    | 2            |
| 7       | Wag         | Johnson    | 3            |
+---------+-------------+------------+--------------+

Denne indstilling udelukker ikke-duplikater fra outputtet.

Det udelukker også nøjagtig én række af hver dublet fra outputtet. Dette åbner døren for os til at dreje den sidste SELECT * ind i en DELETE at de-dupere tabellen, mens du beholder en af ​​hver duplikat.

Valgmulighed 6

Her er en mere kortfattet måde at få det samme output som det foregående eksempel:

SELECT * FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    EXCEPT SELECT MIN(DogId) FROM Dogs 
    GROUP BY FirstName, LastName
    );

Resultat:

+-------+-----------+----------+
| DogId | FirstName | LastName |
+-------+-----------+----------+
|     2 | Bark      | Smith    |
|     6 | Wag       | Johnson  |
|     7 | Wag       | Johnson  |
+-------+-----------+----------+

Dette eksempel kræver ikke generering af vores eget separate rækkenummer.

Valgmulighed 7

Og endelig, her er en lidt mere indviklet teknik til at returnere duplikerede rækker:

SELECT * 
FROM Dogs d1, Dogs d2 
WHERE d1.FirstName = d2.FirstName 
AND d1.LastName = d2.LastName
AND d1.DogId <> d2.DogId 
AND d1.DogId = (
    SELECT MAX(DogId) 
    FROM Dogs d3 
    WHERE d3.FirstName = d1.FirstName 
    AND d3.LastName = d1.LastName
);

Resultat:

+---------+-------------+------------+---------+-------------+------------+
| DogId   | FirstName   | LastName   | DogId   | FirstName   | LastName   |
|---------+-------------+------------+---------+-------------+------------|
| 2       | Bark        | Smith      | 1       | Bark        | Smith      |
| 7       | Wag         | Johnson    | 5       | Wag         | Johnson    |
| 7       | Wag         | Johnson    | 6       | Wag         | Johnson    |
+---------+-------------+------------+---------+-------------+------------+

Selv resultatet ser mere indviklet ud, men hey, det viser os stadig dubletterne!


  1. en optælling for hver joinforbindelse - optimering

  2. MySql-fejl:1364 Feltet 'display_name' har ikke standardværdi

  3. Hvordan ændrer jeg datatypen for en kolonne i MySQL?

  4. SQL kommasepareret række med Group By-sætning