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

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

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

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

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

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

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

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

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

Резултат:

 firstname | lastname | count 
-----------+----------+-------
 Ruff      | Robinson |     1
 Wag       | Johnson  |     3
 Woof      | Jones    |     1
 Bark      | Smith    |     2

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

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

Опция 2

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

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

Резултат:

 firstname | lastname | count 
-----------+----------+-------
 Wag       | Johnson  |     3
 Bark      | Smith    |     2

Опция 3

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

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

Резултат:

    dogname    | count 
---------------+-------
 Wag Johnson   |     3
 Ruff Robinson |     1
 Woof Jones    |     1
 Bark Smith    |     2

Опция 4

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

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

Резултат:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     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

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

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

Опция 5

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

WITH cte AS 
    (
        SELECT 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Резултат:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     2 | Bark      | Smith    |          2
     6 | Wag       | Johnson  |          2
     7 | Wag       | Johnson  |          3

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

Опция 6

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

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

Резултат:

 dogid | firstname | lastname 
-------+-----------+----------
     6 | Wag       | Johnson
     2 | Bark      | Smith
     7 | Wag       | Johnson

Една разлика между този пример и предишния е, че този пример не изисква генериране на собствен отделен номер на ред.

Опция 7

Ето още една опция за връщане на дублиращи се редове в Postgres:

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. PostgreSQL връща функция с персонализиран тип данни

  2. SQL изберете елементи, където сумата на полето е по-малка от N

  3. `pg_tblspc` липсва след инсталиране на най-новата версия на OS X (Yosemite или El Capitan)

  4. ECONNREFUSED за Postgres на nodeJS с докери

  5. Ред на PostgreSQL array_agg