Los siguientes ejemplos devuelven filas duplicadas de una tabla de Oracle Database.
Datos de muestra
Supongamos que tenemos una tabla con los siguientes datos:
SELECT * FROM Pets;
Resultado:
PetId PetName PetType ----- ------- ------- 1 Wag Dog 1 Wag Dog 2 Scratch Cat 3 Tweet Bird 4 Bark Dog 4 Bark Dog 4 Bark Dog
Las dos primeras filas son duplicados, al igual que las últimas tres filas. En este caso, las filas duplicadas contienen valores duplicados en todas las columnas, incluida la columna ID.
Opción 1
Podemos usar la siguiente consulta para ver cuántas filas están duplicadas:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY PetId;
Resultado:
PETID PETNAME PETTYPE Count 1 Wag Dog 2 2 Scratch Cat 1 3 Tweet Bird 1 4 Bark Dog 3
Agrupamos las filas por todas las columnas y devolvimos el recuento de filas de cada grupo. Cualquier fila con un recuento superior a 1 es un duplicado.
Podemos ordenarlo por conteo en orden descendente, de modo que las filas con más duplicados aparezcan primero:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
ORDER BY Count(*) DESC;
Resultado:
PETID PETNAME PETTYPE Count 4 Bark Dog 3 1 Wag Dog 2 2 Scratch Cat 1 3 Tweet Bird 1
Opción 2
Si solo queremos que se enumeren las filas duplicadas, podemos usar HAVING
cláusula para devolver solo filas con un recuento mayor que 1:
SELECT
PetId,
PetName,
PetType,
COUNT(*) AS "Count"
FROM Pets
GROUP BY
PetId,
PetName,
PetType
HAVING COUNT(*) > 1
ORDER BY COUNT(*) DESC;
Resultado:
PETID PETNAME PETTYPE Count 4 Bark Dog 3 1 Wag Dog 2
Opción 3
Otra opción es usar el ROW_NUMBER()
función de ventana:
SELECT
PetId,
PetName,
PetType,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS rn
FROM Pets;
Resultado:
PETID PETNAME PETTYPE RN 1 Wag Dog 1 1 Wag Dog 2 2 Scratch Cat 1 3 Tweet Bird 1 4 Bark Dog 1 4 Bark Dog 2 4 Bark Dog 3
La PARTITION BY
cláusula divide el conjunto de resultados producido por FROM
cláusula en particiones a las que se aplica la función. Cuando especificamos particiones para el conjunto de resultados, cada partición hace que la numeración comience de nuevo (es decir, la numeración comenzará en 1 para la primera fila de cada partición).
Opción 4
Podemos usar la consulta anterior como una expresión de tabla común:
WITH cte AS
(
SELECT
PetId,
PetName,
PetType,
ROW_NUMBER() OVER (
PARTITION BY PetId, PetName, PetType
ORDER BY PetId, PetName, PetType
) AS Row_Number
FROM Pets
)
SELECT * FROM cte WHERE Row_Number <> 1;
Resultado:
PETID PETNAME PETTYPE ROW_NUMBER 1 Wag Dog 2 4 Bark Dog 2 4 Bark Dog 3
Esto devuelve solo el exceso de filas de los duplicados coincidentes. Entonces, si hay dos filas idénticas, devuelve una de ellas. Si hay tres filas idénticas, devuelve dos, y así sucesivamente.
Opción 5
Dado que nuestra tabla no contiene una columna de clave principal, podemos aprovechar el rowid
de Oracle pseudocolumna:
SELECT * FROM Pets
WHERE EXISTS (
SELECT 1 FROM Pets p2
WHERE Pets.PetName = p2.PetName
AND Pets.PetType = p2.PetType
AND Pets.rowid > p2.rowid
);
Resultado:
PETID PETNAME PETTYPE 1 Wag Dog 4 Bark Dog 4 Bark Dog
La forma en que esto funciona es que cada fila en una base de datos 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. Sin embargo, es importante tener en cuenta que las filas en diferentes tablas que se almacenan juntas en el mismo clúster pueden tener el mismo rowid
.
Un beneficio del ejemplo anterior es que podemos reemplazar SELECT *
con DELETE
para deduplicar la tabla.
Opción 6
Y finalmente, aquí hay otra opción que usa el rowid
pseudocolumna:
SELECT * FROM Pets
WHERE rowid > (
SELECT MIN(rowid) FROM Pets p2
WHERE Pets.PetName = p2.PetName
AND Pets.PetType = p2.PetType
);
Resultado:
PETID PETNAME PETTYPE 1 Wag Dog 4 Bark Dog 4 Bark Dog
Mismo resultado que el ejemplo anterior.
Como en el ejemplo anterior, podemos reemplazar SELECT *
con DELETE
para eliminar filas duplicadas de la tabla.