2009-06-03 50 views
14

Sto lavorando con una tabella in cui sono presenti più righe che ho bisogno di ruotare in colonne. Quindi il perno è la soluzione perfetta per questo, e funziona bene quando tutto ciò di cui ho bisogno è un campo. Devo restituire diversi campi in base al pivot. Qui è il codice pseudo con specifiche spogliato fuori:Pivot a più colonne in 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 sintassi di cui sopra funziona brillantemente, ma cosa devo fare quando ho bisogno di ottenere informazioni aggiuntive trovato in field3, Campo4 ....?

+2

Esattamente quello che devi avere? –

+0

Provato, funziona bene per me (3 ° approccio nel blog). http://dba.stackexchange.com/questions/65786/query-pivot-multiple-columns-variable-number-of-rows – JayaPrakash

risposta

11

riscrittura utilizzando MAX (caso ...) e 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 

Da lì si possono aggiungere in field3, Campo4, ecc

+0

Quello che ho finito è stato usare le istruzioni CASe in un CTE per popolare questa tabella derivata, che ho aggiunto a criteri aggiuntivi. Ecco il CTE: – websch01ar

+0

Con cteSec come ( \t SELEZIONA \t vSec.ID, \t --Secretary 1 ----------------------- - \t MAX ( \t \t CASO vSec.RowID \t \t QUANDO 1 ALLORA vSec.field1 \t \t ELSE '' \t \t END \t) [SEC_OfficePhone1], \t MAX ( \t \t CASE vSec.RowID \t \t QUANDO 1 POI vSec.field2 \t \t ELSE '' \t \t END \t) [SEC_OfficeFax1], \t \t DA \t ( \t --Questo SARÀ INTERNA QUERY (assegna righe segretari) \t SELEZIONE TOP 100 PERCENT \t \t campo1, campo2, ID \t \t (ROW_NUMBER() OVER (partizione DA vs.ID ORDER BY vs.ID2)) rowid \t DA tblname vs \t ORDER BY vs.ID, ID2 \t) VSEC \t GROUP BY \t vSec.ID ) – websch01ar

+0

Così, attraverso questo metodo che ho inserito il numero di colonne che mi aspetto. Generalmente preferirei farlo dinamicamente, poiché è destinato a cambiare. Ma come azienda, ci stiamo concentrando sulla riduzione delle spese generali, quindi non vedo la necessità di più di quattro segretari per capo ... Ti sto dando credito perché il tuo post mi ha portato a scrivere il caso 20 dichiarazioni. Funziona come un incantesimo con una risposta inferiore al secondo. – websch01ar

1

Non sono sicuro se si sta utilizzando MS SQL Server, ma se si è in corso ... Si consiglia di dare un'occhiata alla funzionalità CROSS APPLY del motore. Fondamentalmente ti permetterà di applicare i risultati di una UDF con valori di tabella a un set di risultati. Ciò richiederebbe di inserire la query pivot in un set di risultati con valori di tabella.

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

+0

-1 Impossibile vedere la relazione con la domanda – Andomar

+0

La domanda è contrassegnata e denominata come T-SQL . Questo è il dialetto MS .... – RolandTumble

+0

È anche il dialetto Sybase. –

1

avvolgere l'istruzione SQL con qualcosa come:

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

Dovrebbe comprimere i risultati in una riga, raggruppato sul campo1.

1

Il trucco per fare più perni su un row_number è modificare quella sequenza numero di riga per memorizzare sia la sequenza ed il numero di campo. Ecco un esempio che fa ciò che vuoi con più istruzioni 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