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