根据 SQL 中的数据将行转换为列

Convert Row to Column based on data in SQL

下图是我的table

下面excel是输出的设计

我的 table 包含每个月的 12 列和一个年列。一个item,可以有多年可用,每个月有数据。

year- itemcode- jan- feb

2014-  pqr-      12-  11

2015-  pqr-      4-    8

我需要生成以下输出。对于可使用多年的物品 输出需要按以下方式列出。

ItemCode- Jan14- Feb14- Mar14-... Dec14- Jan15- Feb15-... Dec15

pqr-        12-   11-                     4-     8-

我怎样才能做到这一点。 谷歌搜索后我尝试了不同的方法。但是我无法获得解决此问题的适当输入。 目前我正在尝试在 SO 中找到的一些解决方案。有人可以提供一些意见将非常有帮助。提前致谢。

假设您有以下 table :

select 'AA' as ItemCode,2014 as year, 23 as Jan, 55 as Feb, 55 as Mar,565 as Apr,656 as May,
343 as Jun,54 as Jul,23 as Aug,66 as Sep,645 as Oct,32 as Nov,66 as Dec
into dbo.test ;
insert into dbo.test select 'AA',2015,554,456,3,54,756,98,2,765,24,876,34,66
union select 'BB',2014,45,56,3,54,756,98,2,765,24,876,34,66
union select 'BB',2015,45,56,3,54,756,98,2,765,24,876,34,66;

使用动态 sql,执行

declare @sql nvarchar(1000);
declare @sql2 nvarchar(1000);
declare @year int;
declare @first_year int;
declare c cursor for select distinct year from dbo.test;
open c;
FETCH NEXT FROM c into @year
if @@FETCH_STATUS = 0
begin
  select @sql='select test'+convert(varchar,@year)+'.ItemCode';
  select @sql = @sql+',test'+CONVERT(varchar,@year)+'.Jan as Jan'+CONVERT(varchar,@year)+',test'
    +CONVERT(varchar,@year)+'.Feb as Feb'+CONVERT(varchar,@year)+',test'
    +CONVERT(varchar,@year)+'.Mar as Mar'+CONVERT(varchar,@year);
  select @sql2='test test'+CONVERT(varchar,@year);
  select @first_year=@year;
end;
FETCH NEXT FROM c into @year
WHILE @@FETCH_STATUS = 0
begin
  select @sql = @sql+',test'+CONVERT(varchar,@year)+'.Jan as Jan'+CONVERT(varchar,@year)+',test'
    +CONVERT(varchar,@year)+'.Feb as Feb'+CONVERT(varchar,@year)+',test'
    +CONVERT(varchar,@year)+'.Mar as Mar'+CONVERT(varchar,@year);
  select @sql2=@sql2+' inner join test test'+CONVERT(varchar,@year)+' on test'+CONVERT(varchar,@year)+'.ItemCode=test'+CONVERT(varchar,@first_year)+'.ItemCode and test'+CONVERT(varchar,@year)+'.year='+CONVERT(varchar,@year);
  FETCH NEXT FROM c into @year
end;
close c;
deallocate c;
select @sql=@sql+' FROM '+@sql2 + ' AND test'+convert(varchar,@first_year)+'.year='+CONVERT(varchar,@year);
print @sql
EXECUTE sp_executesql @sql;

或者,使用标准 SQL,像这样

select test2014.ItemCode,test2014.Jan as Jan2014,test2014.Feb as Feb2014,test2015.Jan as Jan2015,test2015.Feb as Feb2015
from test test2014 inner join test test2015 on test2014.ItemCode=test2015.ItemCode
where test2014.year=2014 and test2015.year=2015;

您需要使用动态 SQL...

基本上假设一个名为 #tbl 的 table(有一点样本数据 - 我只做了 3 个月但延长到 12 个月!)

CREATE TABLE #tbl ([ItemCode] NVARCHAR(20), [Year] INT, Jan INT, Feb INT, Mar INT)
INSERT #tbl ( ItemCode, Year, Jan, Feb, Mar )
VALUES  ( 'pqr', 2014, 12, 11, 7  ), ( 'pqr', 2015, 4, 8, 0  ), 
  ( 'xyz', 2015, 7, 1, 0  ), ( 'abc', 2013, 63, 23, 12  ), ( 'abc', 2015, 63, 23, 12  )

