Detectando y eliminando filas duplicadas

Deja un comentario

En una Base de Datos bien diseñada nunca deberíamos tener filas duplicadas pero … a veces tal cosa ocurre. Quizás porque heredamos una Base de Datos de alguien que no sabía mucho como se hace un buen diseño.

Entonces ahora tenemos 3 tareas:

  1. Detectar si hay filas duplicadas
  2. Averiguar cuales son las filas duplicadas
  3. Eliminar las filas duplicadas

Aunque se diga “duplicadas”, en realidad debe entenderse como filas que deberían ser únicas y no son únicas, eso incluye: duplicadas, triplicadas, cuadruplicadas, etc.

Para entender mejor, mostraremos un ejemplo. Tenemos una tabla llamada PROVEEDORES. En esa tabla la columna PRO_RUCXXX debería ser única. El RUC es un número que en algunos países se utiliza para identificar a los contribuyentes fiscales.

Primer paso. Detectando si hay filas duplicadas.

Para saber si en la tabla de PROVEEDORES tenemos RUC duplicados, escribimos:

Listado 1.

SELECT
   PRO_RUCXXX,
   COUNT(*) AS CANTIDAD_FILAS
FROM
   PROVEEDORES
GROUP BY
   PRO_RUCXXX
HAVING
   COUNT(*) >= 2

ELIMINANDO1

Captura 1. Si haces clic en la imagen la verás más grande

Al ejecutar el Listado 1. obtenemos lo que vemos en la Captura 1. y así descubrimos que los datos de varios proveedores han sido escritos, incorrectamente desde luego, más de una vez.

Ok, ya sabemos que hay proveedores con datos duplicados, ahora nuestra siguiente tarea es averiguar los datos de esos proveedores.

Segundo paso. Averiguar cuales son las filas duplicadas.

El Listado 1. no nos dice cuales son los identificadores de los proveedores cuyos RUC están duplicados, y eso es algo que nos interesa conocer. Así que escribimos:

Listado 2.

SELECT
   T1.PRO_IDENTI,
   T1.PRO_RUCXXX
FROM
   PROVEEDORES T1
WHERE
   EXISTS (SELECT
              T2.PRO_IDENTI
           FROM
              PROVEEDORES T2
           WHERE
              T1.PRO_RUCXXX = T2.PRO_RUCXXX AND
              T1.PRO_IDENTI > T2.PRO_IDENTI)
ORDER BY
   T1.PRO_RUCXXX

ELIMINANDO2

Captura 2. Si haces clic en la imagen la verás más grande

Ok, ya sabemos cuales son los identificadores y los RUC de los proveedores cuyos datos están duplicados (y también hay un caso de triplicados).

Ahora, nuestra última tarea es eliminar a esas filas que están sobrando.

Tercer paso. Eliminando las filas duplicadas.

Esto ya es muy fácil, es simplemente reemplazar el SELECT del Listado 2. por un DELETE, nos quedaría así:

Listado 3.

DELETE FROM
   PROVEEDORES T1
WHERE
   EXISTS (SELECT
              T2.PRO_IDENTI
           FROM
              PROVEEDORES T2
           WHERE
              T1.PRO_RUCXXX = T2.PRO_RUCXXX AND
              T1.PRO_IDENTI > T2.PRO_IDENTI)

Si al ejecutar el Listado 3. obtenemos un mensaje similar al siguiente: ‘Violation of FOREIGN KEY constraint “FK_COMPRASCAB” on table “COMPRASCAB”‘, eso significa que el Identificador de uno (o más de uno) de los proveedores que quisimos borrar fue usado en la restricción Foreign Key de otra tabla (en este ejemplo, la tabla se llama COMPRASCAB).

¿Solución?

Actualizar el Identificador de proveedor de la tabla que tiene la restricción Foreign Key (en este caso, COMPRASCAB), poniendo un solo Identificador. O sea que si en la fila cuyo Identificador es 81 el RUC es 1421744-9 y en la fila cuyo Identificador es 162 el RUC también es 1421744-9, debemos cambiar el Identificador 162 por el Identificador 81 en todas las filas de la tabla COMPRASCAB cuyo Identificador sea 162.

O sea, en la tabla COMPRASCAB, todos los Identificadores de proveedores 162 se cambiarán por 81.

¿Y cómo podemos ver los Identificadores de todos los proveedores que tiene RUC repetidos?

Con un SELECT similar al siguiente:

Listado 4.

SELECT
   T1.PRO_IDENTI,
   T1.PRO_RUCXXX
