SQL 查询 - 行到列并不是真正的数据透视表

SQL Query - Row to columns not really a pivot

我正在尝试将 ID 的某些字段移动到列中,但它似乎与我找到的所有数据透视示例都不匹配。我能找到的所有示例都使用某种形式的字段值分组。无论字段中的值如何,我都想使用更多的展示位置。我想在不通过代码循环的情况下在查询中执行此操作。

数据源示例(抱歉不知道如何在 post 上格式化 table 所以我使用了代码片段):

+----+--------+--------+
| ID | Field1 | Field2 |
+----+--------+--------+
|  1 | NULL   | NULL   |
|  2 | Jim    | 321    |
|  2 | Jack   | 54     |
|  2 | Sue    | 985    |
|  2 | Gary   | 654    |
|  3 | Herb   | 332    |
|  3 | Chevy  | 10     |
+----+--------+--------+

我尝试生成的结果集:

+----+------+------+-------+------+------+------+
| ID | Col1 | Col2 | Col3  | Col4 | Col5 | Col6 |
+----+------+------+-------+------+------+------+
|  1 | NULL | NULL |       |      |      |      |
|  2 | Jim  | 321  | Jack  |   54 | Sue  |  985 |
|  3 | Herb | 332  | Chevy |   10 |      |      |
+----+------+------+-------+------+------+------+

SQL Fiddle: http://sqlfiddle.com/#!3/a225a/1

;with cte as (
    select id
    , field1
    , field2
    , ROW_NUMBER() over (partition by id order by field1, field2) r 
    from @t   
)
select c1.id
, c1.field1 col1
, c1.field2 col2
, c2.field1 col3
, c2.field2 col4
, c3.field1 col5
, c3.field2 col6
from cte c1
left outer join cte c2 on c2.id = c1.id and c2.r = c1.r + 1
left outer join cte c3 on c3.id = c1.id and c3.r = c1.r + 2
where (c1.r % 3) = 1

说明

ROW_NUMBER() over (partition by id order by field1, field2) r。此行确保我们有一个列从每个 id 开始计数。这使我们能够区分多行。

CTE 用于节省为 c1c2c3 输入相同的语句。

连接确保一行中的所有项目都具有相同的 ID,并且 col1、col3 和 col5(同样适用于 col2、col4 和 col6)的数据取自连续的行。我们正在使用 left outer 联接,因为源 table 中可能没有这些列的行。

where 语句表示为 c1 中的数据取每组 3 的第一行(c2c3 因此是第二行和每组的三分之一,多亏了较早的加入)。

这是一个使用动态 sql 的解决方案,虽然我确信有更好的方法可以解决这个问题。注意,有点痛。首先,它构建要透视的列列表并 select,构建动态 sql 并运行它。

DECLARE @PivotColumns as varchar(max), @SelectColumns as varchar(max), @sql as varchar(max)

SELECT @PivotColumns = ISNULL(@PivotColumns + ',', '') + ColNum,
       @SelectColumns = ISNULL(@SelectColumns + ',', '') + 'NULLIF(' + ColNum + ', ''NULL'') as ' + ColNum
from (select distinct 'Col' + cast(ROW_NUMBER() OVER (partition by id order by id) as varchar) as ColNum 
     from (select id, 
                  isnull(field1,'NULL') as field1,
                  isnull(field2,'NULL') as field2 
            from weirdpivot) cols
unpivot
(
    value
    for col in (field1, field2)
) unpivoted) DistinctColumns

set @sql = '
select id, + ' + @SelectColumns + '
from (select 
        ''Col'' + cast(ROW_NUMBER() OVER (partition by id order by id) as varchar) as colnum
        ,id
        ,value
        from (select id, 
                     isnull(field1,''NULL'') as field1,
                     isnull(field2,''NULL'') as field2 
              from weirdpivot) cols
unpivot
(
    value
    for col in (field1, field2)
) u) unpivoted
pivot
(
    max(value)
    for colnum in (' + @PivotColumns + ')
) p'

exec (@sql)