2010-03-31 6 views
8

Ho una domanda in cui sto cercando valori di riga pivot in nomi delle colonne e attualmente sto usando SUM(Case...) As 'ColumnName' dichiarazioni, in questo modo:SQL dinamico per generare nomi di colonne?

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 query sopra funziona alla grande e mi dà esattamente quello che mi serve. Comunque, sto scrivendo la SUM(Case... dichiarazioni a mano sulla base dei risultati della query seguente:

Select Distinct Sku2 From OrderDetailDeliveryReview 

c'è un modo, utilizzando T-SQL all'interno di una stored procedure, che posso generare dinamicamente le dichiarazioni SUM(Case... dalla query Select Distinct Sku2 From OrderDetailDeliveryReview e quindi eseguire il codice SQL risultante?

risposta

10

Dopo aver risposto un sacco di questi nel corso degli anni, generando SQL perno dinamico dai metadati, uno sguardo a questi esempi:

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

Nel vostro caso particolare (usando il perno ANSI anziché funzione PIVOT SQL Server 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

Grazie per la risposta. Ho visto molte risposte che usano 'COALESCE', ma cosa sta facendo esattamente questa funzione? –

+0

Inoltre, se provo a eseguire la query così com'è, viene visualizzato un errore nella riga 15: "Sintassi non corretta accanto alla parola chiave" FROM "." Se rimuovo la virgola alla fine della riga 14, ottengo quindi un messaggio di errore su * line 3 * che dice "Sintassi errata vicino a" SUM "" Qualche idea su cosa sta succedendo qui o su come eseguire il debug di questo? –

+0

@Cade Roux Ok, ho ottimizzato il codice (inserire la virgola tra le virgolette alla fine della riga 14, aggiunta una linea per tagliare la virgola di @column_list).Ora funziona, il che è fantastico, ma non riesco a capire cosa succede tra le righe 14 e 17. –

2

So che il motore di ricerca SO non è perfetto, ma la tua domanda ha avuto risposta in SQL Server PIVOT Column Data.
Vedere anche Creating cross tab queries and pivot tables in SQL.

+0

@van ho scoperto che anteponendo le mie domande di programmazione come questo, 'StackOverflow SQL Server Pivot', riesco a Bing il sito ben (anche se l ' "altro" motore eredità è buono: D) –

+0

FYI per tutti quelli che non lo conoscono: di solito uso Google: "sito: stackoverflow.com sql server dynamic pivot cade roux" per trovare tutte le mie risposte precedenti su questo (o altro) argomento. –

1

Perché farlo usando i nomi di colonna hard coded quando si può tirare tutto questo in modo dinamico da qualsiasi tabella?

Utilizzando UNPIVOT e COALESCE, è possibile estrarre dinamicamente un elenco di colonne da qualsiasi tabella e valori di colonna associati per qualsiasi record in un elenco di record e combinarli in un elenco di nomi di colonne con valori per riga. Ecco il codice. Basta inserire il nome del database e della tabella. La tabella colonna/valore verrà generata automaticamente in SQL Server. Tieni presente, per ottenere una colonna di valori condivisa per le colonne che desideri convertire in varianti SQL o stringhe di testo. Ma un ottimo modo per ottenere un elenco di valori di colonne di esempio con nomi e tipi di colonne corrispondenti con i nostri cicli while o cursori. La sua piuttosto veloce:

-- 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

riga 9 restituisce un errore: "Nome colonna non valido '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)