Borrando filas duplicadas en Teradata (II)

Es un asunto recurrente en cualquier foro de Teradata: ¿cómo borro filas duplicadas en una tabla MULTISET? El tema ya lo tratamos aquí, y el problema principal es que Teradata no maneja los ROWIDs a la manera de Oracle (y otros RDBMSs), de forma que no se puede acceder a las filas directamente mediante su ROWID para borrarlas de forma individual.

Hay varias formas de librarse de las molestas filas duplicadas, como crear tablas nuevas y llenarlas con SELECT DISTINCT… También con técnicas algo más más artificiosas, como vimos aquí. Hoy vamos a ver otra solución al problema, aunque es un poco más enrevesada…

Tenemos una tabla MULTISET con filas repetidas:

 BTEQ -- Enter your SQL request or BTEQ command:
SHOW TABLE CARLOS.PRUEBADUP;


 *** Text of DDL statement returned.
 *** Total elapsed time was 1 second.

-------------------------------------------------------------------
CREATE MULTISET TABLE CARLOS.PRUEBADUP ,
     NO FALLBACK ,
     NO BEFORE JOURNAL,
     NO AFTER JOURNAL,
     CHECKSUM = DEFAULT,
     DEFAULT MERGEBLOCKRATIO
     (
      ID_N INTEGER NOT NULL,
      C_TXT VARCHAR(10) CHARACTER SET LATIN CASESPECIFIC NOT NULL)
PRIMARY INDEX ( ID_N );


 BTEQ -- Enter your SQL request or BTEQ command:
SELECT * FROM CARLOS.PRUEBADUP;


 *** Query completed. 3 rows found. 2 columns returned.
 *** Total elapsed time was 1 second.

       ID_N  C_TXT
-----------  ----------
          1  UNO
          1  UNO
          1  UNO

Para eliminar los duplicados vamos a recurrir a un cursor y una cláusula WHERE CURRENT OF, que es ANSI 2011. Para ello creamos un procedimiento almacenado de la siguiente forma:

REPLACE PROCEDURE CARLOS.BORRADUPS()
BEGIN
   DECLARE iIndice INTEGER DEFAULT 1;
   FOR iFila AS cFila CURSOR FOR SELECT ID_N, C_TXT FROM CARLOS.PRUEBADUP
   DO
      IF iIndice > 1 THEN
         DELETE FROM CARLOS.PRUEBADUP
               WHERE CURRENT OF cFila;
      END IF;
      SET iIndice = iIndice + 1;
   END FOR;
END;

Así pues, lo compilamos…

 BTEQ -- Enter your SQL request or BTEQ command:
.COMPILE FILE C:\Carlos\TeradataStoredProcedures\BORRADUPS.sql;


 *** Procedure has been replaced.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:
COMMIT;


 *** COMMIT done.
 *** Total elapsed time was 1 second.

…y lo ejecutamos:

 BTEQ -- Enter your SQL request or BTEQ command:
CALL CARLOS.BORRADUPS();


 *** Procedure has been executed.
 *** Total elapsed time was 1 second.


 BTEQ -- Enter your SQL request or BTEQ command:
COMMIT;

 *** COMMIT done.
 *** Total elapsed time was 1 second.

Y, como por arte de magia, tenemos que:

 BTEQ -- Enter your SQL request or BTEQ command:
SELECT * FROM  CARLOS.PRUEBADUP;


 *** Query completed. One row found. 2 columns returned.
 *** Total elapsed time was 1 second.

       ID_N  C_TXT
-----------  ----------
          1  UNO

Las filas duplicadas han desaparecido de forma sencilla y limpia.

Aunque los más avispados se habrán extrañado al encontrarse con todos esos COMMITs… y con razón. Esto es así porque la cláusula WHERE CURRENT OF sólo funciona en sesiones en modo ANSI, por lo que antes de comenzar la sesión en bteq que compilaba el procedimiento almacenado hubo que ejecutar un:

.SET SESSION TRANSACTION ANSI

Y esto, aunque pueda parecer poco importante, tiene ciertas consecuencias, porque si abrimos otra sesión en modo BTET e intentamos ejecutar el procedimiento:

.LOGON SLES11/carlos
Password:

 *** Logon successfully completed.
 *** Teradata Database Release is 14.10.00.02
 *** Teradata Database Version is 14.10.00.02
 *** Transaction Semantics are BTET.
 *** Session Character Set Name is 'ASCII'.

 *** Total elapsed time was 1 second.

 BTEQ -- Enter your SQL request or BTEQ command:
 *** Warning: EOF on INPUT stream.
 BTEQ -- Enter your SQL request or BTEQ command:
CALL CARLOS.BORRADUPS();

 *** Failure 5510 Invalid session mode for procedure execution.
                Statement# 1, Info =0
 *** Total elapsed time was 1 second.

En efecto, un procedimiento almacenado que fue compilado en una sesión con modo ANSI no puede ser ejecutado en modo Teradata (BTET).

Well, nobody’s perfect! – Osgood Fielding III.

Por otra parte, un tratamiento row by row dista mucho de ser el tratamiento ideal (aunque, como siempre, puede haber determinados casos en los que pudiera ser aplicable, sobre todo definiendo bien el cursor y siempre y cuando no haya un gran número de filas duplicadas).

Saludos.

Carlos.

Anuncios

One Response to Borrando filas duplicadas en Teradata (II)

  1. […] Editado: También es posible hacerlo de otra forma. […]

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: