sql >> Database >  >> RDS >> Sqlserver

3 manieren om dubbele rijen in SQL Server te verwijderen terwijl de primaire sleutel wordt genegeerd

In de volgende voorbeelden wordt T-SQL gebruikt om dubbele rijen in SQL Server te verwijderen terwijl de primaire sleutel of de unieke id-kolom wordt genegeerd.

Meer specifiek verwijderen de voorbeelden dubbele rijen, maar behouden ze er een. Dus, gegeven twee identieke rijen, wordt de ene verwijderd en de andere blijft. Dit wordt vaak "deduplicatie" van de tabel genoemd, "deduplicatie" van de tabel, enz.

Voorbeeldgegevens

Stel dat we een tabel hebben met de volgende gegevens:

SELECT * FROM Dogs;

Resultaat:

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

We kunnen zien dat de eerste twee rijen duplicaten zijn, en dat geldt ook voor de laatste drie rijen.

Optie 1

Laten we eerst de volgende code uitvoeren om te controleren welke rijen worden ontdubbeld:

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;

Resultaat:

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

We gebruikten de ROW_NUMBER() functie met de PARTITION BY clausule om ons eigen rijnummer te maken dat wordt verhoogd wanneer er duplicaten worden gevonden en opnieuw wordt ingesteld wanneer een niet-duplicaat wordt gevonden. Een getal groter dan 1 geeft aan dat het een duplicaat is, en daarom retourneren we alleen rijen met een getal groter dan 1.

We kunnen zien dat drie rijen worden verwijderd wanneer we deze tabel ontdubbelen.

Laten we nu de tabel ontdubbelen:

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

Resultaat:

(3 rows affected)

Zoals verwacht zijn er drie rijen verwijderd.

Deze vraag is bijna identiek aan de vorige. Het enige wat we deden was SELECT * veranderen op de laatste regel naar DELETE .

Laten we nu alle rijen uit de tabel selecteren om te controleren of de juiste rijen zijn verwijderd:

SELECT * FROM Dogs;

Resultaat:

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

We kunnen zien dat elke hond nu maar één keer in de tabel voorkomt.

Optie 2

Ervan uitgaande dat de tabel is hersteld na het vorige voorbeeld, is hier een andere manier om te controleren op duplicaten:

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

Resultaat:

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

In dit geval hebben we gebruik gemaakt van de EXCEPT operator samen met de MIN() functie. We zouden MIN() . kunnen vervangen met MAX() afhankelijk van welke rijen we willen verwijderen.

Om de rijen te verwijderen, kunnen we eenvoudig SELECT * . vervangen met DELETE :

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

Resultaat:

(3 rows affected)

En kijk wat er nog over is:

SELECT * FROM Dogs;

Resultaat:

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

Optie 3

Een andere manier om dit te doen is om de tafel op zichzelf te voegen en op die manier te controleren op duplicaten.

Ervan uitgaande dat de tabel is hersteld na het vorige voorbeeld, is hier onze derde optie voor het selecteren van duplicaten:

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
);

Resultaat:

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

Dit resultaat is niet zo duidelijk als in het vorige voorbeeld, maar we kunnen nog steeds zien welke rijen duplicaten zijn.

Nu kunnen we die zoekopdracht aanpassen zodat we dubbele rijen verwijderen:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    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
    )
);

Resultaat:

(3 rows affected)

Opnieuw werden drie rijen verwijderd.

Laten we de tabel nog eens bekijken:

SELECT * FROM Dogs;

Resultaat:

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

Het is u misschien opgevallen dat deze keer de andere rijen zijn verwijderd. Met andere woorden, we hebben nu DogId s 2, 3, 4 en 7 terwijl we in de vorige voorbeelden 1, 3, 4 en 5 overhielden.

We kunnen dit voorbeeld eenvoudig wijzigen om dezelfde rijen als de vorige voorbeelden te verwijderen. Om dit te doen, kunnen we de MIN() . gebruiken functie in plaats van de MAX() functie:

DELETE FROM Dogs WHERE DogId IN (
    SELECT d2.DogId 
    FROM Dogs d1, Dogs d2 
    WHERE d1.FirstName = d2.FirstName 
    AND d1.LastName = d2.LastName 
    AND d1.DogId <> d2.DogId 
    AND d1.DogId=( 
        SELECT MIN(DogId) 
        FROM Dogs d3 
        WHERE d3.FirstName = d1.FirstName 
        AND d3.LastName = d1.LastName
    )
);

  1. Slick 2.0 Generieke CRUD-bewerkingen

  2. Wijzig het wachtwoord voor een SQL Server-aanmelding

  3. MySQL-variabelenformaat voor een NOT IN-lijst met waarden

  4. Opgeslagen Oracle-procedure:retourneer zowel de resultaatset als de out-parameters