sql >> Databáze >  >> RDS >> Oracle

11 způsobů, jak najít duplicitní řádky, které mají primární klíč v Oracle

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

  1. Najděte verzi/záplaty serveru Weblogic v EBS R12.2/ Standalone Weblogic

  2. Jakou verzi PostgreSQL používám?

  3. Jak vypočítat kumulativní součet v MySQL

  4. Doktrína 2 a tabulka odkazů Many-to-many s dalším polem