透视未知列内容

时间:2013-11-26 09:10:39

标签: sql sql-server sql-server-2008 pivot

我有以下数据但我不知道之前的表格内容

courses table
-------------
id  | name
-------------
7   | math
99  | geology
4   | ethics
5   | sports
33  | english
29  | math boot camp

我需要输出

course1_id | course1_name | course2_id | course2_name | course3_id | course3_name
         7 | math         |         99 |      geology |          4 |       ethics

SQLFiddle demo

我试过

select case when id = 7 then id end as course1_id, 
       case when id = 7 then name end as course1_name
from courses

但是返回多行而不是一行,因为我不知道id我不能使用这种方法。有什么想法吗?

2 个答案:

答案 0 :(得分:4)

您需要的SQL是:

SELECT  Course1_ID = MAX(CASE WHEN RowNum = 1 THEN ID END),
        Course1_Name = MAX(CASE WHEN RowNum = 1 THEN Name END),
        Course2_ID = MAX(CASE WHEN RowNum = 2 THEN ID END),
        Course2_Name = MAX(CASE WHEN RowNum = 2 THEN Name END),
        Course3_ID = MAX(CASE WHEN RowNum = 3 THEN ID END),
        Course3_Name = MAX(CASE WHEN RowNum = 3 THEN Name END)
FROM    (   SELECT  ID, 
                    Name, 
                    RowNum = ROW_NUMBER() OVER(ORDER BY ID)
            FROM    Courses
        ) C;

但是对于未知内容,您需要动态生成:

DECLARE @SQL NVARCHAR(MAX) = 'SELECT ' + 
                            STUFF(( SELECT  ',Course' + RowNum + '_ID = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN ID END)
                                            ,Course' + RowNum + '_Name = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN Name END)'
                                    FROM    (   SELECT  RowNum = CAST(ROW_NUMBER() OVER(ORDER BY ID) AS VARCHAR(10))
                                                FROM    Courses
                                            ) c
                                    FOR XML PATH(''), TYPE
                                ).value('.', 'NVARCHAR(MAX)'), 1, 1, '') + 
                                ' FROM (    SELECT  ID, 
                                                    Name, 
                                                    RowNum = ROW_NUMBER() OVER(ORDER BY ID)
                                            FROM    Courses
                                        ) C;'

EXECUTE SP_EXECUTESQL @SQL;

<强> Example on SQL Fiddle


实现相同结果的另一种方法是:

DECLARE @SQL NVARCHAR(MAX) = '';
SELECT   @SQL = @SQL + 
                    ',Course' + RowNum + '_ID = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN ID END)
                    ,Course' + RowNum + '_Name = MAX(CASE WHEN RowNum = ' + RowNum + ' THEN Name END)'
FROM    (   SELECT  RowNum = CAST(ROW_NUMBER() OVER(ORDER BY ID) AS VARCHAR(10))
            FROM    Courses
        ) c;

SET @SQL = 'SELECT ' + STUFF(@SQL, 1, 1, '') + '
            FROM (  SELECT  ID, 
                            Name, 
                            RowNum = ROW_NUMBER() OVER(ORDER BY ID)
                    FROM    Courses
                ) c;';

EXECUTE SP_EXECUTESQL @SQL;

这将删除昂贵的XML扩展,以将行连接成列

<强> Example on SQL Fiddle

如果课程顺序完全相同,您只需更改ROW_NUMBER函数中的order by子句。

答案 1 :(得分:0)

我会使用一个支点。因为你没有关于表长度的信息,所以它必须是动态的:

declare @count int;
declare @i int;
declare @p varchar(max) = '';
declare @s varchar(max) = '';

select @count = COUNT(*) from courses;

set @i = 1;
while @i <= @count
begin
  set @p = @p + ', [course'+convert(varchar,@i)+'_id], [course'+convert(varchar,@i)+'_name]';
  set @i = @i+1;
end


set @p = substring (@p,3,len(@p)-2);

set @s = 'select '+@p+'
       from
( select ''course''+convert(varchar,ROW_NUMBER() over (order by convert(int,id)))+''_id'' as rn 
       , courses.id as c
    from courses
   union all
  select ''course''+convert(varchar,ROW_NUMBER() over (order by convert(int,id)))+''_name'' as rn 
       , courses.name as c
    from courses ) as sourcetable
  pivot ( 
    max(c)
    for rn in ('+@p+')
    )  as pivottable';

execute(@s);