【问题标题】:PIVOT / UNPIVOT in SQL Server 2008SQL Server 2008 中的 PIVOT / UNPIVOT
【发布时间】:2010-04-20 23:37:30
【问题描述】:

我有如下子/父表。

主表:

MasterID, Description

子表

ChildID, MasterID, Description.

使用 PIVOT / UNPIVOT 如何在单行中获得如下结果。

if (MasterID : 1 got x child records)

MasterID, ChildID1, Description1, ChildID2, Description2....... ChildIDx, Descriptionx

谢谢

【问题讨论】:

    标签: sql-server-2008 pivot unpivot


    【解决方案1】:

    这是一个 T_SQL,假设如下:

    • 您不知道结果中可能出现多少列。
    • Pivot 元素可以变化(这就是第一个假设的原因)。
    • 您需要特定的顺序 'ChildId1, ChilDesc1, ChildId2, ChildDesc2... asd so ever'

    声明 @MaxCountOfChild 整数

    -- Obtaining Maximum times a Master is used by its children
    SELECT TOP 1 @MaxCountOfChild= count(*)
    FROM ChildTable
    GROUP BY MasterID
    order by count(*) DESC
    
    
    --With that number, create a string for the Pivot elements
    --if you want them in the order Id1-Desc1-Id2-Desc2
    DECLARE 
        @AuxforReplacing nvarchar(MAX),
        @ChildIdsandDescs nvarchar(MAX),
        @PivotElements nvarchar(MAX),
        @Counter int,
        @sql nvarchar(MAX)
    
    SET @Counter=0
    SET @AuxforReplacing=''
    SET @ChildIdsandDescs=''
    SET @PivotElements=''
    
    WHILE (@Counter < @MaxCountOfChild)
    begin
        SET @Counter=@Counter +1
        SET @PivotElements=@PivotElements + '[' +convert(varchar, @Counter)+ '],' 
        SET @AuxforReplacing=@AuxforReplacing +  '[' +convert(varchar, @Counter)+ '] as ' + convert(varchar, @Counter) + ','
        SET @ChildIdsandDescs=@ChildIdsandDescs + '[ChildID' + convert(varchar, @Counter)+ '],[ChildDesc' + convert(varchar, @Counter) +'],'
    
    end
    SET @PivotElements=LEFT(@PivotElements, len(@PivotElements)-1)
    SET @ChildIdsandDescs=LEFT(@ChildIdsandDescs, len(@ChildIdsandDescs)-1)
    SET @AuxforReplacing=LEFT(@AuxforReplacing, len(@AuxforReplacing)-1)
    
    
    --print REPLACE(@AuxforReplacing, 'as ', 'as ChildId')
    
    --print @ChildIds
    --print @PivotElements
    
    
    SET @sql = N'
    WITH AuxTable (Masterdesc,ChildId, MasterId,ChildDesc,  NumeroenMaster) 
    AS
    (
    SELECT M.Description as MasterDesc, C.*, RANK() OVER (PARTITION BY M.MasterId ORDER BY M.MasterId, ChildId)
    FROM  MasterTable M
        INNER JOIN ChildTable C
            ON M.MasterId=C.MasterId
    )
    
    SELECT TablaMaster.MasterId,' + @ChildIdsandDescs + '
    FROM 
    (
        SELECT MasterId, ' + REPLACE(@AuxforReplacing, 'as ', 'as ChildId') + '
        FROM (
        SELECT MasterId, NumeroenMaster, ChildId
        FROM AuxTable) P
        PIVOT
        (
        MAX (ChildId)
        FOR NumeroenMaster IN (' + @PivotElements +')
        ) AS pvt) As TablaMaster
    INNER JOIN 
    (
        SELECT MasterId, ' + REPLACE(@AuxforReplacing, 'as ', 'as ChildDesc') + '
        FROM (
        SELECT MasterId, NumeroenMaster, ChildDesc
        FROM AuxTable) P
        PIVOT
        (
        MAX (ChildDesc)
        FOR NumeroenMaster IN (' + @PivotElements +')
        ) AS pvt) As TablaChild
    ON TablaMaster.MasterId= TablaChild.MasterId'
    
    EXEC sp_executesql @sql
    

    编辑:结果是这样的:

    MasterId ChildID1 ChildDesc1 ChildID2 ChildDesc2  ChildID3 ChildDesc3 ChildID4 ChildDesc4
    -------- -------- ---------- -------- ----------- -------- ---------- -------- ---------
    1           1      Child1       2      Child2     NULL        NULL       NULL      NULL
    2           3      Child3       4      Child4      7          Child7      8      Child8
    3           5      Child5       6      Child5     NULL        NULL       NULL      NULL
    
    Asumming this in the table ChildTable:
    ChildId  MasterId  ChildDesc
    -------  --------  ---------
    1      1       Child1
    2      1       Child2
    3      2       Child3
    4      2       Child4
    5      3       Child5
    6      3       Child5
    7      2       Child7
    8      2       Child8
    

    【讨论】:

      【解决方案2】:

      很大程度上取决于交叉表列的数量是否固定。如果是,那么您可以简单地执行以下操作:

      Select ParentDesc
          , [1] As ChildId1
          , [Description1] As ChildDescription1
          , [2] As ChildId2
          , [Description2] As ChildDescription2
          , [3] As ChildId3
          , [Description3] As ChildDescription3
      From    (
              Select C.Id As ChildId, C.Description As ChildDesc, P.Description As ParentDesc
              From ChildItems As C
                  Join ParentItems As P
                      On P.Id = C.ParentId
              ) As C
      Pivot   (
              Count(ChildId)
              For ChildId In([1],[2],[3])
              ) As PVT0
      Pivot   (
              Count(ChildDesc)
              For ChildDesc In([Descripion1],[Descripion2],[Descripion3])
              ) As PVT1
      

      还有一种方法可以使用CASE 函数来实现类似的结果。

      但是,如果您想要在运行时确定交叉表列的数量,那么在 SQL Server 内部执行此操作的唯一方法是使用一些非常动态的 SQL。这超出了 SQL Server 提供数据(而不是信息)的主要目的的范围。如果您需要动态交叉表,我建议您不要在 SQL Server 中执行此操作,而是使用报告工具或在中间层组件中构建您的结果集。

      【讨论】:

      • 我不知道你可以使用两个枢轴和一个选择结果!这太棒了!
      猜你喜欢
      • 2021-12-18
      • 1970-01-01
      • 2010-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多