sql >> Databáze >  >> RDS >> Sqlserver

7 způsobů, jak najít duplicitní řádky na serveru SQL při ignorování jakéhokoli primárního klíče

Zde je sedm možností pro nalezení duplicitních řádků na serveru SQL Server, pokud tyto řádky mají primární klíč nebo jiný sloupec jedinečného identifikátoru.

Jinými slovy, tabulka obsahuje dva nebo více řádků, které sdílejí přesně stejné hodnoty ve všech sloupcích kromě sloupce s jedinečným identifikátorem.

Ukázková data

Předpokládejme, že máme tabulku s následujícími údaji:

SELECT * FROM Dogs;

Výsledek:

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

Vidíme, že první dva řádky jsou duplikáty (kromě DogId sloupec, který obsahuje jedinečnou hodnotu ve všech řádcích a lze jej použít jako sloupec primárního klíče tabulky). Můžeme také vidět, že poslední tři řádky jsou duplikáty (kromě DogId sloupec).

Jedinečný sloupec ID zajišťuje, že neexistují žádné duplicitní řádky, což je obvykle vysoce žádoucí vlastnost v RDBMS. V tomto případě však může narušit naši schopnost najít duplikáty. Podle definice sloupec jedinečného ID zajišťuje, že neexistují žádné duplikáty. Naštěstí můžeme tento problém překonat poměrně snadno, jak ukazují následující příklady.

Možnost 1

Pravděpodobně nejjednodušší/nejjednodušší způsob, jak to udělat, je pomocí jednoduchého dotazu, který používá GROUP BY klauzule:

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

Výsledek:

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

Podařilo se nám vyloučit sloupec primárního klíče/jedinečného ID tím, že jsme jej vynechali z našeho dotazu.

Výsledek nám říká, že existují tři řádky obsahující Wag Johnson a dva řádky obsahující Bark Smith. Toto jsou duplikáty (nebo triplikáty v případě Waga Johnsona).

Možnost 2

Neduplikáty můžeme z výsledku vyloučit zahrnutím HAVING klauzule v našem dotazu:

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

Výsledek:

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

Možnost 3

Můžeme také zkontrolovat duplikáty na zřetězených sloupcích. Můžeme například použít CONCAT() funkce pro spojení našich dvou sloupců:

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

Výsledek:

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

Možnost 4

Můžeme použít ROW_NUMBER() pomocí funkce PARTITION BY klauzule k vytvoření nového sloupce s číslem řádku, které se zvyšuje pokaždé, když je duplikát, ale znovu se resetuje, když existuje jedinečný řádek:

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

Výsledek:

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

Jednou z výhod této metody je, že můžeme vidět každý duplicitní řádek spolu s jeho sloupcem s jedinečným identifikátorem, protože výsledky neseskupujeme.

Možnost 5

Předchozí příklad můžeme také použít jako běžný tabulkový výraz ve větším dotazu:

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;

Výsledek:

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

Tato možnost vyloučí z výstupu neduplikáty.

Z výstupu také vyloučí přesně jeden řádek každého duplikátu. Tím se nám otevírají dveře k otočení posledního SELECT * do DELETE pro odstranění duplicit v tabulce při zachování jednoho z každého duplikátu.

Možnost 6

Zde je stručnější způsob, jak získat stejný výstup jako v předchozím příkladu:

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

Výsledek:

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

Tento příklad nevyžaduje generování vlastního samostatného čísla řádku.

Možnost 7

A nakonec je zde trochu komplikovanější technika vrácení duplicitních řádků:

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

Výsledek:

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

I výsledek vypadá spletitěji, ale stále nám ukazuje duplikáty!


  1. Závažná chyba:Volání členské funkce bind_param() na boolean

  2. Jak ladit ORA-01775:smyčkový řetězec synonym?

  3. Postgres NENÍ v poli

  4. Export MySQL do výstupního souboru:CSV escaping chars