2010-03-31 95 views
8

我有一個查詢在那裏我試圖樞行值到列名和我目前使用SUM(Case...) As 'ColumnName'語句,就像這樣:動態SQL來生成列名?

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 

上述查詢的偉大工程,給了我正是我需要的。不過,我寫了基於以下查詢的結果SUM(Case...聲明手:

Select Distinct Sku2 From OrderDetailDeliveryReview 

有沒有一種方法,使用存儲過程中的T-SQL,我可以動態生成SUM(Case...聲明從Select Distinct Sku2 From OrderDetailDeliveryReview查詢然後執行生成的SQL代碼?

回答

10

具有生成從元數據動態支點SQL回答了不少,這些多年來,看看這些例子:

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

你的具體情況(使用ANSI支點,而不是SQL Server 2005的PIVOT功能):

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

感謝您的回答。我見過很多使用'COALESCE'的答案,但是這個函數究竟做了什麼? – 2010-03-31 17:51:00

+0

另外,如果我嘗試按原樣運行查詢,則第15行出現錯誤:「關鍵字'FROM'附近的語法錯誤。」如果我在第14行結束時刪除了逗號,那麼我會在*第3行*上得到一條錯誤消息,說「SUM'附近的語法錯誤'」關於這裏發生了什麼或者如何調試的任何想法? – 2010-03-31 17:53:42

+0

@Cade魯好的,我調整的代碼(在放線14的端部的引號內的逗號;添加了一行修剪逗號關閉@column_list的)。現在,它的工作,這是偉大的,但我不知道第14和17行之間發生了什麼。 – 2010-03-31 18:05:33

2

我知道,所以搜索引擎是不完美的,但你的問題已經在SQL Server PIVOT Column Data有了答案。
另見Creating cross tab queries and pivot tables in SQL

+0

@van我發現,通過在前面我的編程查詢這樣的,'StackOverflow上的SQL Server Pivot',我去冰的網站做好了(雖然「其他」傳統發動機好了:D太) – 2010-03-31 17:13:30

+0

FYI的人誰不知道:我通常使用谷歌:「網站:stackoverflow.com SQL服務器動態透視凱德湯汁」來找到這個我以前所有的答案(或任何)的話題。 – 2010-03-31 19:08:19

1

爲什麼這樣做使用硬編碼的列名時,你可以動態地從任何表拉這一切?

使用UNPIVOT和COALESCE,我可以動態地從任何表和關聯列值中爲列表中的任何記錄動態拉列表的列,並將它們按行列結合到列名列表中。這是代碼。只需放入數據庫和表名即可。列/值表將在SQL Server中爲您生成。請記住,要獲取要轉換爲sql變體或文本字符串的列的值的共享列。但是,通過我們的while循環或遊標來獲取具有匹配的列名和類型的值列樣本列表的好方法。它非常快:

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

行9導致錯誤:「無效的列名'CHANGE_ID'。」 – JESii 2013-01-14 17:04:03

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)