Você está na página 1de 4

Agregar columnas en sentencias SELECT SQL

Artculo original: Adding Columns in SQL SELECT statements


http://weblogs.foxite.com/andykramek/archive/2005/09/18/921.aspx Autor: Andy Kramek (http://www.tightlinecomputers.com) Traducido por: Ana Mara Bisb York (amby@telefonica.net) Para: PortalFox (http://www.portalfox.com)

Un requerimiento habitual cuando trabajamos con datos, independientemente de su origen, es poder agregar "al vuelo" columnas adicionales al resultado. Esto es muy sencillo si slo se necesita una columna en blanco, basta con definirla directamente en la consulta utilizando la funcin SPACE(), de esta forma:

SELECT SPACE(30) AS newcol FROM nametable


(Observe que la palabra "AS" en realidad no es requerida por la sintaxis de VFP (o SQL Server); pero algunos de los dialectos lo requieren, y en cualquier caso, pienso que mejora la lectura de la consulta.) Ahora, vamos a suponer que tenemos algunos datos en una tabla como esta: cfirst Andy clast Kramek iintcol 0 nnum1 123.45 nnum2 3456.78

Vladimir Andropovitch 3

1111.65 654.32

Si necesitamos concatenar las columnas del nombre para crear un "nombre completo", entonces, podemos hacer algo como esto:

SELECT (ALLTRIM( cfirst ) + " " + ALLTRIM( clast )) AS fullname FROM sample
Aunque, en la prctica esto no es tan intuitivo como se puede ver a simple vista. La cuestin aqu es que cuando creamos una "columna computada" (que es lo que yo hago aqu) VFP crea la definicin para esa columna basado en la longitud de las columnas existentes en la concatenacin. Entonces, si ambos campos "cfirst" y "clast" se definen como c(20), el resultado se define con un campo que tenga c(41). En otras palabras, los 20 caracteres para el primer campo, uno para el espacio y 20 caracteres para cada campo. Esto est bien, aunque puede ser una prdida de espacio; pero no provocar prdida de datos y si deseamos en realidad acortarlos, podemos simplemente utilizar la funcin PADR() para forzar el ancho de un valor especfico:

SELECT PADR( ALLTRIM( cfirst ) + " " + ALLTRIM( clast ), 30) AS fullname FROM sample
Sin embargo, si adems estamos convirtiendo tipos de datos (de nmeros a caracteres, por ejemplo), entonces tendremos un problema potencia debido a que en este caso VFP no conoce de qu largo pudieran ser los datos. Todo lo que puede hacer es basarse en la definicin del tamao del primer elemento encontrado. Entonces, la consulta siguiente:

SELECT TRANSFORM( nnum1 ) AS cvalue FROM sample


Devolver un conjunto resultante con la columna "cvalue" definida como c(6) - en otras palabras, el nmero de caracteres en el primer valor de la tabla. Esto, por supuesto, significa que el segundo valor se trunca debido a que en realidad contiene siete caracteres. Entonces, ahora es muy importante asegurarse de que hemos especificado un formato para el campo que sea tan largo como para manipular cualquier posible valor y nosotros podemos utilizar la funcin PADR() para controlar el formato una vez que hayamos transformado el dato: como esto:

SELECT PADR( TRANSFORM( nnum1 ), 10) AS cvalue FROM sample


Pero, la introduccin de la funcin CAST() en VFP 9.0 brinda una alternativa, debido a que nos permite decir directamente a VFP cmo deseamos obtener la salida de los resultados. Entonces, en VFP 9.0 podemos escribir la primera consulta de esta forma:

SELECT CAST( ALLTRIM( cFirst ) + " " + ALLTRIM( cLast ), AS CHAR(30)) AS fullName FROM sample
y la segunda:

SELECT CAST( nnum1 AS CHAR(10)) AS cvalue FROM sample


Todo esto est muy bien cuando estamos trabajando con columnas existentes; pero qu ocurre si necesitamos crear una columna nueva con un tipo de dato especfico? Bueno, es bastante fcil crear columnas de caracteres, empleando la funcin SPACE() (o incluso PADL()) para crear el ancho requerido:

SELECT *, SPACE(30) AS newstring FROM sample


De forma similar, si necesita una columna para datos tipo moneda, las debera definir como "$U" y un dato nuevo utilizando una cadena fecha vaca "{}", una nueva columna decimal utilizando una cadena de ceros, una columna lgica utilizando .F., etc.

SELECT $0 AS yamount, {} AS dpaid, 00000.00 AS newbal, .F. AS lCleared FROM sample


Teniendo esto, podra estar tentado a pensar, que crear una columna para datos enteros sera tan sencillo como:

SELECT 0 AS newint FROM sample


Despus de todo, al crear una columna para enteros en una tabla, se inicializa con "0", entonces, parece razonable decirle a VFP que al crear una columna para valor "0" obtendremos un entero. Desafortunadamente no es el caso! Lo que en realidad ocurre es que VFP crea una columna numrica con ancho = 1 y decimales = 0. El resultado es que solamente puede guardar los valores de 0-9. Y esto no es lo que queremos! Entonces, cmo obtenemos un valor entero? Bueno, antes de VFP 9.0 exista un pequeo truco y dos vas posibles para hacerlo. La primera (y ms sencilla) sera definir la columna con suficiente espacio para guardar el entero.

