2009-06-03 11 views
14

Je travaille avec une table où il y a plusieurs lignes dont j'ai besoin de pivoter dans les colonnes. Donc, le pivot est la solution parfaite pour cela, et fonctionne bien quand tout ce dont j'ai besoin est un seul domaine. Je dois retourner plusieurs champs basés sur le pivot. Voici le code de pseudo avec des détails dépouillé:Pivot de plusieurs colonnes dans T-SQL

SELECT 
    field1, 
    [1], [2], [3], [4] 
FROM 
    (
    SELECT 
    field1, 
    field2, 
    (ROW_NUMBER() OVER(PARTITION BY field1 ORDER BY field2)) RowID 
    FROM tblname 
) AS SourceTable 
PIVOT 
    (
    MAX(field2) 
    FOR RowID IN ([1], [2], [3], [4]) 
) AS PivotTable; 

La syntaxe ci-dessus fonctionne avec brio, mais qu'est-ce que je fais quand j'ai besoin pour obtenir des informations supplémentaires trouvée dans field3, field4 ....?

+2

Exactement ce que vous devez avoir? –

+0

J'ai essayé, ça marche bien pour moi (3ème approche dans le blog). http://dba.stackexchange.com/questions/65786/query-pivot-multiple-columns-variable-number-of-rows – JayaPrakash

Répondre

11

Réécriture en utilisant MAX (CASE ...) et GROUP BY:

select 
    field1 
, [1] = max(case when RowID = 1 then field2 end) 
, [2] = max(case when RowID = 2 then field2 end) 
, [3] = max(case when RowID = 3 then field2 end) 
, [4] = max(case when RowID = 4 then field2 end) 
from (
    select 
    field1 
    , field2 
    , RowID = row_number() over (partition by field1 order by field2) 
    from tblname 
) SourceTable 
group by 
    field1 

De là, vous pouvez ajouter à field3, field4, etc.

+0

Ce que j'ai fini par faire était d'utiliser des instructions CASe dans un CTE pour remplir cette table dérivée, que j'ai jointe avec des critères supplémentaires. Voici le CTE: – websch01ar

+0

Avec cteSec comme ( \t SELECT \t vSec.ID, \t --Secretary 1 ----------------------- - \t MAX ( \t \t CASE vSec.RowID \t \t QUAND 1 THEN vSec.field1 \t \t AUTRE '' \t \t END \t) [SEC_OfficePhone1], \t MAX ( \t \t CASE vSec.RowID \t \t QUAND 1 PUIS vSec.field2 \t \t AUTRE '' \t \t END \t) [SEC_OfficeFax1], \t \t DE \t ( \t --Ce SERA la requête interne (il affecte les lignes de secrétaires) \t SELECT TOP 100 de CENT \t \t field1, field2, ID \t \t (ROW_NUMBER() OVER (PARTITION BY vs.ID ORDER BY vs.ID2)) rowid \t DE tblname vs \t ORDER BY vs.ID, ID2 \t) VSEC \t GROUP BY \t vSec.ID ) – websch01ar

+0

Ainsi, à travers cette méthode que j'ai hardcoded le nombre de colonnes que je attends. Je préférerais généralement faire cela dynamiquement, car il est lié à changer. Mais en tant qu'entreprise, nous nous concentrons sur la réduction des frais généraux, donc je ne vois pas le besoin de plus de quatre secrétaires par patron ... Je vous donne le crédit parce que votre poste m'a conduit sur la route de l'écriture de l'affaire 20 déclarations. Cela fonctionne comme un charme avec une réponse sous-seconde. – websch01ar

1

Je ne suis pas sûr si vous utilisez MS SQL Server, mais si vous êtes ... Vous pouvez jeter un oeil à la fonctionnalité CROSS APPLY du moteur. Fondamentalement, il vous permettra d'appliquer les résultats d'une UDF à valeur de table à un ensemble de résultats. Cela vous obligerait à placer votre requête pivot dans un jeu de résultats de valeur table.

http://weblogs.sqlteam.com/jeffs/archive/2007/10/18/sql-server-cross-apply.aspx

+0

-1 Impossible de voir la relation avec la question – Andomar

+0

La question est étiquetée et intitulée T-SQL . C'est le dialecte MS ... – RolandTumble

+0

C'est aussi le dialecte Sybase. –

1

envelopper votre instruction SQL avec quelque chose comme:

select a.segment, sum(field2), sum(field3) 
from (original select with case arguments) a 
group by a.segment 

Il devrait réduire vos résultats en une seule ligne, groupé sur field1.

1

L'astuce pour faire plusieurs pivots sur une row_number est de modifier cette séquence de numéro de ligne pour stocker à la fois la séquence et le numéro de champ. Voici un exemple qui fait ce que vous voulez avec plusieurs instructions PIVOT.

-- populate some test data 
if object_id('tempdb..#tmp') is not null drop table #tmp 
create table #tmp (
    ID int identity(1,1) not null, 
    MainField varchar(100), 
    ThatField int, 
    ThatOtherField datetime 
) 

insert into #tmp (MainField, ThatField, ThatOtherField) 
select 'A', 10, '1/1/2000' union all 
select 'A', 20, '2/1/2000' union all 
select 'A', 30, '3/1/2000' union all 
select 'B', 10, '1/1/2001' union all 
select 'B', 20, '2/1/2001' union all 
select 'B', 30, '3/1/2001' union all 
select 'B', 40, '4/1/2001' union all 
select 'C', 10, '1/1/2002' union all 
select 'D', 10, '1/1/2000' union all 
select 'D', 20, '2/1/2000' --union all 

-- pivot over multiple columns using the 1.1, 1.2, 2.1, 2.2 sequence trick 
select 
    MainField, 
    max([1.1]) as ThatField1, 
    max([1.2]) as ThatOtherField1, 
    max([2.1]) as ThatField2, 
    max([2.2]) as ThatOtherField2, 
    max([3.1]) as ThatField3, 
    max([3.2]) as ThatOtherField3, 
    max([4.1]) as ThatField4, 
    max([4.2]) as ThatOtherField4 
from 
    (
     select x.*, 
      cast(row_number() over (partition by MainField order by ThatField) as varchar(2)) + '.1' as ThatFieldSequence, 
      cast(row_number() over (partition by MainField order by ThatField) as varchar(2)) + '.2' as ThatOtherFieldSequence 
     from #tmp x 
    ) a 
    pivot (
     max(ThatField) for ThatFieldSequence in ([1.1], [2.1], [3.1], [4.1]) 
    ) p1 
    pivot (
     max(ThatOtherField) for ThatOtherFieldSequence in ([1.2], [2.2], [3.2], [4.2]) 
    ) p2 
group by 
    MainField