2010-04-20 115 views
0

我得到了如下的子/父表。SQL Server 2008中的PIVOT/UNPIVOT

MasterTable:

MasterID, Description 

ChildTable

ChildID, MasterID, Description. 

使用PIVOT/UNPIVOT我怎样才能得到的结果如下单列。

如果(MasterID:1个获得X子记录)

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

感谢

回答

2

这里是一个T_SQL,假设这样的:

  • 你不知道有多少列可能出现在结果。
  • 枢轴元素可以不同(这就是为什么第一个假设)。
  • 您需要的特定顺序 'ChildId1,ChilDesc1,ChildId2,ChildDesc2 ... ASD使以往任何时候'

DECLARE @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 @[email protected] +1 
    SET @[email protected] + '[' +convert(varchar, @Counter)+ '],' 
    SET @[email protected] + '[' +convert(varchar, @Counter)+ '] as ' + convert(varchar, @Counter) + ',' 
    SET @[email protected] + '[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 
1

它很大程度上取决于交叉点列的数量是否固定。如果是这样,那么你可以简单地这样做:

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中执行它,而是使用报表工具或在中间层组件中构建结果集。

+0

我不知道你可以使用两个枢轴与单个选择结果!这太棒了! – Claudia 2010-04-26 15:03:04