没有聚合的透视

Mat*_*don 4 t-sql sql-server pivot aggregate-functions

我试图在没有聚合的情况下进行转动,并且遇到了一些障碍.

这是我试图开始工作的示例T-SQL:

declare @optionalFields table (ParentId int, Name nvarchar(50), Value nvarchar(50));
insert into @optionalFields values (1, 'Field1', 'Foo');
insert into @optionalFields values (1, 'Field2', 'Bar');
insert into @optionalFields values (1, 'Field3', '42');
insert into @optionalFields values (2, 'Field1', 'Bar');
insert into @optionalFields values (2, 'Field2', 'Foo');
insert into @optionalFields values (2, 'Field3', '24');

declare @data table (Id int, Name nvarchar(50));
insert into @data values (1, 'Test record 1');
insert into @data values (2, 'Test record 2');

declare @joined table (Id int, Name nvarchar(50), OptionalFieldName nvarchar(50), OptionalFieldValue nvarchar(50));
insert into @joined
select 
     data.Id
    ,data.Name
    ,opt.Name
    ,opt.Value
from @data data
    inner join @optionalFields opt on data.Id = opt.ParentId

declare @cols as nvarchar(max) = 
    stuff((select distinct ',' + quotename(OptionalFieldName) from @joined for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '');

select * into #tmp from @joined
-- just to see that it's returning the expected values (it does)
select
     Id
    ,Name
    ,OptionalFieldName
    ,OptionalFieldValue
    ,row_number() over (partition by Id order by Id) RN 
from #tmp -- this is the FROM clause in the below dynamic-sql query

declare @query as nvarchar(max) = '
    select Id, Name, ' + @cols + '
    from (select Id, Name, OptionalFieldName, OptionalFieldValue, row_number() over (partition by Id order by Id) RN from #tmp) src 
    pivot (max(OptionalFieldName) for RN in (' + @cols + ')) pvt';

execute(@query);
drop table #tmp;
Run Code Online (Sandbox Code Playgroud)

SSMS给了我2个错误:

  • 消息8114,级别16,状态1,行4 错误将数据类型nvarchar转换为bigint.
  • 消息473,级别16,状态1,行4 在PIVOT运算符中提供了错误值"Field1".

"debug"select语句返回:

正如预期的那样,每个

这篇文章(上面的链接)似乎很有希望,但我似乎无法让它工作.我究竟做错了什么?或者这篇文章是完全错误的,我想要做的是不可能的?

我已经看到了许多类似的SO问题,但要么它们涉及可以"正常工作"聚合的全数字字段,要么它们涉及可以作为简单连接实现的已知列 - 我不知道我有什么OptionalFieldName价值观我将选择,并且OptionalFieldValue值是简单无法聚合的字符串,至少是AFAIK.

Tar*_*ryn 5

我有点困惑为什么你试图欺骗这个使用row_number().即使你有字符串值,你仍然可以聚合它 - 你只需要使用maxmin得到结果.

我总是建议首先尝试使用硬编码值编写查询,尤其是在尝试使用动态SQL之前使用PIVOT时.我不确定为什么你不能这样写这样的查询:

select Id, Name, Field1, Field2, Field3
from 
(
  select
     Id
    ,Name
    ,OptionalFieldName
    ,OptionalFieldValue
  from #tmp
) d
pivot
(
  max(OptionalFieldValue)
  for OptionalFieldName in (Field1, Field2, Field3)
) piv;
Run Code Online (Sandbox Code Playgroud)

看演示.

那么如果你真的需要动态SQL,你只需要编写它:

declare @optionalFields table (ParentId int, Name nvarchar(50), Value nvarchar(50));
insert into @optionalFields values (1, 'Field1', 'Foo');
insert into @optionalFields values (1, 'Field2', 'Bar');
insert into @optionalFields values (1, 'Field3', '42');
insert into @optionalFields values (2, 'Field1', 'Bar');
insert into @optionalFields values (2, 'Field2', 'Foo');
insert into @optionalFields values (2, 'Field3', '24');

declare @data table (Id int, Name nvarchar(50));
insert into @data values (1, 'Test record 1');
insert into @data values (2, 'Test record 2');

declare @joined table (Id int, Name nvarchar(50), OptionalFieldName nvarchar(50), OptionalFieldValue nvarchar(50));
insert into @joined
select 
     data.Id
    ,data.Name
    ,opt.Name
    ,opt.Value
from @data data
    inner join @optionalFields opt on data.Id = opt.ParentId

declare @cols as nvarchar(max);
set @cols = stuff((select distinct ',' + quotename(OptionalFieldName) 
                   from @joined
                   for xml path(''), type).value('.', 'nvarchar(max)'), 1, 1, '');

select * into #tmp from @joined

DECLARE @query  AS NVARCHAR(MAX)

set @query = 'SELECT Id, Name,' + @cols + ' 
            from 
             (
                select Id
                  ,Name
                  ,OptionalFieldName
                  ,OptionalFieldValue
                from #tmp
            ) x
            pivot 
            (
                max(OptionalFieldValue)
                for OptionalFieldName in (' + @cols + ')
            ) p '

execute(@query);
Run Code Online (Sandbox Code Playgroud)

见演示.两个版本似乎都给出了您所请求的结果.