sql >> Database >  >> RDS >> Sqlserver

7 manieren om dubbele rijen in SQL Server te vinden terwijl u een primaire sleutel negeert

Hier zijn zeven opties voor het vinden van dubbele rijen in SQL Server, wanneer die rijen een primaire sleutel of een andere unieke id-kolom hebben.

Met andere woorden, de tabel bevat twee of meer rijen die exact dezelfde waarden delen in alle kolommen, behalve de unieke id-kolom.

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 (behalve de DogId kolom, die een unieke waarde voor alle rijen bevat en kan worden gebruikt als de primaire sleutelkolom van de tabel). We kunnen ook zien dat de laatste drie rijen duplicaten zijn (behalve de DogId kolom).

De unieke ID-kolom zorgt ervoor dat er geen dubbele rijen zijn, wat normaal gesproken een zeer wenselijke eigenschap is in RDBMS'en. In dit geval heeft het echter de potentie om ons vermogen om duplicaten te vinden te verstoren. De unieke ID-kolom zorgt er per definitie voor dat er geen duplicaten zijn. Gelukkig kunnen we dit probleem vrij eenvoudig oplossen, zoals de volgende voorbeelden laten zien.

Optie 1

Waarschijnlijk de gemakkelijkste/eenvoudigste manier om dit te doen, is met een eenvoudige query die de GROUP BY gebruikt clausule:

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

Resultaat:

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

We hebben de kolom primaire sleutel/unieke ID kunnen uitsluiten door deze uit onze zoekopdracht weg te laten.

Het resultaat vertelt ons dat er drie rijen zijn met Wag Johnson en twee rijen met Bark Smith. Dit zijn duplicaten (of drievoud in het geval van Wag Johnson).

Optie 2

We kunnen niet-duplicaten uitsluiten van het resultaat door de HAVING . op te nemen clausule in onze vraag:

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

Resultaat:

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

Optie 3

We kunnen ook controleren op duplicaten op aaneengeschakelde kolommen. We kunnen bijvoorbeeld de CONCAT() . gebruiken functie om onze twee kolommen samen te voegen:

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

Resultaat:

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

Optie 4

We kunnen de ROW_NUMBER() . gebruiken functie met de PARTITION BY clausule om een ​​nieuwe kolom te maken met een rijnummer dat wordt verhoogd telkens wanneer er een duplicaat is, maar opnieuw wordt hersteld wanneer er een unieke rij is:

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

Resultaat:

+---------+-------------+------------+--------------+
| 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            |
+---------+-------------+------------+--------------+

Een voordeel van deze methode is dat we elke dubbele rij kunnen zien, samen met de unieke ID-kolom, omdat we de resultaten niet groeperen.

Optie 5

We kunnen het vorige voorbeeld ook gebruiken als een algemene tabeluitdrukking in een grotere query:

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            |
+---------+-------------+------------+--------------+

Deze optie sluit niet-duplicaten uit van de uitvoer.

Het sluit ook precies één rij van elk duplicaat uit van de uitvoer. Dit opent de deur voor ons om de laatste SELECT * . te draaien in een DELETE om de tabel te ontdubbelen terwijl u een van elk duplicaat behoudt.

Optie 6

Hier is een beknoptere manier om dezelfde uitvoer te krijgen als in het vorige voorbeeld:

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  |
+-------+-----------+----------+

Voor dit voorbeeld is het niet nodig om ons eigen aparte rijnummer te genereren.

Optie 7

En tot slot, hier is een iets ingewikkelder techniek om dubbele rijen te retourneren:

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    |
+---------+-------------+------------+---------+-------------+------------+

Zelfs het resultaat ziet er ingewikkelder uit, maar hey, het laat ons nog steeds de duplicaten zien!


  1. Voeg meerdere rijen in één tabel in op basis van het aantal in een andere tabel

  2. Meerdere rijen invoegen in Oracle

  3. Opslag-engine-opties voor MariaDB verkennen

  4. Hoe schakel ik referentiële integriteit in Postgres 8.2 uit?