编写的查询将行拉入列而不进行聚合会使列混乱而不是按顺序列出它们

时间:2018-06-07 20:52:17

标签: sql sql-server sql-server-2014

TL; DR:大约1800个函数被转换为“pivot”列,但它们没有被按顺序调用,因此function_376始终被称为首先然后“随机”其他人而不是所有角色都有那么多功能而且它正在拉动空值。如何让它按顺序拉出函数?

我正在尝试创建一个查询来生成一个结果集,该结果集可以以人类可读的方式轻松复制并粘贴到Excel中。我的查询中的正常结果集提取了两列,即角色和函数,每个不同的对都有一行。我的目标是将所有函数拉到同一行,并为分配给该角色的每个函数都有一列。我得到的最接近的是重新调整我在this answer中找到的脚本,但我遇到的问题是返回结果的查询是混乱的列。它不会在顺序行,函数1,函数2等中返回它们,因此结果是使用NULL,这使输出几乎无用。 @cols查询每次运行时都以一致的顺序将函数拉到一起,但它不是按数字顺序排列,它看起来是随机的。每个Function_N列代表与角色关联的第N个函数,因此如果我可以按顺序构建@cols查询,那么这将有效。

如何重写这个以使输出具有按数字顺序列出的函数,以便结果是左对齐的?

以下所示结果的代码和截图。

IF OBJECT_ID('tempdb.dbo.#roles', 'U') IS NOT NULL
  DROP TABLE #roles;

CREATE TABLE #roles([role] VARCHAR(MAX), [function] VARCHAR(MAX))
Insert into #roles 
select distinct r.r_desc, f.f_desc
from roles r
join role_functions rf on rf_rid = r_id
join Functions f on f_id = rf_fid
where r.r_Active = 'y'


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

select @cols = STUFF((SELECT distinct ',' 
                      + QUOTENAME(rn) 
                    from
                    (
                      select 'function_'+cast(row_number() over(partition by [role] 
                                order by [role]) as varchar(20)) rn
                      from #roles
                    ) src
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT [Role],' + @cols + ' from 
             (
                select [Role], [function],
                  ''function_''+cast(row_number() over(partition by [role] 
                                              order by [role]) as varchar(20)) rn
                from #roles
            ) x
            pivot 
            (
                max([function])
                for rn in (' + @cols + ')
            ) p '

execute(@query)

Image of results

1 个答案:

答案 0 :(得分:0)

我解决了!独特之处是朝着正确方向点头。我还需要另一个临时表来计算最大列数,然后使用变量将其传递给第一个填充函数。见下文:

IF OBJECT_ID('tempdb.dbo.#roles', 'U') IS NOT NULL
  DROP TABLE #roles;


  IF OBJECT_ID('tempdb.dbo.#funtcnt', 'U') IS NOT NULL
  DROP TABLE #funtcnt;



CREATE TABLE #roles([role] VARCHAR(MAX), [function] VARCHAR(MAX))
Insert into #roles 
select distinct r.r_desc, f.f_desc
from roles r
join role_functions rf on rf_rid = r_id
join Functions sf on f_id = rf_fid
where r.r_Active = 'y'

select [role], count([function]) as [count]
INTO #funtcnt
from #roles  group by [role]

declare @topcount varchar(max) = (select top 1 [role] from #funtcnt order by [count] desc)



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

select @cols = STUFF((SELECT  ',' 
                      + QUOTENAME(rn) 
                    from
                    (
                      select 'function_'+cast(row_number() over(partition by [role] 
                                order by [role]) as varchar(20)) rn
                      from #roles where [role] = @topcount
                    ) src
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT [Role],' + @cols + ' from 
             (
                select [Role], [function],
                  ''function_''+cast(row_number() over(partition by [role] 
                                              order by [role]) as varchar(20)) rn
                from #roles
            ) x
            pivot 
            (
                max([function])
                for rn in (' + @cols + ')
            ) p '

execute(@query)