sql >> Databáze >  >> RDS >> Mysql

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

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

Ukázková data

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

DROP TABLE IF EXISTS Dogs;
CREATE TABLE Dogs (
    DogId int PRIMARY KEY NOT NULL,
    FirstName varchar(50),
    LastName varchar(50)
    );

INSERT INTO Dogs VALUES
    (1, 'Bark', 'Smith'),
    (2, 'Bark', 'Smith'),
    (3, 'Woof', 'Jones'),
    (4, 'Ruff', 'Robinson'),
    (5, 'Wag', 'Johnson'),
    (6, 'Wag', 'Johnson'),
    (7, 'Wag', 'Johnson');
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  |
+-------+-----------+----------+

Duplicitní řádky sdílejí přesně stejné hodnoty ve všech sloupcích kromě sloupce primárního klíče/jedinečného ID.

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 obvykle dobrá věc v RDBMS. Z definice to však znamená, že neexistují žádné duplikáty. V našem případě je sloupec primárního klíče inkrementální číslo a jeho hodnota nemá žádný význam a není významná. Pokud tedy chceme najít duplikáty ve sloupcích, které jsou, musíme tento řádek ignorovat významný.

Možnost 1

Naší první možností je použít 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 |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Woof      | Jones    |     1 |
| Ruff      | Robinson |     1 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Podařilo se nám ignorovat sloupec primárního klíče tím, že jsme jej vynechali v našem dotazu.

Výsledek nám říká, že existují dva řádky obsahující Bark Smith a tři řádky obsahující Wag Johnson. 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 |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Možnost 3

Můžeme také zkontrolovat duplikáty na zřetězených sloupcích. Můžeme například použít 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 |
+---------------+-------+
| Bark Smith    |     2 |
| Woof Jones    |     1 |
| Ruff Robinson |     1 |
| Wag Johnson   |     3 |
+---------------+-------+

Možnost 4

Alternativně můžeme použít ROW_NUMBER() pomocí funkce PARTITION BY klauzule:

SELECT 
    *,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS rn
FROM Dogs;

Výsledek:

+-------+-----------+----------+----+
| DogId | FirstName | LastName | rn |
+-------+-----------+----------+----+
|     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 |
+-------+-----------+----------+----+

Tím se vytvoří nový sloupec s číslem řádku, které se zvýší pokaždé, když existuje duplikát, ale znovu se resetuje, když existuje jedinečný řádek

Tato technika poskytuje možnou výhodu v tom, že nepotřebujeme seskupovat výsledky. To 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 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 rn
        FROM Dogs
    )
SELECT * FROM cte WHERE rn <> 1;

Výsledek:

+-------+-----------+----------+----+
| DogId | FirstName | LastName | rn |
+-------+-----------+----------+----+
|     2 | Bark      | Smith    |  2 |
|     6 | Wag       | Johnson  |  2 |
|     7 | Wag       | Johnson  |  3 |
+-------+-----------+----------+----+

Tato technika vylučuje neduplikáty z výstupu a vylučuje jeden řádek každého duplikátu z výstupu.

Tento dotaz lze použít jako předchůdce operace odstranění duplikací. Může nám ukázat, co bude smazáno, pokud se rozhodneme smazat duplikáty. K odstranění duplicit v tabulce stačí nahradit poslední SELECT * pomocí DELETE .

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 
    WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
    GROUP BY FirstName, LastName)
    );

Výsledek:

+-------+-----------+----------+
| DogId | FirstName | LastName |
+-------+-----------+----------+
|     2 | Bark      | Smith    |
|     6 | Wag       | Johnson  |
|     7 | Wag       | Johnson  |
+-------+-----------+----------+

Tato technika nevyžaduje, abychom generovali samostatné číslo řádku pomocí ROW_NUMBER() jako v předchozím příkladu.

Můžeme také nahradit SELECT * pomocí DELETE k odstranění duplikátů.

Možnost 7

A nakonec je tu ještě jedna možnost, jak vrátit duplikáty:

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. Funkce hodnocení v SQL Server

  2. Jak vytvořit neomezenou úroveň menu přes PHP a mysql

  3. Převeďte jeden řádek na více řádků s méně sloupci

  4. Nelze se připojit k serveru PostgreSQL:nelze se připojit k serveru:Oprávnění odepřeno