sql >> Base de Datos >  >> RDS >> MariaDB

7 formas de devolver filas duplicadas que tienen una clave principal en MariaDB

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

Por lo tanto, las filas duplicadas comparten exactamente los mismos valores en todas las columnas excepto en su columna de identificador único.

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 que normalmente es bueno en los RDBMS. Sin embargo, por definición esto significa que no hay duplicados. En nuestro caso, 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 columnas que son significativo.

Opción 1

Podemos usar el 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 |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Ruff      | Robinson |     1 |
| Wag       | Johnson  |     3 |
| Woof      | Jones    |     1 |
+-----------+----------+-------+

Pudimos excluir la columna de clave principal al omitirla de nuestra consulta.

El resultado nos dice que hay dos filas que contienen a Bark Smith y tres filas que contienen a Wag Johnson. 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 |
+-----------+----------+-------+
| Bark      | Smith    |     2 |
| Wag       | Johnson  |     3 |
+-----------+----------+-------+

Opción 3

También es posible buscar duplicados en columnas concatenadas. Por ejemplo, podemos usar 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 |
+---------------+-------+
| Bark Smith    |     2 |
| Ruff Robinson |     1 |
| Wag Johnson   |     3 |
| Woof Jones    |     1 |
+---------------+-------+

Opción 4

Podemos usar el ROW_NUMBER() función con la PARTITION BY cláusula:

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 |
|     6 | Wag       | Johnson  |          1 |
|     5 | Wag       | Johnson  |          2 |
|     7 | Wag       | Johnson  |          3 |
|     3 | Woof      | Jones    |          1 |
+-------+-----------+----------+------------+

Esto crea una nueva columna con un número de fila que aumenta cada vez que hay un duplicado, pero se reinicia cuando hay una fila única.

En este caso, no estamos agrupando 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 |
|     5 | 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.

Esta consulta podría usarse como precursora de una operación de eliminación de duplicados. Puede mostrarnos qué se va a eliminar si decidimos eliminar los duplicados. Para deduplicar la tabla, todo lo que tenemos que hacer es reemplazar el último SELECT * con DELETE .

Opción 6

Aquí hay una forma más sucinta 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 |
+-------+-----------+----------+
|     2 | Bark      | Smith    |
|     6 | Wag       | Johnson  |
|     7 | Wag       | Johnson  |
+-------+-----------+----------+

Este ejemplo no requiere generar nuestro propio número de fila por separado.

Podemos reemplazar SELECT * con DELETE para eliminar los duplicados.

Opción 7

Y finalmente, aquí hay otra opción para devolver duplicados:

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  |
+-------+-----------+----------+-------+-----------+----------+