【问题标题】:Dynamic Pivot Tables MS SQL 2008动态数据透视表 MS SQL 2008
【发布时间】:2013-05-28 14:41:15
【问题描述】:

我正在尝试创建一个动态数据透视表以在不同的列而不是行中获取结果。

这是我用来测试的表

CREATE TABLE [dbo].[Authors](
[Client_Id] [nvarchar](50) NOT NULL,
[Project_Id] [nvarchar](50) NOT NULL,
[Person_Id] [int] NOT NULL,
[Author_Number] [int] NOT NULL,
[Family_Name] [nvarchar](50) NULL,
[First_Name] [nvarchar](50) NULL,
)

INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12345,1,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12345,2,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12346,1,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12346,2,'Giust','Fede')
INSERT INTO Authors (Client_Id, Project_Id, Person_Id, Author_Number, Family_Name, First_Name)
VALUES ('TEST','TEST',12346,3,'Giust','Fede')

到目前为止,我得到了这样的结果

CLIENT_ID   PROJECT_ID  PERSON_ID   AUTHOR_NUMBER   FAMILY_NAME FIRST_NAME
TEST        TEST        12345       1               Giust       Fede
TEST        TEST        12345       2               Ma          Ke
TEST        TEST        12346       1               Jones       Peter
TEST        TEST        12346       2               Davies      Bob
TEST        TEST        12346       3               Richards        Craig

我需要这样的结果,并且是动态的,因为有时我可以有 2 个作者或 10 个作者。

CLIENT_ID   PROJECT_ID  PERSON_ID   FAMILY_NAME_1   FIRST_NAME_1    FAMILY_NAME_2   FIRST_NAME_2        FAMILY_NAME_3   FIRST_NAME_3      
TEST        TEST        12345       Giust           Fede            Ma              Ke

TEST        TEST        12346       Jones           Peter           Davies          Bob                 Richards            Craig

我一直在尝试使用此代码,但不断出错

SQL Fiddle

【问题讨论】:

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


    【解决方案1】:

    这里有一些解决您问题的建议。

    首先,您当前的代码正在取消透视表中的所有列,您只需取消透视Family_NameFirst_Name 列。因此,我不会使用变量来获取此列列表,只需硬编码您需要取消透视的两列。

    然后要获取 PIVOT 的列列表,更改代码以同时使用 Author_number 和列名称为 Family_NameFirst_Name 的字符串:

    select @colsPivot = STUFF((SELECT ',' + QUOTENAME(c.col + '_'+cast(Author_Number as varchar(10))) 
                        from Authors
                        cross apply
                        (
                          select 'Family_Name' col, 1 so union all
                          select 'First_Name', 2
                        ) c
                        group by col, author_number, so
                        order by author_number, so
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    

    这给出了一个列列表:

    |                                                                                     COLUMN_0 |
    ------------------------------------------------------------------------------------------------
    | [Family_Name_1],[First_Name_1],[Family_Name_2],[First_Name_2],[Family_Name_3],[First_Name_3] |
    

    对您的代码进行这些更改,最终查询将是

    DECLARE @colsPivot AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX)
    
    select @colsPivot = STUFF((SELECT ',' + QUOTENAME(c.col + '_'+cast(Author_Number as varchar(10))) 
                        from Authors
                        cross apply
                        (
                          select 'Family_Name' col, 1 so union all
                          select 'First_Name', 2
                        ) c
                        group by col, author_number, so
                        order by author_number, so
                FOR XML PATH(''), TYPE
                ).value('.', 'NVARCHAR(MAX)') 
            ,1,1,'')
    
    
    set @query 
      = 'select Client_id, Project_id, Person_Id, '+@colsPivot+' 
          from
          (
            select Client_id, Project_id, Person_Id, 
              col+''_''+cast(Author_Number as varchar(10)) col, val
            from
            (
              select Client_id, Project_id,
                Person_Id, 
                Author_Number, 
                Family_Name, 
                First_Name
              from Authors
            ) s
            unpivot
            (
              val
              for col in (Family_Name, First_Name)
            ) u
          ) x1
          pivot
          (
            max(val)
            for col in ('+ @colspivot +')
          ) p'
    
    exec(@query)
    

    SQL Fiddle with Demo。这给出了一个结果:

    | CLIENT_ID | PROJECT_ID | PERSON_ID | FAMILY_NAME_1 | FIRST_NAME_1 | FAMILY_NAME_2 | FIRST_NAME_2 | FAMILY_NAME_3 | FIRST_NAME_3 |
    -----------------------------------------------------------------------------------------------------------------------------------
    |      TEST |       TEST |     12345 |         Giust |         Fede |            Ma |           Ke |        (null) |       (null) |
    |      TEST |       TEST |     12346 |         Jones |        Peter |        Davies |          Bob |      Richards |        Craig |
    

    【讨论】:

    • 看起来很有前途!非常感谢这么快的回复!我将在我们的服务器上进行测试,看看我们得到的结果是否有用。我在示例中只粘贴了几列,但源表大约有 30 列。
    • 我怎样才能把它变成一个函数或视图?这可能吗?
    • @FedericoGiust 由于您使用的是动态 SQL,因此它必须位于存储过程中。视图或函数中不允许使用动态 SQL。
    • 有没有办法在视图或函数上做类似的事情,以便我将来可以与其他表进行 JOINS?
    • @FedericoGiust 您是否有数量有限的author_numbers 允许?还是无限的?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多