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 |