我们想要生成一个看起来像

的查询
SELECT tbase.ItemCode
    , ISNULL(t13.Jan,0) AS 'Jan-13', ISNULL(t13.Feb,0) AS 'Feb-13', ISNULL(t13.Mar,0) AS 'Mar-13'
    , ISNULL(t14.Jan,0) AS 'Jan-14', ISNULL(t14.Feb,0) AS 'Feb-14', ISNULL(t14.Mar,0) AS 'Mar-14'
    , ISNULL(t15.Jan,0) AS 'Jan-15', ISNULL(t15.Feb,0) AS 'Feb-15', ISNULL(t15.Mar,0) AS 'Mar-15'  
FROM
    (SELECT DISTINCT(ItemCode) AS ItemCode FROM #tbl) AS tbase 
    LEFT JOIN (SELECT * FROM #tbl AS t13 WHERE YEAR = 2013) AS t13 ON t13.ItemCode = tbase.ItemCode
    LEFT JOIN (SELECT * FROM #tbl AS t14 WHERE YEAR = 2014) AS t14 ON t14.ItemCode = tbase.ItemCode
    LEFT JOIN (SELECT * FROM #tbl AS t15 WHERE YEAR = 2015) AS t15 ON t15.ItemCode = tbase.ItemCode

结果如下:

ItemCode    Jan-13  Feb-13  Mar-13  Jan-14  Feb-14  Mar-14  Jan-15  Feb-15  Mar-15
abc         63      23      12      0       0       0       63      23      12
pqr         0       0       0       12      11      7       4       8       0
xyz         0       0       0       0       0       0       7       1       0

正如您从查询中看到的那样 - 需要加强的两件事是行 , ISNULL(t13.Jan,0)...LEFT JOIN (SELECT ...

我们可以通过声明 2 个 NVARCHAR(MAX) 变量(一个用于 select,一个用于 from)并在遍历可用年份的同时在 while 循环中构建它们。

比如……

DECLARE @select NVARCHAR(MAX);
DECLARE @from NVARCHAR(MAX);
DECLARE @years TABLE(yr INT);
DECLARE @year INT;
DECLARE @yearName NVARCHAR(2)
INSERT @years
SELECT DISTINCT [Year] FROM #tbl

SELECT @year = MIN(yr) FROM @years
SELECT @yearName = RIGHT(CAST(@year AS NVARCHAR(4)),2)

SELECT @select = 'SELECT tbase.ItemCode'
SELECT @from = 'FROM (SELECT DISTINCT(ItemCode) AS ItemCode FROM #tbl) AS tbase '

WHILE EXISTS (SELECT NULL FROM @years WHERE yr = @year)
BEGIN
    SELECT @yearName = RIGHT(CAST(@year AS NVARCHAR(4)),2)
    SELECT @select = @select + CHAR(13) + CHAR(10) 
        + ', ISNULL(t' + @yearName + '.Jan,0) AS [Jan-' + @yearName + '],' 
        + ' ISNULL(t' + @yearName + '.Feb,0) AS [Feb-' + @yearName + '],'-- +9 more
        + ' ISNULL(t' + @yearName + '.Mar,0) AS [Mar-' + @yearName + '] '  
    SELECT @from = @from + CHAR(13) + CHAR(10) 
        + 'LEFT JOIN (SELECT * FROM #tbl AS t' + @yearName 
        + ' WHERE [Year] = ' + CAST(@year AS NVARCHAR(4)) + ') AS t' + @yearName 
        + ' ON t' + @yearName + '.ItemCode = tbase.ItemCode '

    SELECT @year = @year + 1
END

DECLARE @sql NVARCHAR(MAX)
SELECT @sql = @select + CHAR(13) + CHAR(10) + @from
EXEC (@sql)

您只需将此延长至完整的 12 个月即可!

注意 - 我假设每年至少有 1 个条目。如果你有一个差距,在你的范围中间有一年没有任何条目,你需要对 WHILE 循环做一个小的修改 - 即 WHILE @year <= (SELECT MAX(Year) FROM @years)