Pivot Dinamico

December 13, 2022 | Author: Anonymous | Category: N/A
Share Embed Donate


Short Description

Download Pivot Dinamico...

Description

 

Implementación de PIVOT Dinámico PIVOT es uno de los nuevos operadores incluídos en SQL Server 2005 que podemos usar en la PIVOT  cláusula FROM para rotar filas en columnas y conseguir informes de tabla cruzada en un formato tabular, más presentables, claramente claramente resumidos y descriptivos. descriptivos. En un post anterior tratamos tratamos un ejemplo acerca del uso de PIVOT. Bien, la forma cómo se usó PIVOT en dicho ejemplo viene a ser su implementación estática, asi es, vimos  vimos cómo implementar PIVOT estático, estático, además se dejó algunos al gunos recursos para familiarizarse con el tema. Por ejemplo, usemos la base de datos AdventureWorks AdventureWorks y analicemos un poquito el resultado del siguiente query que más adelante pivotearemos: SELECT CustomerID, CustomerID,YEAR YEAR(DueDate) (DueDate) [Year [Year], ], TotalDue FROM Sales.SalesOrderHeader ORDER  ORDER  BY CustomerID En los resultados podemos apreciar que cada cliente hizo muchas ventas por año, entre los años 2001 y 2004. CustomerID Year TotalDue --------------------- --------------------1 2001 14603,7393 2001 26128,8674 1 1 2002 37643,1378 1 2002 34722,9906 2 2002 10184,0774 2 2002 5469,5941 2 2003 1739,4078 2 2003 1935,5166 2 2003 3905,2547 2 2003 4537,8484 2 2004 4053,9506 2 2004 908,3199 3 2004 17051,8292 3 2004 34873,5257 ... ..... .......(Continúa) En fin, el uso de  de  PIVOT estático  estático tiene la clara desventaja de limitar en número de columnas desglosadas para mostrar información de la columna pivoteada, por ejemplo, de acuerdo al resultado del query anterior, si queremos pivotear la columna TotalDue, y desglosar la informac i nformación ión en 4 columnas, es decir, pivotear TotatlDue para los años del 2001 al 2004, se tendría que especificar cada uno de esos valores dentro de la consulta, cuestión que será sencillo y fácil dado que sólo tendremos que indicar 4 valores.

SELECT CustomerID, [2001] AS AS   '2001' '2001', , [2002] AS AS   '2002' '2002', , [2003] AS AS   '2003' '2003', , [2004] AS AS   '2004' '2004'    FROM ( SELECT CustomerID, CustomerID,YEAR YEAR(DueDate) (DueDate) [Year [Year], ], TotalDue FROM FROM    Sales.SalesOrderHeader ) pvt PIVOT (SUM (SUM(TotalDue) (TotalDue) FOR [Year Year] ] IN ([2001],[2002],[2003],[2004])) AS Child ORDER  ORDER  BY CustomerID Hasta aquí todo parece estar bien, y claro que es así. He aquí los resultados: CustomerID 2001 2002 2003 2004 ------------------------------- --------------------- --------------------- --------------------1 40732,6067 40732,6067 72366,1284 72366,128 4 NULL NULL 2 NULL 15653,6715 12118,0275 4962,2705 3 4

39752,8421 NULL

168393,7021 263025,3113

219434,4265 373484,299

51925,3549 143525,6018

 

5 6 7 8 9 10 11 12 14 ...

NULL NULL NULL NULL NULL NULL 40350,4474 40350,44 74 NULL NULL ........

33370,6901 NULL 6651,036 NULL 320,6283 96701,7401 24300,4254 24300,425 4 117419,735 NULL ...........

60206,9999 20641,1106 20641,110 6 668,4861 2979,3473 2979,347 3 3718,7804 NULL 19439,2466 10900,0347 10900,034 7 11401,5975 5282,8652 291472,2172 204525,9634 NULL NULL 191505,7911 191505,791 1 29091,7653 7348,0162 1446,6848 ............. ......(Continúa)

Sin embargo, hay un problema, ¿Sabes ¿Sabes cual es el problema? -> la implementación de  de PIVOT estáticos  no es escalable, ya que los valores de la estáticos l a columna que se desglosa para llenar información de la columna pivoteada puede aumentar, es decir, conforme vaya pasando el tiempo la ventas se seguirán llevando acabo teniendo años superiores al 2004, como 2005, 2006,..., y si quisiera (pasados 2 años por ejemplo) pivotear todas las ventas para todos los años hasta la fecha tendría que modificar el query, modificar e indicar i ndicar los años adicionales a desglosars desglosarse. e. Otro desventaja sería por ejemplo, ¿Qué pasa si tengo que pivotear un columna que tiene 30 valores diferentes?, pues usando  usando PIVOT estático  estático tendría que estar indicando manualmente cada uno de los 30 valores dentro del query, cosa que se torna fastidiosa, aburrida, y sobre todo trabajosa, y esto es poco, pueden ser más valores, por ejemplo 100, me muero!. Todos estos líos se solucionan mediante PIVOT dinámico, que no viene a ser más que una implementación algoritmica para capturar dinámicamente dinámicamente los valores de la columna a desglosare para la columna pivoteada e insertarlo dentro de la cadena final del query a ejecutarse usando  sp_executesql usando sp_executesql  (SQl Dinámico) Dinámico). Dejo el query a su merced!, podeis masticarlo a su gusto!.

