Mysql
 sql >> база данни >  >> RDS >> Mysql

7 начина за намиране на дублиращи се редове, докато игнорирате първичния ключ в MySQL

Ето седем начина за връщане на дублиращи се редове в MySQL, когато тези редове имат първичен ключ или друга колона с уникален идентификатор.

Примерни данни

Ще използваме следните данни за нашите примери:

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;

Резултат:

+-------+-----------+----------+
| DogId | FirstName | LastName |
+-------+-----------+----------+
|     1 | Bark      | Smith    |
|     2 | Bark      | Smith    |
|     3 | Woof      | Jones    |
|     4 | Ruff      | Robinson |
|     5 | Wag       | Johnson  |
|     6 | Wag       | Johnson  |
|     7 | Wag       | Johnson  |
+-------+-----------+----------+

Дублираните редове споделят абсолютно еднакви стойности във всички колони, с изключение на колоната с първичен ключ/уникален идентификатор.

Първите два реда са дублирани (с изключение на DogId колона, която е първичен ключ на таблицата и съдържа уникална стойност във всички редове). Последните три реда също са дублирани (с изключение на DogId колона).

Колоната с първичен ключ гарантира, че няма дублиращи се редове, което обикновено е добро нещо в RDBMS. По дефиниция обаче това означава, че няма дубликати. В нашия случай колоната с първичен ключ е нарастващо число и стойността му няма значение и не е значима. Следователно трябва да игнорираме този ред, ако искаме да намерим дубликати в колоните, които са значителен.

Опция 1

Първата ни опция е да използваме GROUP BY клауза, за да групирате колоните по значимите им колони, след което използвайте COUNT() функция за връщане на броя на еднакви редове:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName;

Резултат:

+-----------+----------+-------+
| FirstName | LastName | Count |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Woof      | Jones    |     1 |
| Ruff      | Robinson |     1 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Успяхме да игнорираме колоната с първичен ключ, като я пропуснахме от нашата заявка.

Резултатът ни казва, че има два реда, съдържащи Барк Смит и три реда, съдържащи Уаг Джонсън. Това са дубликати (или три екземпляра в случая на Уаг Джонсън). Другите два реда нямат дубликати.

Опция 2

Можем да изключим недубликатите от изхода с HAVING клауза:

SELECT 
    FirstName, 
    LastName, 
    COUNT(*) AS Count
FROM Dogs
GROUP BY FirstName, LastName
HAVING COUNT(*) > 1;

Резултат:

+-----------+----------+-------+
| FirstName | LastName | Count |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Опция 3

Можем също да проверим за дубликати на свързани колони. Например, можем да използваме CONCAT() функция за свързване на нашите две колони, използвайте DISTINCT ключова дума, за да получите различни стойности, след това използвайте COUNT() функция за връщане на броя:

SELECT
    DISTINCT CONCAT(FirstName, ' ', LastName) AS DogName,
    COUNT(*) AS Count
FROM Dogs
GROUP BY CONCAT(FirstName, ' ', LastName);

Резултат:

+---------------+-------+
| DogName       | Count |
+---------------+-------+
| Bark Smith    |     2 |
| Woof Jones    |     1 |
| Ruff Robinson |     1 |
| Wag Johnson   |     3 |
+---------------+-------+

Опция 4

Като алтернатива можем да използваме ROW_NUMBER() функция с PARTITION BY клауза:

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

Резултат:

+-------+-----------+----------+----+
| 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 |
+-------+-----------+----------+----+

Това създава нова колона с номер на ред, който се увеличава всеки път, когато има дубликат, но се нулира отново, когато има уникален ред

Тази техника осигурява възможна полза, тъй като не е необходимо да групираме резултатите. Това означава, че можем да видим всеки дублиран ред, включително неговата колона с уникален идентификатор.

Опция 5

Можем да използваме предишния пример като общ табличен израз в по-голяма заявка:

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;

Резултат:

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

Тази техника изключва недубликатите от изхода и изключва един ред от всеки дубликат от изхода.

Тази заявка може да се използва като предшественик на операция за премахване на дупиране. Може да ни покаже какво ще бъде изтрито, ако решим да изтрием дубликати. За да премахнем фалшифицирането на таблицата, всичко, което трябва да направим, е да заменим последния SELECT * с DELETE .

Опция 6

Ето по-сбит начин да получите същия изход като предишния пример:

SELECT * FROM Dogs 
WHERE DogId IN (
    SELECT DogId FROM Dogs 
    WHERE DogId NOT IN (SELECT MIN(DogId) FROM Dogs
    GROUP BY FirstName, LastName)
    );

Резултат:

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

Тази техника не изисква от нас да генерираме отделен номер на ред с ROW_NUMBER() като в предишния пример.

Можем също да заменим SELECT * с DELETE за да изтриете дубликатите.

Опция 7

И накрая, ето още една опция за връщане на дубликати:

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
);

Резултат:

+-------+-----------+----------+-------+-----------+----------+
| 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. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Изключете предупрежденията и грешките в PHP и MySQL

  2. SQL ключове, MUL срещу PRI срещу UNI

  3. Как бързо да преименувам MySQL база данни (промяна на името на схемата)?

  4. Настройки на множество центрове за данни с помощта на Galera Cluster за MySQL или MariaDB

  5. 4 начина за намиране на дублиращи се редове в MySQL