【问题标题】:Dynamic pivot with similar column names具有相似列名的动态数据透视
【发布时间】:2015-03-10 14:14:12
【问题描述】:

我正在寻找一种方法将不同数量的行转换为sql server 2008 R2 中的列。我在查询中创建了数据列RANK,因为最终我希望将透视列名称标记为RANK 列中的值。然后,如果我能以某种方式将 STUFF 其他 3 个字段值合并到一个字段中,我将能够在我的后端语言中迭代该行并适当地拆分字段结果。

这是当前的数据集:

我希望枢轴的最终结果产生这样的结果:

我还没有发现任何关于能够以这种“动态”方式进行旋转的信息。任何帮助将不胜感激。

【问题讨论】:

  • AFAIK 如果不在动态 SQL 中构建查询,您将无法生成动态列数。您可能会在游标或 while 循环中构建查询,同时迭代上面的结果
  • 你如何计算Rank?为此,您很可能必须使用Other1Other2 等创建那些Other 值,以便它们是唯一的。完成此操作后,您应该能够旋转这些列名。您将不得不这样做,因为您不能与 PIVOT 内的新列具有相同的名称 - 您需要一些方法来区分每一行。
  • @bluefeet 我绝对可以在OTHER 的末尾添加一个数字,但除非您有想法,否则我的旋转问题仍然存在。你能举例说明你的想法吗?

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


【解决方案1】:

正如我上面提到的,您需要区分每个 Rank 值。您已经说过这是一个计算值,您可以在每个值的末尾添加一个数字。添加该数字后,您仍然需要旋转它。

首先看到这一点的最简单方法是首先编写查询的硬编码版本。

样本数据:

create table yourdata
(
    id int,
    code varchar(50),
    created datetime,
    [rank] varchar(50)
);

insert into yourdata
select 285856, 'J7609', '2015-01-19', 'Principle' union all
select 285856, 'J7613', '2015-01-19', 'Other' union all
select 285856, 'J0456', '2015-01-19', 'Other' union all
select 285856, 'J0694', '2015-01-19', 'Other' union all
select 285856, 'J1885', '2015-01-19', 'Other' union all
select 285856, 'J2060', '2015-01-19', 'Other' union all
select 285856, 'J2930', '2015-01-19', 'Other';

静态查询:

select Principle_1, Other_1, 
    Other_2, Other_3, Other_4,
    Other_5, Other_6
from
(
    -- using row_number to get unique id for each rank
    select 
        data = cast(id as varchar(10)) +' | '+ code +' | '+ convert(varchar(10), created, 112),     
        [rank] = [rank] + '_' +cast(row_number() over(partition by id, [rank] 
                                                        order by id) as varchar(10))
    from yourdata
) d
pivot
(
    max(data)
    for [rank] in (Principle_1, Other_1, Other_2, Other_3, Other_4,
                    Other_5, Other_6)
) p;

现在要动态执行此操作,您将使用列名创建一个 sql 字符串,然后执行该字符串:

DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

select @cols = STUFF((SELECT  ',' + QUOTENAME([rank] + '_' +cast(rn as varchar(10))) 
                    from
                    (
                        select [rank],
                            rn = row_number() over(partition by id, [rank] 
                                                    order by id) 
                        from  yourdata
                    ) d
                    group by [rank], rn
                    order by rn, [rank] desc
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ' + @cols + '
            from 
             (
                select 
                    data = cast(id as varchar(10)) +'' | ''+ code +'' | ''+ convert(varchar(10), created, 112),     
                    [rank] = [rank] + ''_'' +cast(row_number() over(partition by id, [rank] 
                                                                    order by id) as varchar(10))
                from yourdata
            ) x
            pivot 
            (
                max(data)
                for [rank] in (' + @cols + ')
            ) p '

exec sp_executesql @query;

这会给你一个结果:

+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
|        Principle_1        |          Other_1          |          Other_2          |          Other_3          |          Other_4          |          Other_5          |          Other_6          |
+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+
| 285856 | J7609 | 20150119 | 285856 | J7613 | 20150119 | 285856 | J0456 | 20150119 | 285856 | J0694 | 20150119 | 285856 | J1885 | 20150119 | 285856 | J2060 | 20150119 | 285856 | J2930 | 20150119 |
+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+---------------------------+

【讨论】:

  • 这是一个非常酷的解决方案,似乎正是我所需要的。我不一定喜欢需要多个陈述才能完成工作的事实,但我倾向于总是尝试将所有内容都塞进一个陈述中(好或坏)......感谢您的帮助
  • @sadmicrowave 有些事情不能用一个语句来完成。就像您的问题一样,它需要动态 SQL。因此,您至少需要 2 个语句,一个用于生成查询,另一个用于运行它。
猜你喜欢
  • 1970-01-01
  • 2011-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多