SELECT *, 0000000000 AS newint FROM sample


El resultado en realidad no es una columna para datos enteros, muy por el contrario, es una columna numrica muy grande (N(10,0)) y siempre encuentro problemtico estar contando tantos ceros. Para crear una verdadera columna para enteros en un conjunto resultante tenemos que emplear un truco que implica crear un producto cartesiano. Un producto cartesiano ocurre cuado una consulta une dos tablas sin especificar una condicin de validacin. El resultado es que cada registro de la primera tabla se enlaza con cada registro de la segunda. El conjunto resultante contiene, por tanto, la cantidad de registros que se obtiene de la multiplicacin de la cantidad de registros de la primera tabla por la cantidad de registros de la segunda tabla. Esto generar rpidamente un conjunto resultante MUY grande. Una consulta como esta:

SELECT * FROM table1, table2

Asumiendo que tenemos 100 registros en la primera tabla y 1000 registros en la segunda, podramos generar un resultado que contenga 100,000 registros. Suena como un error, verdad? Entonces, cmo puede esto ayudarnos a crear una columna para datos enteros? Bueno, si creamos un cursor llamado "dummy" (ficticio) que tiene una nica columna (definida como un entero). Entonces, aadimos un registro vaco al cursor e incluimos "dummy" en la lista FROM de la consulta sin especificar una condicin de unin, forzamos que todas las columnas del cursor ficticio sean agregadas incondicionalmente al conjunto resultante con una columna extra, para valores enteros, que se llama con el nombre que le hayamos dado en el cursor ficticio. De esta forma:

CREATE CURSOR dummy ( newint I ) INSERT INTO dummy VALUES (0) SELECT * FROM sample, dummy
El mismo truco puede ser utilizado para agregar al conjunto resultante, campos MEMO, GENERAL o incluso cualquier columna, para cualquier tipo de datos. Sin embargo, utilizando VFP 9.0 no tendremos ms necesidad de emplear este truco, gracias, una vez ms a la funcin CAST(). Al utilizar esta funcin podemos simplemente decirle a VFP que cree el tipo de columna que necesitamos:

SELECT *, CAST( 0 AS INT) AS newint FROM sample


De hecho, podemos tambin utilizar CAST() para forzar que sea devuelto un tipo de datos determinado. Algo que siempre resultaba irritante para los usuarios era cuando nosotros, los desarrolladores, utilizamos campos tipo fechahora para guardar datos que son en realidad solo fecha (con frecuencia, no tenamos opcin debido a que necesitbamos compatibilidad con SQL Server donde no podemos utilizar tipos fecha directamente porque no est soportado). Una vez ms, tenemos forma de controlar esto en todas las versiones de VFP; pero la nueva funcin CAST() es la forma ms limpia y sencilla de controlarlo:

SELECT CAST( datetime AS date ) AS sqldate FROM sample


El fichero de Ayuda de VFP 9.0 incluye una tabla que define las conversiones que se pueden hacer con CAST() y las que no. Por ejemplo, puede mostrar valores de fecha como caracteres, varchar, datetime o memo; pero no como datos numricos. Por supuesto, la razn habitual para agregar una nueva columna al conjunto resultante es que luego puede actualizarlo con algunos valores. Un requerimiento habitual es agregar una columna de valores lgicos al cursor que ser utilizada como fuente para imprimir un informe. La idea es que al procesar cada registro, un indicador se actualiza y tenemos alguna idea de cules son los registros que en realidad deben enviarse a la impresora en caso de que algo vaya mal. El problema en este caso es, que el cursor creado por una instruccin select SQL se crea en VFP de tipo slo lectura. Antes de la versin 7.0, tenamos que emplear otro truco para crear una versin slo lectura de un cursor VFP. Se basa en el hecho de que el cursor en realidad est implementado como una tabla temporal y si trata de utilizar en dos ocasiones un cursor existente, VFP est obligado a crear una segunda tabla para ello, y esa tabla se va a crear del tipo lectura-escritura. Entonces, el cdigo siguiente va a crear un cursor de lectura-escritura en cualquier versin de VFP ( incluso en FoxPro 2.x!!)

SELECT * FROM sample INTO CURSOR temp USE DBF( "temp" ) AGAIN IN 0 ALIAS cur_readwrite SELECT cur_readwrite USE IN temp
La versin 7.0 de VFP introdujo la clasula READWRITE al lenguaje, la que dice a VFP que cree directamente un cursor tipo lectura-escritura:

SELECT * FROM sample INTO CURSOR temp READWRITE

Y ahora lo utilizo siempre que sea posible. Sin embargo, como recordaba hace unos das, es importante conocer los viejos trucos ya que tenemos alguna aplicacin funcionando en FoxPro 2.6 para un cliente y la va ms sencilla para controlar el problema era utilizar un cursor del tipo lectura-escritura, por supuesto, en FoxPro 2.6 no lo poda hacer ... excepto utilizando el truco mostrado antes.

Você também pode gostar