2012-07-31 67 views
4
與扭曲

SQL支點的問題,採取以下表(注年份和月份是分開的):SQL樞紐,形成列

CREATE TABLE [dbo].[tbl_BranchTargets] 
    (
     [BranchID] [varchar](4) NOT NULL , 
     [Year] [smallint] NOT NULL , 
     [Month] [smallint] NOT NULL , 
     [Target] [int] NULL , 
     CONSTRAINT [PK_tbl_BranchTargets] PRIMARY KEY CLUSTERED ([BranchID] ASC, [Year] ASC, [Month] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] 
    ) 
ON [PRIMARY] 

和下面的虛擬數據:

INSERT [dbo].[tbl_BranchTargets] ([BranchID], [Year], [Month], [Target]) VALUES (N'001', 2012, 4, 1) 
INSERT [dbo].[tbl_BranchTargets] ([BranchID], [Year], [Month], [Target]) VALUES (N'001', 2012, 5, 117) 
INSERT [dbo].[tbl_BranchTargets] ([BranchID], [Year], [Month], [Target]) VALUES (N'001', 2012, 6, 233) 
INSERT [dbo].[tbl_BranchTargets] ([BranchID], [Year], [Month], [Target]) VALUES (N'001', 2012, 7, 386) 
INSERT [dbo].[tbl_BranchTargets] ([BranchID], [Year], [Month], [Target]) VALUES (N'003', 2012, 4, 2) 
INSERT [dbo].[tbl_BranchTargets] ([BranchID], [Year], [Month], [Target]) VALUES (N'003', 2012, 6, 234) 
INSERT [dbo].[tbl_BranchTargets] ([BranchID], [Year], [Month], [Target]) VALUES (N'003', 2012, 7, 387) 

我怎麼會給出假數據模型是這樣的(注意的年份和月份鍵列合併爲YYYYMM):

Raw Data

到這一點:

Expected Output

注意分支5月3日失蹤的進入,這就需要爲空來處理。例如,在我們的12個月中,一個分支可能只有一個目標,所以其他月份都需要爲空。我已經看着PIVOT()和笨重的遊標選項,但我很難找到一個快速的最佳實踐方式,我假設我需要實現一些動態的SQL + PIVOT() - 但不能相當讓我感到頭痛。

我知道,動態樞軸您首先確定列名(我認爲),我可以做到這一點,如下所示:

DECLARE @Columns AS NVARCHAR(MAX); 
DECLARE @StrSQL AS NVARCHAR(MAX); 

SET @Columns = STUFF((SELECT DISTINCT 
          ',' + QUOTENAME(CONVERT(VARCHAR, c.YEAR) + RIGHT('00' + CONVERT(VARCHAR, c.MONTH), 2)) 
        FROM  tbl_BranchTargets c 
    FOR   XML PATH('') , 
         TYPE 
      ).value('.', 'NVARCHAR(MAX)'), 1, 1, '') 

但如何執行樞軸有點超出我(因爲我基本上合併到關鍵列來創建最終列) - 我需要合併數據,然後再嘗試將YYYY + MM定義爲1列中的值的數據透視表。

(我使用SQL Server 2008 R2)

回答

4

你非常接近最終答案。您可以使用PIVOT類似於以下(見SQL Fiddle with Demo):

DECLARE @Columns AS NVARCHAR(MAX) 
DECLARE @StrSQL AS NVARCHAR(MAX) 

SET @Columns = STUFF((SELECT DISTINCT 
          ',' + QUOTENAME(CONVERT(VARCHAR(4), c.YEAR) + RIGHT('00' + CONVERT(VARCHAR(2), c.MONTH), 2)) 
        FROM  tbl_BranchTargets c 
    FOR   XML PATH('') , 
         TYPE 
      ).value('.', 'NVARCHAR(MAX)'), 1, 1, '') 

set @StrSQL = 'SELECT branchid, ' + @Columns + ' from 
      (
       select branchid 
        , target 
        , CONVERT(VARCHAR(4), [YEAR]) + RIGHT(''00'' + CONVERT(VARCHAR(2), [MONTH]), 2) dt 
       from tbl_BranchTargets 
      ) x 
      pivot 
      (
       sum(target) 
       for dt in (' + @Columns + ') 
      ) p ' 


execute(@StrSQL) 

這將創建一個你想在執行時間列的列表。

+0

只需將GROUP BY和ORDER BY添加到FOR XML,完美地工作,歡呼 – HeavenCore 2012-07-31 14:45:22

+0

幾乎在同一時間幾乎完全相同的答案:-)。我會在你的'CAST'上加上varchar的長度,它是一個很好的習慣,總是使用長度明確的'VARCHAR'。 – Lamak 2012-07-31 14:49:46

+0

@Lamak非常真實,謝謝指出。 :) – Taryn 2012-07-31 14:51:18

3

你有兩個問題 - 建設期,並旋轉

此生成周期...

declare @strPeriod nvarchar(1000) 
select @strPeriod=N'' 
select @strPeriod = @strPeriod + ', ['+YearMonth +']' 
from 
(
    select distinct convert(varchar(4),tbl_BranchTargets.Year) 
    + right('0'+convert(varchar(2),tbl_BranchTargets.Month),2) as YearMonth 
    from tbl_BranchTargets 
) src 

select @strPeriod = substring(@strPeriod, 3,LEN(@strPeriod)) 

而且這樣做的樞軸點

declare @sql nvarchar(4000) 

select @sql = N'select * from 
    (select BranchID, convert(varchar(4),tbl_BranchTargets.Year)+right(''0''+ 
    convert(varchar(2),tbl_BranchTargets.Month),2) as YearMonth, Target from tbl_BranchTargets) 
    src 
    PIVOT 
    (sum(target) for YearMonth in ('[email protected]+'))p' 

exec (@sql) 
4

您已經很近了。試試這個:

DECLARE @Columns AS NVARCHAR(MAX) 
DECLARE @StrSQL AS NVARCHAR(MAX) 

SET @Columns = STUFF((SELECT DISTINCT 
          ',' + QUOTENAME(CONVERT(VARCHAR(4), c.YEAR) + RIGHT('00' + CONVERT(VARCHAR(2), c.MONTH), 2)) 
        FROM  tbl_BranchTargets c 
    FOR   XML PATH('') , 
         TYPE 
      ).value('.', 'NVARCHAR(MAX)'), 1, 1, '') 

SET @StrSQL = ' 
SELECT * 
FROM (SELECT BranchId, 
      CONVERT(VARCHAR(4), [YEAR]) + RIGHT(''00'' + CONVERT(VARCHAR(2), [MONTH]), 2) YearMonth, 
      Target 
     FROM [dbo].[tbl_BranchTargets]) T 
PIVOT(MIN(Target) FOR YearMonth IN ('[email protected]+')) AS PT' 

EXEC(@StrSQL) 

Here是一個sqlfiddle查看結果。