2010-04-20 100 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