TSQL数据透视问题-寻找更好的方法

TSQL数据透视问题-寻找更好的方法,tsql,sql-server-2012,pivot,dynamic-sql,Tsql,Sql Server 2012,Pivot,Dynamic Sql,这是一个与T-SQL相关的问题。我正在使用SQL Server 2012 我有一张这样的桌子: 我希望有这样的输出: 说明: 对于每个员工,将有一行。员工有一项或多项任务。批次Id指定了这一点。根据批次Id,列名将更改(例如国家1、国家2等) 迄今为止的做法: 按如下方式取消对源表的透视: select EmpId, 'Country ' + cast(BatchId as varchar) as [ColumnName], Country as [ColumnValue

这是一个与T-SQL相关的问题。我正在使用SQL Server 2012

我有一张这样的桌子:

我希望有这样的输出:

说明:

对于每个员工,将有一行。员工有一项或多项任务。批次Id指定了这一点。根据批次Id,列名将更改(例如国家1、国家2等)

迄今为止的做法:

按如下方式取消对源表的透视:

select 
    EmpId, 'Country ' + cast(BatchId as varchar) as [ColumnName], 
    Country as [ColumnValue] 
from 
    SourceTable
UNION
select 
    EmpId, 'Pass ' + cast(BatchId as varchar) as [ColumnName], 
    Pass as [ColumnValue] 
from 
    SourceTable
它以行的形式给出每列的值。然后,可以旋转此结果以获得所需的输出

问题:

  • 有更好的方法吗
  • 目前,我知道将有固定数量的批次,但是,对于未来,如果我想使旋转部件动态化,最好的方法是什么
  • 使用SSIS或SSRS之类的工具,动态处理枢轴是否更容易
有许多可能的解决方案可以实现您想要的(在多列上搜索动态轴心)

DECLARE @cols NVARCHAR(MAX),
        @sql  NVARCHAR(MAX) = '';

;WITH cte(col_name, rn) AS(
SELECT DISTINCT col_name = col_name + CAST(BatchId AS VARCHAR(10)),
       rn = ROW_NUMBER() OVER(PARTITION BY EmpId ORDER BY BatchId)
FROM SourceTable
CROSS APPLY (VALUES ('Country', Country), ('Pass', Pass)) AS c(col_name, val)
)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME(col_name)
                      FROM cte
                      ORDER BY rn /* If column order is important for you */
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');

SET @sql =
 N';WITH cte AS 
   (
       SELECT EmpId, col_name = col_name + CAST(BatchId AS VARCHAR(10)), val
       FROM SourceTable
       CROSS APPLY (VALUES (''Country'', Country), (''Pass'', Pass)) AS c(col_name, val)
   )  
   SELECT *
   FROM cte
   PIVOT
   (
      MAX(val)
      FOR col_name IN (' + @cols + ')
    ) piv';

EXEC(@sql);
警告:我假设Country和Pass列不为NULL


有许多可能的解决方案可以实现您想要的(在多列上搜索动态轴心)

DECLARE @cols NVARCHAR(MAX),
        @sql  NVARCHAR(MAX) = '';

;WITH cte(col_name, rn) AS(
SELECT DISTINCT col_name = col_name + CAST(BatchId AS VARCHAR(10)),
       rn = ROW_NUMBER() OVER(PARTITION BY EmpId ORDER BY BatchId)
FROM SourceTable
CROSS APPLY (VALUES ('Country', Country), ('Pass', Pass)) AS c(col_name, val)
)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME(col_name)
                      FROM cte
                      ORDER BY rn /* If column order is important for you */
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');

SET @sql =
 N';WITH cte AS 
   (
       SELECT EmpId, col_name = col_name + CAST(BatchId AS VARCHAR(10)), val
       FROM SourceTable
       CROSS APPLY (VALUES (''Country'', Country), (''Pass'', Pass)) AS c(col_name, val)
   )  
   SELECT *
   FROM cte
   PIVOT
   (
      MAX(val)
      FOR col_name IN (' + @cols + ')
    ) piv';

EXEC(@sql);
警告:我假设Country和Pass列不为NULL


有许多可能的解决方案可以实现您想要的(在多列上搜索动态轴心)

DECLARE @cols NVARCHAR(MAX),
        @sql  NVARCHAR(MAX) = '';

;WITH cte(col_name, rn) AS(
SELECT DISTINCT col_name = col_name + CAST(BatchId AS VARCHAR(10)),
       rn = ROW_NUMBER() OVER(PARTITION BY EmpId ORDER BY BatchId)
FROM SourceTable
CROSS APPLY (VALUES ('Country', Country), ('Pass', Pass)) AS c(col_name, val)
)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME(col_name)
                      FROM cte
                      ORDER BY rn /* If column order is important for you */
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');

SET @sql =
 N';WITH cte AS 
   (
       SELECT EmpId, col_name = col_name + CAST(BatchId AS VARCHAR(10)), val
       FROM SourceTable
       CROSS APPLY (VALUES (''Country'', Country), (''Pass'', Pass)) AS c(col_name, val)
   )  
   SELECT *
   FROM cte
   PIVOT
   (
      MAX(val)
      FOR col_name IN (' + @cols + ')
    ) piv';

EXEC(@sql);
警告:我假设Country和Pass列不为NULL


有许多可能的解决方案可以实现您想要的(在多列上搜索动态轴心)

DECLARE @cols NVARCHAR(MAX),
        @sql  NVARCHAR(MAX) = '';

;WITH cte(col_name, rn) AS(
SELECT DISTINCT col_name = col_name + CAST(BatchId AS VARCHAR(10)),
       rn = ROW_NUMBER() OVER(PARTITION BY EmpId ORDER BY BatchId)
FROM SourceTable
CROSS APPLY (VALUES ('Country', Country), ('Pass', Pass)) AS c(col_name, val)
)
SELECT @cols = STUFF((SELECT ',' + QUOTENAME(col_name)
                      FROM cte
                      ORDER BY rn /* If column order is important for you */
                      FOR XML PATH(''), TYPE
                     ).value('.', 'NVARCHAR(MAX)') 
                        , 1, 1, '');

SET @sql =
 N';WITH cte AS 
   (
       SELECT EmpId, col_name = col_name + CAST(BatchId AS VARCHAR(10)), val
       FROM SourceTable
       CROSS APPLY (VALUES (''Country'', Country), (''Pass'', Pass)) AS c(col_name, val)
   )  
   SELECT *
   FROM cte
   PIVOT
   (
      MAX(val)
      FOR col_name IN (' + @cols + ')
    ) piv';

EXEC(@sql);
警告:我假设Country和Pass列不为NULL

在SQL中完成它

让SSR使用矩阵为您完成工作。它将为您提供数据透视,而无需创建动态SQL来处理需要了解所有列的可怕限制

对于数据,将EMP ID作为行组,PASS作为列组

在SQL中执行此操作

让SSR使用矩阵为您完成工作。它将为您提供数据透视,而无需创建动态SQL来处理需要了解所有列的可怕限制

对于数据,将EMP ID作为行组,PASS作为列组

在SQL中执行此操作

让SSR使用矩阵为您完成工作。它将为您提供数据透视,而无需创建动态SQL来处理需要了解所有列的可怕限制

对于数据,将EMP ID作为行组,PASS作为列组

在SQL中执行此操作

让SSR使用矩阵为您完成工作。它将为您提供数据透视,而无需创建动态SQL来处理需要了解所有列的可怕限制

对于数据,将EMP ID作为行组,PASS作为列组


您做得很好,取消PIVOT PIVOT子句。如果不知道批处理的确切数量,可以使用动态sql。搜索动态数据透视。这是标准方式。你得到了最大批号,并为此构造了pivot语句。这里的最大循环和游标是最糟糕的解决方案。添加了+1以抵消那些没有好理由(如果他们有好的理由,他们可能会说)否决投票的混蛋。你做得对,取消pivot pivot子句。如果不知道批处理的确切数量,可以使用动态sql。搜索动态数据透视。这是标准方式。你得到了最大批号,并为此构造了pivot语句。这里的最大循环和游标是最糟糕的解决方案。添加了+1以抵消那些没有好理由(如果他们有好的理由,他们可能会说)否决投票的混蛋。你做得对,取消pivot pivot子句。如果不知道批处理的确切数量,可以使用动态sql。搜索动态数据透视。这是标准方式。你得到了最大批号,并为此构造了pivot语句。这里的最大循环和游标是最糟糕的解决方案。添加了+1以抵消那些没有好理由(如果他们有好的理由,他们可能会说)否决投票的混蛋。你做得对,取消pivot pivot子句。如果不知道批处理的确切数量,可以使用动态sql。搜索动态数据透视。这是标准方式。你得到了最大批号,并为此构造了pivot语句。最大循环和游标是这里最糟糕的解决方案。添加了+1以抵消那些没有好理由(如果他们有好的理由,他们可能会说)否决投票的混蛋。谢谢汉诺威Fist。我打算用SSRS解决这个问题@你的答案也很完美。不过,我只能选择一个可以接受的答案,所以很遗憾,我不能接受你的答案。谢谢汉诺威。我打算用SSRS解决这个问题@你的答案也很完美。不过,我只能选择一个可以接受的答案,所以很遗憾,我不能接受你的答案。谢谢汉诺威。我打算用SSRS解决这个问题@你的答案也很完美。不过,我只能选择一个可以接受的答案,所以很遗憾,我不能接受你的答案。谢谢汉诺威。我打算用SSRS解决这个问题@你的答案也很完美。然而,我只能选择一个可以接受的答案,所以很遗憾,我不能接受你的答案。