透视未知列内容

2022-01-22 00:00:00 pivot sql sql-server-2008 sql-server

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

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 演示

我试过了

SQLFiddle demo

I tried

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

但这会返回多行而不是一行,并且由于我不知道 id 我不能使用这种方法.有什么想法吗?

but that returns multiple rows instead of one and since I don't know the id I can't use that approach. Any ideas?

推荐答案

你需要的 SQL 是:

The SQL You would need is:

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;

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

But with unkown content you would need to generate this dynamically:

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;

SQL Fiddle 示例

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

Another way to achieve the same result is:

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 扩展

SQL Fiddle 示例

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

If the order of courses is relevant at all you can just change the order by clause in the ROW_NUMBER function.

相关文章