【问题标题】:Pivot unknown Column content透视未知列内容
【发布时间】:2013-11-26 09:10:38
【问题描述】:

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

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,所以我不能使用这种方法。有什么想法吗?

【问题讨论】:

  • 这个是什么意思但是不知道之前表格的内容
  • ids 可以是任何东西,我不知道可能的课程名称。也可以是任何东西。
  • 刚看到编辑,课程的顺序是什么?即为什么是地质学课程 2,伦理学课程是 3?
  • @GarethD:顺序无关紧要。我想输出所有课程。我只是将示例输出减少到 3 以避免滚动。

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


【解决方案1】:

您需要的 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 子句即可。

【讨论】:

    【解决方案2】:

    我会使用一个支点。由于您没有关于表格长度的信息,因此它必须是动态的:

    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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-11
      • 1970-01-01
      相关资源
      最近更新 更多