2010-03-31 33 views
8

Tengo una consulta en la que estoy tratando de valores de la fila pivote en nombres de columna y actualmente estoy usando SUM(Case...) As 'ColumnName' declaraciones, así:SQL dinámico para generar nombres de columna?

SELECT 
SKU1, 
SUM(Case When Sku2=157 Then Quantity Else 0 End) As '157', 
SUM(Case When Sku2=158 Then Quantity Else 0 End) As '158', 
SUM(Case When Sku2=167 Then Quantity Else 0 End) As '167' 
FROM 
OrderDetailDeliveryReview 
Group By 
OrderShipToID, 
DeliveryDate, 
SKU1 

La consulta anterior funciona muy bien y me da exactamente lo que necesito. Sin embargo, estoy escribiendo un vistazo a las declaraciones de SUM(Case... mano sobre la base de los resultados de la consulta siguiente:

Select Distinct Sku2 From OrderDetailDeliveryReview 

¿Hay alguna manera, el uso de T-SQL dentro de un procedimiento almacenado, que pueda generar dinámicamente las declaraciones SUM(Case... de la consulta Select Distinct Sku2 From OrderDetailDeliveryReview y luego ejecuta el código SQL resultante?

Respuesta

10

Después de haber respondido a una gran cantidad de éstos en los últimos años mediante la generación de SQL cruzada dinámica de los metadatos, echar un vistazo a estos ejemplos:

SQL Dynamic Pivot - how to order columns

SQL Server 2005 Pivot on Unknown Number of Columns

What SQL query or view will show "dynamic columns"

How do I Pivot on an XML column's attributes in T-SQL

How to apply the DRY principle to SQL Statements that Pivot Months

En su caso particular (con el pivote en lugar de ANSI función PIVOT servidor de SQL 2005):

DECLARE @template AS varchar(max) 
SET @template = 'SELECT 
SKU1 
{COLUMN_LIST} 
FROM 
OrderDetailDeliveryReview 
Group By 
OrderShipToID, 
DeliveryDate, 
SKU1 
' 

DECLARE @column_list AS varchar(max) 
SELECT @column_list = COALESCE(@column_list, ',') + 'SUM(Case When Sku2=' + CONVERT(varchar, Sku2) + ' Then Quantity Else 0 End) As [' + CONVERT(varchar, Sku2) + '],' 
FROM OrderDetailDeliveryReview 
GROUP BY Sku2 
ORDER BY Sku2 

Set @column_list = Left(@column_list,Len(@column_list)-1) 

SET @template = REPLACE(@template, '{COLUMN_LIST}', @column_list) 

EXEC (@template) 
+0

Gracias por su respuesta. He visto muchas respuestas que usan 'COALESCE', pero ¿qué está haciendo exactamente esa función? –

+0

Además, si trato de ejecutar su consulta tal como está, aparece un error en la línea 15: "Sintaxis incorrecta cerca de la palabra clave 'FROM'." Si elimino la coma al final de la línea 14, aparece un mensaje de error en * línea 3 * que dice "Sintaxis incorrecta cerca de 'SUM'" ¿Alguna idea sobre qué está pasando aquí o cómo depurar esto? –

+0

@Cade Roux Ok, modifiqué el código (coloque la coma entre las comillas al final de la línea 14, agregué una línea para recortar la coma de @column_list).Ahora funciona, lo cual es genial, pero no puedo entender lo que está pasando entre las líneas 14 y 17. –

2

Sé que SO el motor de búsqueda no es perfecto, pero su pregunta ha sido respondida en SQL Server PIVOT Column Data.
Ver también Creating cross tab queries and pivot tables in SQL.

+0

@van me enteré de que mis consultas con el prefijo de programación de este tipo, 'Stackoverflow SQL Server Pivot', llego a Bing el sitio del pozo (aunque el "otro" motor legado es bueno: D también) –

+0

FYI para cualquier persona que no lo sepa: suelo usar Google: "sitio: stackoverflow.com sql server dynamic pivot cade roux" para encontrar todas mis respuestas anteriores sobre este (o cualquier) tema. –

1

Por qué hacer esto utilizando nombres de columna codificados duro cuando se puede tirar todo esto de forma dinámica desde cualquier mesa?

Usando UNPIVOT y COALESCE, puedo extraer dinámicamente una lista de columnas de cualquier tabla y valores de columna asociados para cualquier registro en una lista de registros y combinarlos en una lista de nombres de columna con valores por fila. Aquí está el código. Solo ingrese su nombre de base de datos y tabla. La columna/tabla de valores se generará para usted en SQL Server. Tenga en cuenta que para obtener una columna de valores compartidos para las columnas que desea convertir en variante sql o cadenas de texto. Pero es una gran manera de obtener una lista de columnas de muestra de valores con nombres y tipos de columna coincidentes con nuestros ciclos while o cursores. Es bastante rápido:

-- First get a list of all known columns in your database, dynamically... 
DECLARE @COLUMNS nvarchar(max) 
SELECT @COLUMNS = 

CASE 
WHEN A.DATA_TYPE = 'nvarchar' OR A.DATA_TYPE = 'ntext' THEN 
COALESCE(@COLUMNS + ',','') + 'CAST(CONVERT(nvarchar(4000),['+A.[name]+']) AS sql_variant) AS ['+A.[name]+']' 
WHEN A.DATA_TYPE = 'datetime' OR A.DATA_TYPE = 'smalldatetime' THEN 
COALESCE(@COLUMNS + ',','') + 'CAST(CONVERT(nvarchar,['+A.[name]+'],101) AS sql_variant) AS ['+A.[name]+']' 
ELSE 
COALESCE(@COLUMNS + ',','') + 'CAST(['+A.[name]+'] AS sql_variant) AS ['+A.[name]+']' 
END 

FROM 
(
SELECT 
A.name, 
C.DATA_TYPE 
FROM YOURDATABASENAME.dbo.syscolumns A 
INNER JOIN YOURDATABASENAME.dbo.sysobjects B ON B.id = A.id 
LEFT JOIN 
(
SELECT 
COLUMN_NAME, 
DATA_TYPE 
FROM YOURDATABASENAME.INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'YOURTABLENAME' 
) C ON C.COLUMN_NAME = A.name 
WHERE B.name = 'YOURTABLENAME' 
AND C.DATA_TYPE <> 'timestamp' 
) A 
-- Test that the formatted columns list is returned... 
--SELECT @COLUMNS 

-- This gets a second string list of all known columns in your database, dynamically... 
DECLARE @COLUMNS2 nvarchar(max) 
SELECT @COLUMNS2 = COALESCE(@COLUMNS2 + ',','') + '['+A.[name]+']' 
FROM 
(
SELECT 
A.name, 
C.DATA_TYPE 
FROM YOURDATABASENAME.dbo.syscolumns A 
INNER JOIN YOURDATABASENAME.dbo.sysobjects B ON B.id = A.id 
LEFT JOIN 
(
SELECT 
COLUMN_NAME, 
DATA_TYPE 
FROM YOURDATABASENAME.INFORMATION_SCHEMA.COLUMNS 
WHERE TABLE_NAME = 'YOURTABLENAME' 
) C ON C.COLUMN_NAME = A.name 
WHERE B.name = 'YOURTABLENAME' 
AND C.DATA_TYPE <> 'timestamp' 
) A 
-- Test that the formatted columns list is returned... 
--SELECT @COLUMNS2 


-- Now plug in the list of the dynamic columns list into an UNPIVOT to get a Column Name/Column Value list table... 
DECLARE @sql nvarchar(max) 
SET @sql = 
' 
SELECT 
ColumnName,ColumnValue 
FROM 
(
SELECT 
'[email protected]+' 
FROM YOURDATABASENAME.dbo.YOURTABLENAME 
WHERE CHANGE_ID IN (SELECT ChangeId FROM YOURDATABASENAME.dbo.OperatorProcess WHERE OperatorProcessID = 3) 
) AS SourceTable 
UNPIVOT 
(
ColumnValue FOR ColumnName IN ('[email protected]+') 
) AS PivotTable 
' 

EXEC (@sql) 
+0

línea 9 resultados en error: "Nombre de columna inválido 'CHANGE_ID'." – JESii

0
-- Darshankar Madhusudan i can do dynamic columnheading table easly... 
--thanks 
declare @incr int = 1, 
     @col int, 
     @str varchar(max), 
     @tblcrt varchar(max), 
     @insrt varchar(max), 
     set @tblcrt = 'DECLARE @Results table ('   
     set @str = ''  
     set @insrt = '' 
    select @col = max(column_id) From tempdb.sys.all_columns where object_id = object_id('tempdb.dbo.#aaa') 
    while @incr <= @col 
     BEGIN 
      SELECT @STR = @STR +case when @incr = 1 then '''' else ',''' end +rtrim(ltrim(NAME))+'''' FROM TEMPDB.SYS.ALL_COLUMNS WHERE OBJECT_ID = OBJECT_ID('TEMPDB.DBO.#AAA') and column_id = @incr 
      set @tblcrt = @tblcrt + case when @incr = 1 then '' else ',' end + 'Fld'+CAST(@incr as varchar(3)) +' varchar(50)' 
      set @insrt = @insrt + case when @incr = 1 then '' else ',' end + 'Fld'+CAST(@incr as varchar(3)) 
      SET @INCR = @INCR + 1 
     END 
     set @tblcrt = @tblcrt + ')' 
     set @insrt = 'insert into @Results('[email protected]+') values (' + @STR +')' 
     set @tblcrt = @tblcrt+ ';' + @insrt + 'select * from @Results ' 
exec(@tblcrt) 
Cuestiones relacionadas