Показать результат SQL в горизонтальном формате

все, что я хочу, это преобразовать это:

Period  | Department    | Print | Copy
---------------------------------------
201601  | Dept 1        | 10    | 20
201601  | Dept 2        | 20    | 10
201602  | Dept 1        | 30    | 40
201602  | Dept 2        | 40    | 30
201603  | Dept 1        | 50    | 60
201603  | Dept 2        | 60    | 50

в:

Department  | 201601 Print  | 201601 Copy   | 201602 Print  | 201602 Copy   | 201603 Print  | 201603 Copy
------------------------------------------------------------------------------------------
Dept 1      | 10            | 20            | 30            | 40            | 50            | 60
Dept 2      | 20            | 10            | 40            | 30            | 60            | 50

Я пытался построить сценарий с PIVOT но я не знаю, как показать как "печать", так и "копирование" каждого периода в Столбцах. Кроме того, поскольку значения "Period" были бы неизвестны, поэтому я не могу жестко закодировать значение в скрипте.

вот моя попытка:

SELECT [Department]
    ,[201601] AS [201601 Copy]
    ,[201602] AS [201602 Copy]
    ,[201603] AS [201603 Copy]
FROM
    (SELECT [Copy], [Period], [Department] from #tempTable) AS ST
PIVOT
    (SUM([Copy]) FOR [Period] IN ([201601],[201602],[201603])) AS PT

и вот скрипт для создания таблицы с моим образцом данные:

IF OBJECT_ID('tempdb..#tempTable') IS NOT NULL
    DROP TABLE #tempTable
CREATE TABLE #tempTable(
    [Period] varchar(50)
    ,[Department] varchar(50)   
    ,[Print] int
    ,[Copy] int
)
INSERT INTO #tempTable VALUES 
     ('201601', 'Dept 1', 10, 20)
    ,('201601', 'Dept 2', 20, 10)
    ,('201602', 'Dept 1', 30, 40)
    ,('201602', 'Dept 2', 40, 30)
    ,('201603', 'Dept 1', 50, 60)
    ,('201603', 'Dept 2', 60, 50)

Спасибо за любой ответ заранее.

ответ

Я изучил полученные ответы и, наконец, построил следующий скрипт:

DECLARE @sql AS varchar(max);
SELECT @sql = 'SELECT [Department],' + 
    STUFF((
        SELECT DISTINCT
            ',SUM(ISNULL(CASE [Period] WHEN ''' + [Period] + ''' THEN [Print] END, 0)) AS [' + [period] + ' Print]' +
            ',SUM(ISNULL(CASE [Period] WHEN ''' + [Period] + ''' THEN [Copy]  END, 0)) AS [' + [period] + ' Copy]'
        FROM #TempTable
        FOR XML PATH('')
    ), 1, 1, '') +
    'FROM #TempTable 
    GROUP BY [Department]';
PRINT @sql
EXEC(@sql);

4 ответов


можно использовать динамический SQL-запрос.

запрос

declare @sql as varchar(max);
select @sql = 'select [Department],' + stuff((
    select distinct ',max(case [Period] when ' + char(39) + [Period] + char(39) + 
    ' then [Print] end) [' + [period] + ' Print]'
    + ',max(case [Period] when ' + char(39) + [Period] + char(39) + 
    ' then [Copy] end) [' + [period] + ' Copy]'
    from #TempTable
    for xml path('')
), 1, 1, '');

select @sql += ' from #TempTable group by [Department];';
exec(@sql);

другой динамический SQL, который использует pivot.
Но этот использует переменную @Columns для создания строки с именами столбцов.

declare @Columns varchar(max);
set  @Columns = STUFF((SELECT ', ' + QUOTENAME([Period] +' Print') + ', ' + QUOTENAME([Period] +' Copy') FROM  #tempTable GROUP BY [Period] FOR  XML PATH(''), TYPE).value('.', 'NVARCHAR(max)') ,1,1,'');

declare @SQL varchar(max);
set @SQL = 'select *
from (
select [Department], [Period] + '' Print'' as Title, [Print] as Value from #tempTable
union all
select [Department], [Period] + '' Copy'' as Title, [Copy] as Value from #tempTable
) q
pivot (sum(Value) for Title in ('+ @Columns +')) p;';

--select @SQL;
exec (@SQL);

вы можете достичь этого, используя функции ISNULL() и SUM ().

SELECT [Department]
        ,SUM(ISNULL(CASE WHEN [Period]='201601' THEN [Print] END,0)) AS [201601 Print]
        ,SUM(ISNULL(CASE WHEN [Period]='201601' THEN Copy END,0)) AS [201601 Copy]
        ,SUM(ISNULL(CASE WHEN [Period]='201602' THEN [Print] END,0)) AS [201602 Print]
        ,SUM(ISNULL(CASE WHEN [Period]='201602' THEN Copy END,0)) AS [201602 Copy]
        ,SUM(ISNULL(CASE WHEN [Period]='201603' THEN [Print] END,0)) AS [201603 Print]
        ,SUM(ISNULL(CASE WHEN [Period]='201603' THEN Copy END,0)) AS [201603 Copy]               
FROM #tempTable
GROUP BY [Department]

SELECT Department,SUM([201601Print])[201601 Print],SUM([201601Copy])[201601  Copy],SUM([201602Print])[201602 Print],
                 SUM([201602Copy])[201602 Copy],SUM([201603Print])[201603   Print],SUM([201603Copy])[201603 Copy] FROM (
SELECT [Department]
,[201601] AS [201601Copy]
,[201602] AS [201602Copy]
,[201603] AS [201603Copy]
,0 AS [201601Print]
,0 AS [201602Print]
,0 AS [201603Print]
FROM
(SELECT  [Period],[Copy], [Department] from #tempTable) AS ST
PIVOT
(SUM([Copy]) FOR [Period] IN ([201601],[201602],[201603])) AS PT
UNION ALL
SELECT [Department]
,0 AS [201601Copy]
,0 AS [201602Copy]
,0 AS [201603Copy]
,[201601] AS [201601Print]
,[201602] AS [201602Print]
,[201603] AS [201603Print]
FROM
(SELECT  [Period],[Print], [Department] from #tempTable) AS ST
PIVOT
(SUM([Print]) FOR [Period] IN ([201601],[201602],[201603])) AS PT
)A GROUP BY Department