Ето някои опции за изтриване на дублиращи се редове от таблица в Oracle Database, когато тези редове имат първичен ключ или колона с уникален идентификатор.
В такива случаи първичният ключ трябва да се игнорира при сравняване на дублиращи се редове (поради факта, че първичните ключове съдържат уникални стойности).
Примерни данни
Нашите примери използват следните данни:
SELECT * FROM Dogs;
Резултат:
ДОГИД | FIRSTNAME | LASTNAME |
---|---|---|
1 | Кора | Смит |
2 | Кора | Смит |
3 | Уф | Джоунс |
4 | Ръф | Робинзон |
5 | Размахване | Джонсън |
6 | Размахване | Джонсън |
7 | Размахване | Джонсън |
Можем да видим, че първите два реда са дублирани, както и последните три реда.
DogId
колоната съдържа уникални стойности (тъй като това е първичен ключ на таблицата), но ние игнорираме тази колона, когато сравняваме дубликати. Често може да се окаже, че се налага да премахнете дублирането на таблици, които съдържат първични ключове, така че следните примери могат да се използват за това.
Опция 1
Ето първата ни опция за премахване на дубликата на горната таблица:
DELETE FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
SELECT * FROM Dogs;
Резултат:
ДОГИД | FIRSTNAME | LASTNAME |
---|---|---|
1 | Кора | Смит |
3 | Уф | Джоунс |
4 | Ръф | Робинзон |
5 | Размахване | Джонсън |
Дубликатите са премахнати (но остава един ред от всеки дубликат).
Като алтернатива можем да използваме MAX()
функция вместо MIN()
функция за промяна на кои редове се изтриват.
Опция 2
В този пример (и следващите примери) ще приемем, че таблицата е възстановена в първоначалното си състояние (с дубликатите).
Ето още един пример, който премахва дублирането на таблицата и след това избира останалите редове:
DELETE FROM Dogs WHERE DogId IN (
SELECT d2.DogId
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
)
);
SELECT * FROM Dogs;
Резултат:
ДОГИД | FIRSTNAME | LASTNAME |
---|---|---|
2 | Кора | Смит |
3 | Уф | Джоунс |
4 | Ръф | Робинзон |
7 | Размахване | Джонсън |
Забележете, че използвах MAX()
функция вместо MIN()
който използвах в предишния пример. Можем да видим влиянието, което това оказва върху операцията за премахване на дуппинга. Той изтри различни редове от таблицата.
Опция 3
Ето опция, която не изисква използването на MIN()
или MAX()
:
DELETE FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.DogId > d2.DogId
);
SELECT * FROM Dogs;
Резултат:
ДОГИД | FIRSTNAME | LASTNAME |
---|---|---|
1 | Кора | Смит |
3 | Уф | Джоунс |
4 | Ръф | Робинзон |
5 | Размахване | Джонсън |
Опция 4
Ето още една опция:
DELETE FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
SELECT * FROM Dogs;
Резултат:
ДОГИД | FIRSTNAME | LASTNAME |
---|---|---|
1 | Кора | Смит |
3 | Уф | Джоунс |
4 | Ръф | Робинзон |
5 | Размахване | Джонсън |
Опция 5
Всеки ред в Oracle има rowid
псевдоколона, която връща адреса на реда. rowid
е уникален идентификатор за редове в таблицата и обикновено неговата стойност уникално идентифицира ред в базата данни (въпреки че е важно да се отбележи, че редовете в различни таблици, които се съхраняват заедно в един и същ клъстер, могат да имат един и същ rowidкод> ).
Следователно можем да използваме rowid
в нашата заявка вместо DogId
колона:
DELETE FROM Dogs
WHERE EXISTS (
SELECT 1 FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
AND Dogs.rowid > d2.rowid
);
SELECT * FROM Dogs;
Резултат:
ДОГИД | FIRSTNAME | LASTNAME |
---|---|---|
1 | Кора | Смит |
3 | Уф | Джоунс |
4 | Ръф | Робинзон |
5 | Размахване | Джонсън |
Въпреки че този пример може да изглежда малко излишен, като се има предвид, че вече имаме колона с първичен ключ, може да има случаи, в които предпочитате да използвате rowid
. rowid
може да бъде полезно, ако по някаква причина не можете да използвате колоната с първичен ключ или ако таблицата няма първичен ключ. Освен това в документацията на Oracle се споменава, че rowid
стойностите са най-бързият начин за достъп до един ред.
Опция 6
И ето другия пример, но с rowid
вместо първичния ключ:
DELETE FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
SELECT * FROM Dogs;
Резултат:
ДОГИД | FIRSTNAME | LASTNAME |
---|---|---|
1 | Кора | Смит |
3 | Уф | Джоунс |
4 | Ръф | Робинзон |
5 | Размахване | Джонсън |