sql >> Base de Datos >  >> RDS >> Oracle

11 formas de encontrar filas duplicadas que tienen una clave principal en Oracle

Aquí hay once opciones para devolver filas duplicadas en Oracle Database cuando esas filas tienen una clave principal o alguna otra columna de identificador único y desea ignorarlo.

Datos de muestra

Usaremos los siguientes datos para nuestros ejemplos:

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

Las primeras dos filas son duplicados y las últimas tres filas son duplicados. Las filas duplicadas comparten exactamente los mismos valores en todas las columnas con la excepción de su clave principal/columna de ID única.

La columna de clave principal garantiza que no haya filas duplicadas, lo cual es una buena práctica en RDBMS, porque las claves principales ayudan a reforzar la integridad de los datos. Pero el hecho de que las claves primarias contengan valores únicos significa que debemos ignorar esa columna al buscar duplicados.

En nuestra tabla anterior, la columna de clave principal es un número creciente, y su valor no tiene ningún significado y no es significativo. Por lo tanto, podemos ignorar los datos de esa columna cuando buscamos duplicados.

Opción 1

Esta es nuestra primera opción para devolver duplicados:

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

Resultado:

NOMBRE APELLIDO CONTAR
Meneo Johnson 3
Ladrar Smith 2
Ruff Robinson 1
Guau Jones 1

Aquí construimos nuestra consulta con GROUP BY cláusula para que la salida se agrupe por las columnas relevantes. También usamos el COUNT() función para devolver el número de filas idénticas. Y lo ordenamos por conteo en orden descendente para que los duplicados aparezcan primero.

El resultado nos dice que hay tres filas que contienen a Wag Johnson y dos filas que contienen a Bark Smith. Estos son duplicados (o triplicados en el caso de Wag Johnson). Las otras dos filas no tienen duplicados.

Opción 2

Podemos agregar el HAVING cláusula a nuestro ejemplo anterior para excluir no duplicados de la salida:

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

Resultado:

NOMBRE APELLIDO CONTAR
Meneo Johnson 3
Ladrar Smith 2

Opción 3

También podemos buscar duplicados en columnas concatenadas. En este caso usamos el DISTINCT palabra clave para obtener valores distintos, luego use COUNT() función para devolver el conteo:

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

Resultado:

NOMBRE DE PERRO CONTAR
Wag Johnson 3
Herrero de ladridos 2
Ruff Robinson 1
Guau Jones 1

Opción 4

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

De todos modos, podemos construir una consulta que use el rowid si queremos:

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

Resultado:

DOGID NOMBRE APELLIDO
2 Ladrar Smith
6 Meneo Johnson
7 Meneo Johnson

Podríamos reemplazar el SELECT * con DELETE para realizar una operación de eliminación de duplicados en la tabla.

Tenga en cuenta que podríamos haber usado el DogId columna (nuestra clave principal) en lugar de rowid si quisiéramos. Dicho esto, 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.

Opción 5

Aquí hay otra consulta que usa el rowid :

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

Resultado:

DOGID NOMBRE APELLIDO
2 Ladrar Smith
6 Meneo Johnson
7 Meneo Johnson

Al igual que en el ejemplo anterior, podríamos reemplazar el SELECT * con DELETE para eliminar las filas duplicadas.

Opción 6

Los dos rowid Las opciones anteriores son excelentes si debe ignorar por completo la clave principal en su consulta (o si no tiene una columna de clave principal). Sin embargo, como se mencionó, todavía existe la opción de reemplazar rowid con la columna de la clave principal, en nuestro caso, el DogId columna:

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

Resultado:

DOGID NOMBRE APELLIDO
2 Ladrar Smith
6 Meneo Johnson
7 Meneo Johnson

Opción 7

Y aquí está la otra consulta con rowid reemplazado por el DogId columna:

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

Resultado:

DOGID NOMBRE APELLIDO
2 Ladrar Smith
6 Meneo Johnson
7 Meneo Johnson

Opción 8

Otra forma de encontrar duplicados es usar ROW_NUMBER() función de ventana:

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

Resultado:

DOGID NOMBRE APELLIDO ROW_NUM
1 Ladrar Smith 1
2 Ladrar Smith 2
4 Ruff Robinson 1
7 Meneo Johnson 1
5 Meneo Johnson 2
6 Meneo Johnson 3
3 Guau Jones 1

Usando la PARTITION La cláusula da como resultado que se agregue una nueva columna, con un número de fila que aumenta cada vez que hay un duplicado, pero se restablece nuevamente cuando hay una fila única.

En este caso, no agrupamos los resultados, lo que significa que podemos ver cada fila duplicada, incluida su columna de identificador único.

Opción 9

También podemos usar el ejemplo anterior como una expresión de tabla común en una consulta más grande:

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;

Resultado:

DOGID NOMBRE APELLIDO ROW_NUM
2 Ladrar Smith 2
5 Meneo Johnson 2
6 Meneo Johnson 3

Esa consulta excluye los no duplicados de la salida y excluye una fila de cada duplicado de la salida.

Opción 10

Aquí hay otra forma de obtener el mismo resultado que el ejemplo anterior:

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

Resultado:

DOGID NOMBRE APELLIDO
2 Ladrar Smith
6 Meneo Johnson
7 Meneo Johnson

Este ejemplo utiliza MINUS de Oracle operador, que devuelve solo filas únicas devueltas por la primera consulta pero no por la segunda.

El MINUS El operador es similar al EXCEPT operador en otros DBMS, como SQL Server, MariaDB, PostgreSQL y SQLite.

Opción 11

Aquí hay otra opción para seleccionar duplicados de nuestra tabla:

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

Resultado:

DOGID NOMBRE APELLIDO DOGID NOMBRE APELLIDO
2 Ladrar Smith 1 Ladrar Smith
7 Meneo Johnson 5 Meneo Johnson
7 Meneo Johnson 6 Meneo Johnson