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

11 начина за намиране на дублиращи се редове, които имат първичен ключ в Oracle

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

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

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

SELECT * FROM Dogs;

Резултат:

ДОГИД FIRSTNAME ФАМИЛИЯ
1 Кора Смит
2 Кора Смит
3 Уф Джоунс
4 Ръф Робинзон
5 Размахване Джонсън
6 Размахване Джонсън
7 Размахване Джонсън

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

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

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

Опция 1

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

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

Резултат:

FIRSTNAME LASTNAME COUNT
Размахване Джонсън 3
Кора Смит 2
Ръф Робинзон 1
Уф Джоунс 1

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

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

Опция 2

Можем да добавим HAVING клауза към предишния ни пример за изключване на недублирани от изхода:

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

Резултат:

FIRSTNAME LASTNAME COUNT
Размахване Джонсън 3
Кора Смит 2

Опция 3

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

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

Резултат:

ИМЕ НА КУЧЕ COUNT
Уаг Джонсън 3
Барк Смит 2
Ръф Робинсън 1
Уау Джоунс 1

Опция 4

Всеки ред в Oracle има rowid псевдоколона, която връща адреса на реда. rowid е уникален идентификатор за редове в таблицата и обикновено неговата стойност уникално идентифицира ред в базата данни (въпреки че е важно да се отбележи, че редовете в различни таблици, които се съхраняват заедно в един и същ клъстер, могат да имат един и същ rowid ).

Както и да е, можем да изградим заявка, която използва rowid ако искаме:

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

Резултат:

ДОГИД FIRSTNAME LASTNAME
2 Кора Смит
6 Размахване Джонсън
7 Размахване Джонсън

Бихме могли да заменим SELECT * с DELETE за извършване на операция за премахване на дупки на масата.

Имайте предвид, че можехме да използваме DogId колона (нашия първичен ключ) вместо rowid ако искахме. Това каза, rowid може да бъде полезно, ако по някаква причина не можете да използвате колоната с първичен ключ или ако таблицата няма първичен ключ.

Опция 5

Ето още една заявка, която използва rowid :

SELECT * FROM Dogs
WHERE rowid > (
  SELECT MIN(rowid) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Резултат:

ДОГИД FIRSTNAME LASTNAME
2 Кора Смит
6 Размахване Джонсън
7 Размахване Джонсън

Както в предишния пример, бихме могли да заменим SELECT * с DELETE за да изтриете дублиращите се редове.

Опция 6

Двата rowid опциите по-горе са страхотни, ако трябва напълно да игнорирате първичния ключ във вашата заявка (или ако изобщо нямате колона с първичен ключ). Въпреки това, както споменахме, все още има опция за замяна на rowid с колоната с първичен ключ – в нашия случай DogId колона:

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

Резултат:

ДОГИД FIRSTNAME LASTNAME
2 Кора Смит
6 Размахване Джонсън
7 Размахване Джонсън

Опция 7

А ето и другата заявка с rowid заменен от DogId колона:

SELECT * FROM Dogs
WHERE DogId > (
  SELECT MIN(DogId) FROM Dogs d2  
  WHERE Dogs.FirstName = d2.FirstName
  AND Dogs.LastName = d2.LastName
);

Резултат:

ДОГИД FIRSTNAME LASTNAME
2 Кора Смит
6 Размахване Джонсън
7 Размахване Джонсън

Опция 8

Друг начин за намиране на дубликати е да използвате ROW_NUMBER() функция на прозореца:

SELECT 
    DogId,
    FirstName,
    LastName,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS row_num
FROM Dogs;

Резултат:

ДОГИД FIRSTNAME ФАМИЛИЯ ROW_NUM
1 Кора Смит 1
2 Кора Смит 2
4 Ръф Робинзон 1
7 Размахване Джонсън 1
5 Размахване Джонсън 2
6 Размахване Джонсън 3
3 Уф Джоунс 1

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

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

Опция 9

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

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;

Резултат:

ДОГИД FIRSTNAME LASTNAME ROW_NUM
2 Кора Смит 2
5 Размахване Джонсън 2
6 Размахване Джонсън 3

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

Опция 10

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

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

Резултат:

ДОГИД FIRSTNAME ФАМИЛИЯ
2 Кора Смит
6 Размахване Джонсън
7 Размахване Джонсън

Този пример използва MINUS на Oracle оператор, който връща само уникални редове, върнати от първата заявка, но не и от втората.

MINUS операторът е подобен на EXCEPT оператор в други СУБД, като SQL Server, MariaDB, PostgreSQL и SQLite.

Опция 11

Ето още една опция за избор на дубликати от нашата таблица:

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

Резултат:

ДОГИД FIRSTNAME LASTNAME КУЧЕ FIRSTNAME LASTNAME
2 Кора Смит 1 Кора Смит
7 Размахване Джонсън 5 Размахване Джонсън
7 Размахване Джонсън 6 Размахване Джонсън

  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Как да приложите пакетно извличане с Fluent NHibernate, когато работите с Oracle?

  2. Как да създадете спул файл на sql sql

  3. 12c Автоматично попълване на колона със стойност на последователността

  4. Примери за синтаксис за присъединяване на oracle

  5. Каква е минималната настройка, необходима за разгръщане на .NET приложение с Oracle клиент 11?