4

ひねりを加えた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を形成することに注意してください)。

生データ

これに:

期待される出力

5月にブランチ3のエントリが欠落していることに注意してください。これは、nullとして処理する必要があります。たとえば、12か月のうち、ブランチにはそのうちの1つのターゲットしかない可能性があるため、他のすべての月はnullである必要があります。

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

3 に答える 3

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 ('+@Columns+')) AS PT'

EXEC(@StrSQL)

結果を確認するためのsqlfiddleを次に示します。

于 2012-07-31T14:38:23.477 に答える
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)

これにより、実行時に必要な列のリストが作成されます。

于 2012-07-31T14:38:26.573 に答える
3

期間の構築とピボットの 2 つの問題があります。

これにより、期間が構築されます...

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 ('+@strPeriod+'))p' 

exec (@sql)
于 2012-07-31T14:36:37.090 に答える