DECLARE @TableYears AS AS   TABLE TABLE([ ([Year Year] ] INT INT   NOT NOT   NULL NULL) ) DECLARE @Year Year   INT INT, , @YearsPVT NVARCHAR(MAX NVARCHAR(MAX) ) INSERT  INSERT  INTO @TableYears SELECT SELECT   DISTINCT DISTINCT   YEAR YEAR(DueDate) (DueDate) AS [Year Year] ] FROM FROM    Sales.SalesOrderHeader SET @Year = (SELECT (SELECT   MIN MIN([ ([Year Year]) ]) FROM @TableYears) SET @YearsPVT=N @YearsPVT=N'' ''    WHILE @Year Year   IS IS   NOT NOT   NULL NULL    BEGIN  BEGIN   SET @YearsPVT = @YearsPVT + N',[' N',['+ + CONVERT CONVERT(NVARCHAR(10),@ (NVARCHAR(10),@Year Year) ) + N']' N']'    SET @Year = (SELECT (SELECT   MIN MIN([ ([Year Year]) ]) FROM @TableYears WHERE [Year Year]>@ ]>@Year Year) ) END  END   SET @YearsPVT = SUBSTRING SUBSTRING(@YearsPVT,2,LEN(@YearsPVT)) (@YearsPVT,2,LEN(@YearsPVT)) PRINT @YearsPVT DECLARE @SQL NVARCHAR( NVARCHAR(MAX MAX) ) SET @SQL = N'SELECT N'SELECT *  *  FROM ( SELECT CustomerID,YEAR(DueDate) [Year], TotalDue FROM Sales.SalesOrderHeader ) pvt PIVOT (SUM(TotalDue) FOR [Year] IN (' + @YearsPVT + ')) AS Child  Child  ORDER by CustomerID' EXECUTE sp_executesql @SQL

Los resultados del query con PIVOT dinámico serán los mismos que los conseguidos usando PIVOT estático :D. Funciona!, sí señor! :). Ahora vayamos con otro ejemplo, algo parecido, pero ahora será usando la  la base de datos Northwind, Northwind, pivoteamos la columna Monto y lo desglosaremos de acuerdo al CategoryName CategoryName::

 

