Todo aquél que llega a Teradata procedente de entornos Oracle pregunta lo mismo ‘¿Aquí no hay tabla DUAL?’. La respuesta suele ser ‘No. No hace falta.’.
En efecto: en Teradata un ‘SELECT’ no tiene por qué tener un ‘FROM’:
BTEQ -- Enter your DBC/SQL request or BTEQ command: SELECT DATE; *** Query completed. One row found. One column returned. *** Total elapsed time was 1 second. Date -------- 09/12/10 BTEQ -- Enter your DBC/SQL request or BTEQ command: SELECT 1 DUMMY; *** Query completed. One row found. One column returned. *** Total elapsed time was 1 second. DUMMY ----- 1
Esto al principio le deja a uno un poco ‘a cuadros’, acostumbrado a años y años de ‘SELECT SYSDATE FROM DUAL’ (‘OK. Me adapto y ya está.’).
Entonces uno se acuerda de esto:
SQL*Plus: Release 10.2.0.1.0 - Production on Jue Dic 10 20:21:08 2009 Copyright (c) 1982, 2005, Oracle. All rights reserved. Introduzca el nombre de usuario: carlos@XE.localhost Introduzca la contraseña: Conectado a: Oracle Database 10g Express Edition Release 10.2.0.1.0 - Production CARLOS@XE.localhost> SELECT * 2 FROM ( SELECT 1 FROM DUAL 3 UNION ALL 4 SELECT 2 FROM DUAL 5 UNION ALL 6 SELECT 3 FROM DUAL ); 1 ---------- 1 2 3
… e intenta hacer algo como esto:
BTEQ -- Enter your DBC/SQL request or BTEQ command: SELECT * FROM ( SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ); *** Failure 3707 Syntax error, expected something like a name or a Unicode delimited identifier or an 'UDFCALLNAME' keyword between ')' and ';'. Statement# 1, Info =108 *** Total elapsed time was 1 second.
‘¡Ah!, es que en Terdata todas las SUBSELECTs deben llevar alias’:
SELECT * FROM ( SELECT 1 UNION ALL SELECT 2 UNION ALL SELECT 3 ) a; SELECT * $ *** Failure 3706 Syntax error: All expressions in a derived table must have an explicit name. Statement# 1, Info =0 *** Total elapsed time was 1 second.
‘¡Ah!, es que en Terdata todas las columnas deben llevar nombre’.
Pero entonces ocurre lo siguiente:
BTEQ -- Enter your DBC/SQL request or BTEQ command: SELECT * FROM ( SELECT 1 DUMMY UNION ALL SELECT 2 DUMMY UNION ALL SELECT 3 DUMMY ) a ; *** Failure 3888 A SELECT for a UNION,INTERSECT or MINUS must reference a table. Statement# 1, Info =0 *** Total elapsed time was 1 second.
¿Pero, no habíamos quedado en que en Teradata no hacía falta un ‘FROM’? Ya. Pero parece que en las UNION, INTERSECT o MINUS sí.
¿Entonces, qué hacemos sin nuestra tabla DUAL?
Aquí hay gente que decide recurrir a cualquier tabla de utilidad:
BTEQ -- Enter your DBC/SQL request or BTEQ command: SELECT * FROM ( SELECT 1 DUMMY FROM SYS_CALENDAR.CALENDAR WHERE DAY_OF_CALENDAR = 1 UNION ALL SELECT 2 DUMMY FROM SYS_CALENDAR.CALENDAR WHERE DAY_OF_CALENDAR = 1 UNION ALL SELECT 3 DUMMY FROM SYS_CALENDAR.CALENDAR WHERE DAY_OF_CALENDAR = 1 ) a; *** Query completed. 3 rows found. One column returned. *** Total elapsed time was 1 second. DUMMY ----- 1 2 3
Pero, en el fondo, no es más que un rodeo (‘workaround‘, lo llaman los anglosajones) para soslayar el problema de la falta de tabla DUAL.
Otra solución es crearnos nuestra propia tabla DUAL, con una única columna ‘DUMMY’ y una única fila ‘X’ -a imagen y semejanza de la añorada DUAL de Oracle-. Otro rodeo.
Pero lo que queremos no es rodear el problema. Queremos resolverlo. ¿Cómo crear tablas sobre la marcha con ‘UNION’ en Teradata?
Teniendo en cuenta lo que hemos dicho arriba sobre la obligatorieded de alias y nombres para tablas y columnas, la solución es más fácil de lo que parece:
BTEQ -- Enter your DBC/SQL request or BTEQ command: SELECT * FROM ( SELECT 1 COL FROM ( SELECT 'X' DUMMY ) a UNION ALL SELECT 2 FROM ( SELECT 'X' DUMMY ) b UNION ALL SELECT 3 FROM ( SELECT 'X' DUMMY ) c ) d ; *** Query completed. 3 rows found. One column returned. *** Total elapsed time was 1 second. COL ---- 1 2 3
Una cosa más para los nostálgicos: no utilicéis ‘DUAL’ como alias de tabla, ya que en TERADATA DUAL es una palabra reservada:
SELECT * FROM ( SELECT 1 COL FROM ( SELECT 'X' DUMMY ) DUAL UNION ALL SELECT 2 FROM ( SELECT 'X' DUMMY ) DUAL UNION ALL SELECT 3 FROM ( SELECT 'X' DUMMY ) DUAL ) d ; UNION ALL $ *** Failure 3707 Syntax error, expected something like a name or a Unicode delimited identifier or an 'UDFCALLNAME' keyword between ')' and the 'DUAL' keyword. Statement# 1, Info =63 *** Total elapsed time was 1 second.
Cualquier otra valdrá:
BTEQ -- Enter your DBC/SQL request or BTEQ command: SELECT * FROM ( SELECT 1 COL FROM ( SELECT 'X' DUMMY ) MY_DUAL UNION ALL SELECT 2 FROM ( SELECT 'X' DUMMY ) MY_DUAL UNION ALL SELECT 3 FROM ( SELECT 'X' DUMMY ) MY_DUAL ) d ; *** Query completed. 3 rows found. One column returned. *** Total elapsed time was 1 second. COL ---- 1 2 3
Saludos.
Carlos.