FROM
   PROVEEDORES T1
WHERE
   EXISTS (SELECT
              T2.PRO_RUCXXX
           FROM
              PROVEEDORES T2
           WHERE
              T1.PRO_RUCXXX = T2.PRO_RUCXXX
           GROUP BY
              T2.PRO_RUCXXX
           HAVING
              COUNT(*) >= 2)
ORDER BY
   T1.PRO_RUCXXX

ELIMINANDO3

Captura 3. Si haces clic en la imagen la verás más grande

En la Captura 3. vemos el resultado de ejecutar el Listado 4. y así podremos saber cuales son los Identificadores de los proveedores cuyos RUC están repetidos.

Conclusión:

En nuestras tablas no debemos tener filas duplicadas pero a veces tal cosa ocurre. En casos así nuestras tareas serán detectar si hay filas duplicadas, encontrar cuales son las filas duplicadas, y eliminar las filas duplicadas.

Algo que está en la Base de Datos pero que no debería estar se llama basura, y las filas duplicadas son un ejemplo de basura.

Artículos relacionados:

Obteniendo la primera fila de cada grupo

El índice del blog Firebird21

El foro del blog Firebird21

 

Ejemplo de GROUP BY (1). Respondiendo a “todos” o “en cada uno”

Deja un comentario

A veces necesitamos responder a preguntas que incluyen a las palabras “todos” o “en cada uno”. Por ejemplo:

  • Los productos que se vendieron todos los días
  • Los alumnos que rindieron todos los exámenes
  • Los empleados que trabajaron todos los días

¿Cómo podemos solucionarlo?

Una alternativa es mediante el uso de las cláusulas GROUP BY y HAVING.

La idea es: primero, hallar la cantidad total de alternativas distintas, y luego hallar quienes tienen esa cantidad

Ejemplo:

Tenemos una tabla llamada MOVIMCAB (cabecera de movimientos) donde guardamos, entre otros datos, la fecha de cada venta y el identificador del vendedor que realizó la venta. Y nos interesa responder a la pregunta: ¿cuáles vendedores vendieron todos los días?

TODOS1

Captura 1. Si haces clic en la imagen la verás más grande

En casos así lo mejor es dividir el problema en 3 partes:

  1. Hallar la cantidad de fechas distintas
  2. Hallar la cantidad de fechas distintas en que cada vendedor ha vendido
  3. Comparar ambas cantidades

Paso 1. Hallando la cantidad de fechas distintas

Listado 1.

SELECT
   COUNT(DISTINCT MVC_FECHAX)
FROM
   MOVIMCAB

TODOS2

Captura 2. Si haces clic en la imagen la verás más grande

Al ejecutar el Listado 1. vemos que hay 3 fechas distintas en la tabla MOVIMCAB.

Paso 2. Hallando la cantidad de fechas distintas que cada vendedor ha vendido

Listado 2.

SELECT
   MVC_IDEVEN,
   COUNT(DISTINCT MVC_FECHAX)
FROM
   MOVIMCAB
GROUP BY
   MVC_IDEVEN

TODOS3

Captura 3. Si haces clic en la imagen la verás más grande

Al ejecutar el Listado 2. vemos la cantidad de fechas distintas en que cada vendedor ha vendido.

Paso 3. Comparando ambas cantidades

Listado 3.

SELECT
   MVC_IDEVEN,
   COUNT(DISTINCT MVC_FECHAX)
FROM
   MOVIMCAB
GROUP BY
   MVC_IDEVEN
HAVING
   COUNT(DISTINCT MVC_FECHAX) = (SELECT COUNT(DISTINCT MVC_FECHAX) FROM MOVIMCAB)

TODOS4

Captura 4. Si haces clic en la imagen la verás más grande

Al ejecutar el Listado 3. obtenemos la Captura 4. que nos dice que los vendedores cuyos identificadores son 1 y 7 han vendido todos los días, y que hay 3 días distintos.

Explicación:

En la cláusula HAVING del Listado 3. comparamos la cantidad de fechas distintas que ha vendido cada vendedor con la cantidad de fechas distintas que tenemos en la tabla MOVIMCAB. Si ambas cantidades son iguales entonces evidentemente ese vendedor ha vendido en todas las fechas.

Artículos relacionados:

Entendiendo la cláusula GROUP BY: agrupando datos

La claúsula GROUP BY requiere estar ordenada

La claúsula HAVING: filtrando las filas agrupadas

El índice del blog Firebird21

El foro del blog Firebird21