--ESTO ES LO QUE PIVOTEAMOS! SELECT P.ProductID, C.CategoryName, OD.UnitPrice * OD.Quantity AS Monto FROM Products P INNER  INNER  JOIN dbo.[ dbo.[Order Order Details] OD ON P.ProductID=OD.ProductID INNER  INNER  JOIN Categories C ON C.CategoryID=P.CategoryID Estos serán los resultados: ProductID CategoryNa CategoryName me Monto ----------- ----------------------------------11 Dairy Products 168,00 42 Grains/Cereals Grains/Ce reals 98,00 72 Dairy Products 174,00 14 Produce 167,40 51 Produce 1696,00 41 Seafood 77,00 51 Produce 1484,00 65 Condiments 252,00 22 Grains/Cereals Grains/Ce reals 100,80 57 Grains/Cereals Grains/Ce reals 234,00 65 Condiments 336,00 20 Confections 2592,00 33 Dairy Products 50,00 ... ................ .....(Continúa) Pivoteando el resultado anterior, usando PIVOT "estático": "estáti co":

--PIVOTEO SELECT ProductID, [Beverages], [Condiments], [Confections], [Dairy Products], [Grains/Cereals], [Meat/Poultry],[Produce],[Seafood] FROM  FROM   ( SELECT P.ProductID, C.CategoryName, (OD.UnitPrice * OD.Quantity) AS Monto FROM Products P INNER  INNER  JOIN dbo.[ dbo.[Order Order Details] OD ON P.ProductID=OD.ProductID INNER  INNER  JOIN Categories C on C.CategoryID=P.CategoryID ) PIV PIVOT (SUM (SUM(Monto) (Monto) FOR CategoryName IN ([Beverages], [Condiments], [Confections], [Dairy Products], [Grains/Cereals], [Meat/Poultry],[Produce],[Seafood])) AS Child Seguro que ya hiciste un copy/paste, je je je, y si aún el nivel de compatibilidad de la base de datos Northwind es 80 o inferior i nferior de seguro te encontrarás con este error: Msg 325, Level 15, State 1, Line 13 Incorrect syntax near 'PIVOT'. 'PIVOT'. You may need to set the compatibility level of the current database to a higher value to enable this feature. See help for the stored st ored procedure sp_dbcmptlevel. sp_dbcmptlevel.   El operador  operador PIVOT sólo trabaja con base de datos cuyo nivel de compatibilidad mayor o igual a 90 (SQL Server 2005).  2005). Northwind es una base de datos creada con SQL Server 2000, y por lo tanto su nivel de compatibilidad es 80. Para solucionar este problema debemos obviamente cambiar dicho nivel de compatibilidad a 90. EXEC dbo.sp_dbcmptlevel @dbname=N'Northwind' @dbname=N'Northwind', , @new_cmptlevel=90

Ahora si, volvemos a ejecutar el query y tendremos (Muestro resultados parciales):

 

ProductID Beverages Condiments Confections Dairy Products Grains/Cer Grains/Cereals eals Meat/Poultry Produce Seafood ------------------------------- --------------------- --------------------- --------------------- -------------------- --------------------- --------------------- --------------------1 14277.60 NULL NULL NULL NULL NULL NULL NULL 2 18559.20 NULL NULL NULL NULL NULL NULL NULL 3 NULL 3080.00 NULL NULL NULL NULL NULL NULL 4 NULL 9424.80 NULL NULL NULL NULL NULL NULL 5 NULL 5801.15 NULL NULL NULL NULL NULL NULL 6 NULL 7345.00 NULL NULL NULL NULL NULL NULL 7 NULL NULL NULL NULL NULL NULL 22464.00 NULL 8 NULL 13760.00 NULL NULL NULL NULL NULL NULL 9 NULL NULL NULL NULL NULL 8827.00 NULL NULL 10 NULL NULL NULL NULL NULL NULL NULL 22140.20 11 NULL 12 NULL 13 NULL 14 NULL 15 NULL 16 NULL 17 5482.20 18 NULL 19 NULL 20 NULL

NULL NULL NULL NULL NULL NULL NULL 8630.40 NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL NULL

NULL NULL NULL NULL NULL 5234.40 NULL NULL 1813.50 NULL NULL NULL NULL NULL NULL 31987.50 NULL NULL NULL NULL

NULL

13902.00

NULL

NULL

12866.80

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

18748.05

NULL

NULL

NULL

NULL

NULL

NULL

NULL

NULL

6159.50

NULL

NULL

23635.80

NULL

NULL

Lograremos lo mismo, esta vez usando PIVOT dinámico:

--pivot dinámico DECLARE @CatPVT AS NVARCHAR( NVARCHAR(MAX MAX), ), @Categorias AS AS   varchar varchar(20) (20) DECLARE @CatID INT INT    SET @CatID=( @CatID=(SELECT SELECT   MIN MIN(CategoryID) (CategoryID) FROM Categories) SET @Categorias = ( SELECT CategoryName FROM Categories WHERE CategoryID = @CatID) SET @CatPVT = N'' N''    WHILE @Categorias IS IS   NOT NOT   NULL NULL    BEGIN  BEGIN   SET @CatPVT = @CatPVT + N',[' N',['+ + @Categorias +N']' +N']'    SET @Categorias = (SELECT (SELECT   TOP TOP(1) (1) CategoryName

3

 

 

FROM Categories WHERE CategoryID > @CatID ORDER  ORDER  BY CategoryID ASC ASC) ) SET @CatID=( @CatID=(SELECT SELECT   MIN MIN(CategoryID) (CategoryID) FROM Categories Where Where    Categoryname=@Categorias) END  END   print @CatPVT SET @CatPVT = SUBSTRING SUBSTRING(@CatPVT, (@CatPVT, 2, LEN(@CatPVT)) print  print  'ok' 'ok'    print @CatPVT DECLARE @sql sql   AS nvarchar( nvarchar(MAX MAX) ) SET @sql = N'SELECT N'SELECT * FROM (SELECT P.ProductID, C.CategoryName, (OD.UnitPrice * OD.Quantity) AS Monto FROM Products P INNER JOIN dbo.[Order Details] OD ON P.ProductID=OD.ProductID INNER JOIN Categories C ON C.CategoryID=P.CategoryID ) PIV PIVOT (SUM(Monto) FOR CategoryName IN ('+ @CatPVT + ')) AS Child'  Child'   EXEC sp_executesql @sql @sql    No debo recordarles que dentro de la implementación de PIVOT dinámico podrían usarse tablas temporables,  variables del tipo TABLE  temporables, TABLE y/o CTEs CTEs  en lugar de emplearse subconsultas, en todo caso los resultados serán los mismos, sin embargo el rendimiento podría ser mejor, y la lógica se simplicaría bastante. En fin, es bastante bastante sencillo, y a ver si en otro post explico algo al respecto. Saludos,

View more...

Comments

Copyright ©2017 KUPDF Inc.
SUPPORT KUPDF