2010-04-20 8 views
0

J'ai les tables parent/enfant comme ci-dessous.PIVOT/UNPIVOT dans SQL Server 2008

MasterTable:

MasterID, Description 

ChildTable

ChildID, MasterID, Description. 

En utilisant PIVOT/UNPIVOT Comment puis-je obtenir le résultat comme ci-dessous en ligne unique.

si (MASTERID: 1 obtenu x enregistrements enfants)

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

Merci

Répondre

2

ici est un T_SQL, en supposant ceci:

  • Vous ne savez pas combien de colonnes peuvent apparaître dans Les resultats.
  • Les éléments Pivot peuvent varier (c'est pourquoi la première hypothèse).
  • Vous avez besoin de l'ordre spécifique 'ChildId1, ChilDesc1, ChildId2, ChildDesc2 ... asd si jamais'

DECLARE @MaxCountOfChild int

-- 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 

EDIT: Le résultat est le suivant:

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

Cela dépend beaucoup du fait que le nombre de colonnes croisées est corrigé. Si elles le sont, vous pouvez tout simplement faire quelque chose comme:

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 

Il y a aussi une façon d'obtenir des résultats similaires utilisent CASE fonctions. Cependant, si vous souhaitez que le nombre de colonnes de tableau croisé soit déterminé lors de l'exécution, le seul moyen de le faire à l'intérieur de SQL Server consiste à utiliser un SQL dynamique. C'est en dehors du domaine de l'objectif principal de SQL Server qui est de servir des données (par opposition à l'information). Si vous souhaitez un tableau croisé dynamique, je vous recommande de ne pas le faire dans SQL Server, mais d'utiliser un outil de création de rapports ou de créer votre jeu de résultats dans un composant de niveau intermédiaire.

+0

Je ne sais pas que vous pouvez utiliser deux pivots avec un seul résultat de sélection! C'est génial! – Claudia