viernes, 10 de enero de 2014

Este articulo voy a explicar como de una consulta normal podemos obtener el mismo resultado pero transformando las filas por columna.
Para ello la tabla a transformar debe cumplir los siguientes requisitos:
- La tabla a original debe tener un identificador único.
- La tabla original solo puede tener 2 columnas, a ser posible una cadena y un valor numérico.

En mi caso voy a utilizar una tabla simple que se llama 'Prueba' con 3 columnas,la primera es el identificador unico 'Id', la segunda columna es 'Nombre' del tipo varchar, y la tercera se llama 'Valor' del tipo int.

El resultado de un SELECT * FROM Prueba es el siguiente
Primero debemos guardar el resultado del la tabla a transformar en una tabla Temporal de esta manera

SELECT P.Id Id_Registro,'[' +P.Nombre+ ']' NombreCampo ,P.Valor Valor
INTO #TablaTransformada
FROM Prueba P

Después creamos 2 variables para asignarles valor dentro de un SELECT, la primera guardara un texto que sera una consulta en texto plano del tipo 'ALTER TABLE #Resultado ADD' la cual va a añadir como nombre de columna los valores del campo 'NombreCampo'.
La segunda tiene la misma funcionalidad pero para guardar un UPDATE con el valor del campo 'Valor'.

DECLARE @SqlAlter VARCHAR(MAX), @SqlUpdate VARCHAR(MAX)
SET @SqlAlter = 'ALTER TABLE #Resultado ADD '
SET @SqlUpdate = ''
SELECT @SqlAlter = @SqlAlter + NombreCampo + ' varchar(250),'
, @SqlUpdate = @SqlUpdate + 'UPDATE #Resultado SET ' + NombreCampo + ' = LEFT(CV.Valor, 250) FROM #TablaTransformada CV INNER JOIN #Resultado R ON CV.Id_Registro = R.Id WHERE CV.NombreCampo = ''' + NombreCampo + '''' + CHAR(10) + CHAR(13)
FROM #TablaTransformada DC
WHERE NombreCampo IS NOT NULL
GROUP BY NombreCampo
ORDER BY NombreCampo

La consulta anterior lo que hace es generar este codigo plano dinamicamente para luego lanzarlo con un EXEC

ALTER TABLE #Resultado ADD [Mesa] varchar(250),[Puerta] varchar(250),[Silla] varchar(250),[Sillon] varchar(250),

-UPDATE #Resultado SET [Mesa¡] = LEFT(CV.Valor, 250) FROM #TablaTransformada CV 
INNER JOIN #Resultado R ON CV.Id_Registro = R.Id WHERE CV.NombreCampo = '[Mesa]'

-UPDATE #Resultado SET [Puerta] = LEFT(CV.Valor, 250) FROM #TablaTransformada CV
 INNER JOIN #Resultado R ON CV.Id_Registro = R.Id WHERE CV.NombreCampo = '[Puerta]'

-UPDATE #Resultado SET [Silla] = LEFT(CV.Valor, 250) FROM #TablaTransformada CV
 INNER JOIN #Resultado R ON CV.Id_Registro = R.Id WHERE CV.NombreCampo = '[Silla]'

-UPDATE #Resultado SET [Sillon] = LEFT(CV.Valor, 250) FROM #TablaTransformada CV 
INNER JOIN #Resultado R ON CV.Id_Registro = R.Id WHERE CV.NombreCampo = '[Sillon]'

Si te das cuenta que al final de la consulta alter hay una ',' que si no se quita el sql al ejecutarlo mostraría un error, por ello mas adelante lo eliminaremos.
Ademas tenemos que tener en cuenta, que para el proceso funcione para cualquier tipo datos, se realiza una conversión tanto de la columna 'NombreCampo' así como 'Valor' al tipo VARCHAR(250), ademas de agrupar por 'NombreCampo', para que tenga en cuenta que dentro del campo 'NombreCampo'
pueden existir 2 registros con el mismo valor.

Ya para finalizar debemos crear la tabla temporal #Resultado y lanzar las variables declaradas con un simple EXEC e insertamos dentro de la tabla  #Resultado como han quedado los resultados

CREATE TABLE #Resultado (Id INT)
IF @SqlUpdate <> '' 
BEGIN
   SET @SqlAlter = LEFT(@SqlAlter, LEN(@SqlAlter) -1) -- Quitamos la última coma de @SqlAlter
   EXEC (@SqlAlter)
   INSERT INTO #Resultado(Id) SELECT DISTINCT Id_Registro FROM #TablaTransformada
   EXEC (@SqlUpdate)
END

Si hacemos SELECT  * FROM #Resultado el resultado es el siguiente
No olvides borrar las tablas temporales cuando no las tengas que utilizar mas para liberar memoria y que no produzca un error al volver a ejecutar el procedimiento.

DROP TABLE #TablaTransformada
DROP TABLE #Resultado

Espero que os sirva para algo este articulo.

El código completo seria:

SELECT P.Id Id_Registro,'[' +P.Nombre+ ']' NombreCampo ,P.Valor 
INTO #TablaTransformada
FROM Prueba P

DECLARE @SqlAlter VARCHAR(MAX), @SqlUpdate VARCHAR(MAX)
SET @SqlAlter = 'ALTER TABLE #Resultado ADD '
SET @SqlUpdate = ''
SELECT @SqlAlter = @SqlAlter + NombreCampo + ' varchar(250),', @SqlUpdate = @SqlUpdate + 'UPDATE #Resultado SET ' + NombreCampo + ' = LEFT(CV.Valor, 250) FROM #TablaTransformada CV INNER JOIN #Resultado R ON CV.Id_Registro = R.Id WHERE CV.NombreCampo = ''' + NombreCampo + '''' + CHAR(10) + CHAR(13)
FROM #TablaTransformada DC
WHERE NombreCampo IS NOT NULL
GROUP BY NombreCampo
ORDER BY NombreCampo

CREATE TABLE #Resultado (Id INT)
IF @SqlUpdate <> ''
BEGIN
SET @SqlAlter = LEFT(@SqlAlter, LEN(@SqlAlter) -1)-- Quitamos la última coma de la variable @SqlAlter.
EXEC (@SqlAlter)
INSERT INTO #Resultado(Id) SELECT DISTINCT Id_Registro FROM #TablaTransformada
EXEC (@SqlUpdate)
END

SELECT  *
FROM    #Resultado

DROP TABLE #TablaTransformada
DROP TABLE #Resultado

0 comentarios:

Publicar un comentario

Site search