sql >> Databáze >  >> RDS >> PostgreSQL

7 způsobů, jak najít duplicitní řádky v PostgreSQL při ignorování primárního klíče

Zde je sedm způsobů, jak vrátit duplicitní řádky v PostgreSQL, když tyto řádky mají primární klíč nebo jiný sloupec jedinečného identifikátoru.

To znamená, že duplicitní řádky sdílejí přesně stejné hodnoty ve všech sloupcích s výjimkou jejich primárního klíče/sloupce jedinečného ID.

Ukázková data

Pro naše příklady použijeme následující data:

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

První dva řádky jsou duplikáty (kromě DogId sloupec, který je primárním klíčem tabulky a obsahuje jedinečnou hodnotu ve všech řádcích). Poslední tři řádky jsou také duplikáty (kromě DogId sloupec).

Sloupec primárního klíče zajišťuje, že neexistují žádné duplicitní řádky, což je dobrá praxe v RDBMS, protože primární klíče pomáhají zajistit integritu dat. Ale protože primární klíče zabraňují duplicitním řádkům, mohou narušit naši schopnost najít duplikáty.

V naší tabulce výše je sloupec primárního klíče rostoucí číslo a jeho hodnota nemá žádný význam a není významná. Pokud tedy chceme najít duplikáty v ostatních sloupcích, musíme tento řádek ignorovat.

Možnost 1

Můžeme použít SQL GROUP BY klauzule k seskupení sloupců podle jejich významných sloupců, pak použijte COUNT() funkce, která vrátí počet identických řádků:

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

Výsledek:

 firstname | lastname | count 
-----------+----------+-------
 Ruff      | Robinson |     1
 Wag       | Johnson  |     3
 Woof      | Jones    |     1
 Bark      | Smith    |     2

Zde jsme vyloučili sloupec primárního klíče jeho vynecháním 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. Jedná se o duplikáty (nebo triplikáty v případě Waga Johnsona). Další dva řádky nemají žádné duplikáty.

Možnost 2

Neduplikáty můžeme z výstupu vyloučit pomocí HAVING klauzule:

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

Zde je příklad kontroly duplikátů ve zřetězených sloupcích. V tomto případě použijeme CONCAT() funkci pro spojení našich dvou sloupců použijte DISTINCT klíčové slovo, abyste získali odlišné hodnoty, pak použijte COUNT() funkce, která vrátí počet:

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

Výsledek:

    dogname    | count 
---------------+-------
 Wag Johnson   |     3
 Ruff Robinson |     1
 Woof Jones    |     1
 Bark Smith    |     2

Možnost 4

Alternativně můžeme použít ROW_NUMBER() funkce okna:

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

Pomocí PARTITION klauzule má za následek přidání nového sloupce s číslem řádku, které se zvýší pokaždé, když existuje duplikát, ale znovu se resetuje, když existuje jedinečný řádek.

V tomto případě výsledky neseskupujeme, což znamená, že můžeme vidět každý duplicitní řádek, včetně sloupce s jedinečným identifikátorem.

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

Tím se z výstupu vyloučí neduplikáty a z výstupu se vyloučí jeden řádek každého duplikátu. Jinými slovy, zobrazuje pouze přebytečné řádky z duplikátů. Tyto řádky jsou hlavními kandidáty na odstranění v operaci odstranění duplikátů.

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 
-------+-----------+----------
     6 | Wag       | Johnson
     2 | Bark      | Smith
     7 | Wag       | Johnson

Jeden rozdíl mezi tímto příkladem a předchozím je v tom, že tento příklad nevyžaduje generování vlastního samostatného čísla řádku.

Možnost 7

Zde je další možnost, jak vrátit duplicitní řádky v Postgres:

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

  1. Přejmenování uživatelem definovaného datového typu v SQL Server (T-SQL)

  2. Jak importovat soubor Excel do SQL Server?

  3. Jak použít smyčku SQL for k vložení řádků do databáze?

  4. Spouštěcí vs. kontrolní omezení