Aquí hay algunas opciones para eliminar filas duplicadas de una tabla en Oracle Database cuando esas filas tienen una clave principal o una columna de identificador único.
En tales casos, la clave principal debe ignorarse al comparar filas duplicadas (debido al hecho de que las claves principales contienen valores únicos).
Datos de muestra
Nuestros ejemplos utilizan los siguientes datos:
SELECT * FROM Dogs;
Resultado:
DOGID | NOMBRE | APELLIDO |
---|---|---|
1 | Ladrar | Smith |
2 | Ladrar | Smith |
3 | Guau | Jones |
4 | Ruff | Robinson |
5 | Meneo | Johnson |
6 | Meneo | Johnson |
7 | Meneo | Johnson |
Podemos ver que las dos primeras filas están duplicadas, al igual que las últimas tres filas.
El DogId
columna contiene valores únicos (porque es la clave principal de la tabla), pero estamos ignorando esa columna al comparar duplicados. Es posible que a menudo necesite desduplicar tablas que contienen claves principales, por lo que los siguientes ejemplos se pueden usar para hacer precisamente eso.
Opción 1
Esta es nuestra primera opción para deduplicar la tabla anterior:
DELETE FROM Dogs
WHERE DogId IN (
SELECT DogId FROM Dogs
MINUS SELECT MIN(DogId) FROM Dogs
GROUP BY FirstName, LastName
);
SELECT * FROM Dogs;
Resultado:
DOGID | NOMBRE | APELLIDO |
---|---|---|
1 | Ladrar | Smith |
3 | Guau | Jones |
4 | Ruff | Robinson |
5 | Meneo | Johnson |
Los duplicados se han eliminado (pero queda una fila de cada duplicado).
Alternativamente, podemos usar el MAX()
función en lugar de MIN()
función para cambiar qué filas se eliminan.
Opción 2
En este ejemplo (y los siguientes ejemplos) asumiremos que la tabla ha sido restaurada a su estado original (con los duplicados).
Aquí hay otro ejemplo que elimina los duplicados de la tabla y luego selecciona las filas restantes:
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;
Resultado:
DOGID | NOMBRE | APELLIDO |
---|---|---|
2 | Ladrar | Smith |
3 | Guau | Jones |
4 | Ruff | Robinson |
7 | Meneo | Johnson |
Note que usé el MAX()
función en lugar de MIN()
que usé en el ejemplo anterior. Podemos ver el efecto que esto tiene en la operación de eliminación de duplicados. Eliminó diferentes filas de la tabla.
Opción 3
Aquí hay una opción que no requiere el uso de MIN()
o 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;
Resultado:
DOGID | NOMBRE | APELLIDO |
---|---|---|
1 | Ladrar | Smith |
3 | Guau | Jones |
4 | Ruff | Robinson |
5 | Meneo | Johnson |
Opción 4
Aquí hay otra opción:
DELETE FROM Dogs
WHERE DogId > (
SELECT MIN(DogId) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
SELECT * FROM Dogs;
Resultado:
DOGID | NOMBRE | APELLIDO |
---|---|---|
1 | Ladrar | Smith |
3 | Guau | Jones |
4 | Ruff | Robinson |
5 | Meneo | Johnson |
Opción 5
Cada fila en Oracle tiene un rowid
pseudocolumna que devuelve la dirección de la fila. El rowid
es un identificador único para las filas de la tabla y, por lo general, su valor identifica de forma única una fila en la base de datos (aunque es importante tener en cuenta que las filas de diferentes tablas que se almacenan juntas en el mismo clúster pueden tener el mismo rowid
).
Por lo tanto, podemos usar el rowid
en nuestra consulta en lugar del DogId
columna:
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;
Resultado:
DOGID | NOMBRE | APELLIDO |
---|---|---|
1 | Ladrar | Smith |
3 | Guau | Jones |
4 | Ruff | Robinson |
5 | Meneo | Johnson |
Si bien este ejemplo puede parecer un poco superfluo, dado que ya tenemos una columna de clave principal, puede haber instancias en las que prefiera usar el rowid
. El rowid
puede ser útil si no puede usar la columna de clave principal por algún motivo, o si la tabla no tiene una clave principal. Además, la documentación de Oracle menciona que rowid
los valores son la forma más rápida de acceder a una sola fila.
Opción 6
Y aquí está el otro ejemplo, pero con rowid
en lugar de la clave principal:
DELETE FROM Dogs
WHERE rowid > (
SELECT MIN(rowid) FROM Dogs d2
WHERE Dogs.FirstName = d2.FirstName
AND Dogs.LastName = d2.LastName
);
SELECT * FROM Dogs;
Resultado:
DOGID | NOMBRE | APELLIDO |
---|---|---|
1 | Ladrar | Smith |
3 | Guau | Jones |
4 | Ruff | Robinson |
5 | Meneo | Johnson |