Zde je jedenáct možností pro vrácení duplicitních řádků v databázi Oracle, když tyto řádky mají primární klíč nebo jiný sloupec jedinečného identifikátoru a chcete jej ignorovat.
Ukázková data
Pro naše příklady použijeme následující data:
SELECT * FROM Dogs; Výsledek:
| DOGID | FIRSTNAME | LASTNAME |
|---|---|---|
| 1 | Kůra | Smith |
| 2 | Kůra | Smith |
| 3 | Fuj | Jones |
| 4 | Ruff | Robinson |
| 5 | Wag | Johnson |
| 6 | Wag | Johnson |
| 7 | Wag | Johnson |
První dva řádky jsou duplikáty a poslední tři řádky jsou duplikáty. Duplicitní řádky sdílejí přesně stejné hodnoty ve všech sloupcích s výjimkou jejich primárního klíče/sloupce s jedinečným ID.
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 skutečnost, že primární klíče obsahují jedinečné hodnoty, znamená, že tento sloupec musíme při hledání duplikátů ignorovat.
V naší tabulce výše je sloupec primárního klíče vzrůstající číslo a jeho hodnota nemá žádný význam a není významná. Při hledání duplikátů tedy můžeme data tohoto sloupce ignorovat.
Možnost 1
Zde je naše první možnost, jak vrátit duplikáty:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
ORDER BY Count DESC; Výsledek:
| FIRSTNAME | LASTNAME | COUNT |
|---|---|---|
| Wag | Johnson | 3 |
| Kůra | Smith | 2 |
| Ruff | Robinson | 1 |
| Fuj | Jones | 1 |
Zde jsme vytvořili náš dotaz pomocí GROUP BY klauzule tak, aby byl výstup seskupen podle příslušných sloupců. Také jsme použili COUNT() funkce vrátí počet identických řádků. A seřadili jsme to podle počtu v sestupném pořadí, aby se jako první objevily duplikáty.
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
Můžeme přidat HAVING klauzule k našemu předchozímu příkladu k vyloučení neduplikátů z výstupu:
SELECT
FirstName,
LastName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1
ORDER BY Count DESC; Výsledek:
| FIRSTNAME | LASTNAME | COUNT |
|---|---|---|
| Wag | Johnson | 3 |
| Kůra | Smith | 2 |
Možnost 3
Můžeme také zkontrolovat duplikáty na zřetězených sloupcích. V tomto případě použijeme DISTINCT klíčové slovo, abyste získali odlišné hodnoty, pak použijte COUNT() funkce, která vrátí počet:
SELECT
DISTINCT FirstName || ' ' || LastName AS DogName,
COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName || ' ' || LastName
ORDER BY Count DESC; Výsledek:
| JMÉNO PSA | COUNT |
|---|---|
| Wag Johnson | 3 |
| Bark Smith | 2 |
| Ruff Robinson | 1 |
| Páni Jones | 1 |
Možnost 4
Každý řádek v Oracle má rowid pseudosloupec, který vrací adresu řádku. rowid je jedinečný identifikátor pro řádky v tabulce a jeho hodnota obvykle jednoznačně identifikuje řádek v databázi (ačkoli je důležité si uvědomit, že řádky v různých tabulkách, které jsou uloženy společně ve stejném clusteru, mohou mít stejný rowid ).
Každopádně můžeme sestavit dotaz, který používá rowid pokud chceme:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.rowid > d2.rowid
); Výsledek:
| DOGID | FIRSTNAME | LASTNAME |
|---|---|---|
| 2 | Kůra | Smith |
| 6 | Wag | Johnson |
| 7 | Wag | Johnson |
Mohli bychom nahradit SELECT * pomocí DELETE k provedení operace odstranění duplikace na stole.
Všimněte si, že jsme mohli použít DogId (náš primární klíč) namísto rowid kdybychom chtěli. To znamená, že rowid může být užitečné, pokud z nějakého důvodu nemůžete použít sloupec primárního klíče nebo pokud tabulka primární klíč nemá.
Možnost 5
Zde je další dotaz, který používá rowid :
SELECT * FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
); Výsledek:
| DOGID | FIRSTNAME | LASTNAME |
|---|---|---|
| 2 | Kůra | Smith |
| 6 | Wag | Johnson |
| 7 | Wag | Johnson |
Stejně jako v předchozím příkladu bychom mohli nahradit SELECT * pomocí DELETE k odstranění duplicitních řádků.
Možnost 6
Dva rowid výše uvedené možnosti jsou skvělé, pokud musíte primární klíč v dotazu zcela ignorovat (nebo pokud sloupec primárního klíče vůbec nemáte). Jak však bylo zmíněno, stále existuje možnost nahradit rowid se sloupcem primárního klíče – v našem případě DogId sloupec:
SELECT * FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.DogId > d2.DogId
); Výsledek:
| DOGID | FIRSTNAME | LASTNAME |
|---|---|---|
| 2 | Kůra | Smith |
| 6 | Wag | Johnson |
| 7 | Wag | Johnson |
Možnost 7
A zde je další dotaz s rowid nahrazeno DogId sloupec:
SELECT * FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
); Výsledek:
| DOGID | FIRSTNAME | LASTNAME |
|---|---|---|
| 2 | Kůra | Smith |
| 6 | Wag | Johnson |
| 7 | Wag | Johnson |
Možnost 8
Dalším způsobem, jak najít duplikáty, je použít ROW_NUMBER() funkce okna:
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs; Výsledek:
| DOGID | FIRSTNAME | LASTNAME | ROW_NUM |
|---|---|---|---|
| 1 | Kůra | Smith | 1 |
| 2 | Kůra | Smith | 2 |
| 4 | Ruff | Robinson | 1 |
| 7 | Wag | Johnson | 1 |
| 5 | Wag | Johnson | 2 |
| 6 | Wag | Johnson | 3 |
| 3 | Fuj | 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 vidíme každý duplicitní řádek, včetně sloupce s jedinečným identifikátorem.
Možnost 9
Předchozí příklad můžeme také použít jako běžný tabulkový výraz ve větším dotazu:
WITH cte AS
(
SELECT
DogId,
FirstName,
LastName,
ROW_NUMBER() OVER (
PARTITION BY FirstName, LastName
ORDER BY FirstName, LastName
) AS row_num
FROM Dogs
)
SELECT * FROM cte WHERE row_num <> 1; Výsledek:
| DOGID | FIRSTNAME | LASTNAME | ROW_NUM |
|---|---|---|---|
| 2 | Kůra | Smith | 2 |
| 5 | Wag | Johnson | 2 |
| 6 | Wag | Johnson | 3 |
Tento dotaz vyloučí z výstupu neduplikáty a z výstupu vyloučí jeden řádek každého duplikátu.
Možnost 10
Zde je další 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
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
); Výsledek:
| DOGID | FIRSTNAME | LASTNAME |
|---|---|---|
| 2 | Kůra | Smith |
| 6 | Wag | Johnson |
| 7 | Wag | Johnson |
Tento příklad používá MINUS společnosti Oracle operátor, který vrací pouze jedinečné řádky vrácené prvním dotazem, ale ne druhým.
MINUS operátor je podobný EXCEPT operátor v jiných DBMS, jako je SQL Server, MariaDB, PostgreSQL a SQLite.
Možnost 11
Zde je další možnost výběru duplikátů z naší tabulky:
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 | Kůra | Smith | 1 | Kůra | Smith |
| 7 | Wag | Johnson | 5 | Wag | Johnson |
| 7 | Wag | Johnson | 6 | Wag | Johnson |