sql >> Base de Datos >  >> RDS >> PostgreSQL

7 formas de encontrar filas duplicadas en PostgreSQL ignorando la clave principal

Aquí hay siete formas de devolver filas duplicadas en PostgreSQL cuando esas filas tienen una clave principal u otra columna de identificador único.

Esto significa que las filas duplicadas comparten exactamente los mismos valores en todas las columnas con la excepción de su clave principal/columna de ID única.

Datos de muestra

Usaremos los siguientes datos para nuestros ejemplos:

SELECT * FROM Dogs;

Resultado:

 dogid | firstname | lastname 
-------+-----------+----------
     1 | Bark      | Smith
     2 | Bark      | Smith
     3 | Woof      | Jones
     4 | Ruff      | Robinson
     5 | Wag       | Johnson
     6 | Wag       | Johnson
     7 | Wag       | Johnson

Las dos primeras filas son duplicados (excepto el DogId columna, que es la clave principal de la tabla y contiene un valor único en todas las filas). Las últimas tres filas también son duplicados (excepto el DogId columna).

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 debido a que las claves principales evitan filas duplicadas, tienen el potencial de interferir con nuestra capacidad para encontrar 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, debemos ignorar esa fila si queremos encontrar duplicados en las otras columnas.

Opción 1

Podemos usar el SQL GROUP BY cláusula para agrupar las columnas por sus columnas significativas, luego use el COUNT() función para devolver el número de filas idénticas:

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

Resultado:

 firstname | lastname | count 
-----------+----------+-------
 Ruff      | Robinson |     1
 Wag       | Johnson  |     3
 Woof      | Jones    |     1
 Bark      | Smith    |     2

Aquí excluimos la columna de clave principal al omitirla de nuestra consulta.

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 excluir los no duplicados de la salida con HAVING cláusula:

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

Resultado:

 firstname | lastname | count 
-----------+----------+-------
 Wag       | Johnson  |     3
 Bark      | Smith    |     2

Opción 3

Este es un ejemplo de verificación de duplicados en columnas concatenadas. En este caso usamos el CONCAT() función para concatenar nuestras dos columnas, use el DISTINCT palabra clave para obtener valores distintos, luego use COUNT() función para devolver el conteo:

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

Resultado:

    dogname    | count 
---------------+-------
 Wag Johnson   |     3
 Ruff Robinson |     1
 Woof Jones    |     1
 Bark Smith    |     2

Opción 4

Alternativamente, podemos usar el ROW_NUMBER() función de ventana:

SELECT 
    *,
    ROW_NUMBER() OVER ( 
        PARTITION BY FirstName, LastName 
        ORDER BY FirstName, LastName
        ) AS Row_Number
FROM Dogs;

Resultado:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     1 | Bark      | Smith    |          1
     2 | Bark      | Smith    |          2
     4 | Ruff      | Robinson |          1
     5 | Wag       | Johnson  |          1
     6 | Wag       | Johnson  |          2
     7 | Wag       | Johnson  |          3
     3 | Woof      | 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 5

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 
            *,
            ROW_NUMBER() OVER ( 
                PARTITION BY FirstName, LastName 
                ORDER BY FirstName, LastName
                ) AS Row_Number
        FROM Dogs
    )
SELECT * FROM cte WHERE Row_Number <> 1;

Resultado:

 dogid | firstname | lastname | row_number 
-------+-----------+----------+------------
     2 | Bark      | Smith    |          2
     6 | Wag       | Johnson  |          2
     7 | Wag       | Johnson  |          3

Esto excluye los no duplicados de la salida y excluye una fila de cada duplicado de la salida. En otras palabras, solo muestra el exceso de filas de los duplicados. Estas filas son las principales candidatas para ser eliminadas en una operación de eliminación de duplicados.

Opción 6

Aquí hay una forma más concisa de obtener el mismo resultado que el ejemplo anterior:

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

Resultado:

 dogid | firstname | lastname 
-------+-----------+----------
     6 | Wag       | Johnson
     2 | Bark      | Smith
     7 | Wag       | Johnson

Una diferencia entre este ejemplo y el anterior es que este ejemplo no requiere generar nuestro propio número de fila por separado.

Opción 7

Aquí hay otra opción para devolver filas duplicadas en Postgres:

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 | firstname | lastname | dogid | firstname | lastname 
-------+-----------+----------+-------+-----------+----------
     2 | Bark      | Smith    |     1 | Bark      | Smith
     7 | Wag       | Johnson  |     5 | Wag       | Johnson
     7 | Wag       | Johnson  |     6 | Wag       | Johnson