2013-04-02 18 views
6

Ho letto decine di soluzioni a problemi di trasposizione simili a quelli che sto per proporre, ma stranamente nessuno che riflette esattamente il mio problema. Sto semplicemente cercando di capovolgere le mie righe in colonne in un semplice set di dati di tipo dashboard.Visualizzazione di colonne come righe in SQL Server 2005

i dati quando tirato da varie tabelle di transazione si presenta così:

DatePeriod PeriodNumberOverall Transactions Customers Visits 

'Jan 2012' 1     100   50   150 
'Feb 2012' 2     200   100   300 
'Mar 2012' 3     300   200   600 

e voglio essere in grado di generare i seguenti:

     Jan 2012 Feb 2012 Mar 2012 

Transactions   100  200  300 
Customers    50   100  200 
Visits    150  300  600 

Le metriche saranno statici (transazioni, Clienti e visite), ma i periodi di data saranno dinamici (IE - più aggiunti come i mesi passano).

Ancora una volta, ho preparato molti esempi che sfruttano le funzioni di pivot, unpivot, store, UNION ALLs, ecc., Ma nulla dove non sto facendo alcuna aggregazione, semplicemente trasponendo letteralmente l'intero output. Ho anche trovato un modo semplice per farlo in Visual Studio 2005 usando una matrice con un elenco incorporato, ma non posso esportare l'output finale in Excel che è un requisito. Qualsiasi aiuto sarebbe molto apprezzato.

+0

Controllo dinamico pivot versione in answert di Bluefeet a http://stackoverflow.com/questions/13372276/simple-way-to-transpose-columns-and-rows-in-sql –

risposta

2

Al fine di ottenere il risultato che si desidera è necessario prima UNPIVOT i dati e poi PIVOT the Valori DatePeriod`.

UNPIVOT trasformerà le colonne multiple di Transactions, Customers e Visits in più righe.Le altre risposte utilizzano lo svuotamento di UNION ALL ma SQL Server 2005 è stato il primo anno supportato dalla funzione UNPIVOT.

La query per UNPIVOT dei dati è:

select dateperiod, 
    col, value 
from transactions 
unpivot 
(
    value for col in (Transactions, Customers, Visits) 
) u 

Vedi Demo. Questo trasforma le vostre colonne attuali in più righe, quindi i dati è simile al seguente:

| DATEPERIOD |   COL | VALUE | 
------------------------------------- 
| Jan 2012 | Transactions | 100 | 
| Jan 2012 | Customers | 50 | 
| Jan 2012 |  Visits | 150 | 
| Feb 2012 | Transactions | 200 | 

Ora, dal momento che i dati sono in righe, è possibile applicare la funzione PIVOT alla colonna DatePeriod:

select col, [Jan 2012], [Feb 2012], [Mar 2012] 
from 
(
    select dateperiod, 
    t.col, value, c.SortOrder 
    from 
    (
    select dateperiod, 
     col, value 
    from transactions 
    unpivot 
    (
     value for col in (Transactions, Customers, Visits) 
    ) u 
) t 
    inner join 
    (
    select 'Transactions' col, 1 SortOrder 
    union all 
    select 'Customers' col, 2 SortOrder 
    union all 
    select 'Visits' col, 3 SortOrder 
    ) c 
    on t.col = c.col 
) d 
pivot 
(
    sum(value) 
    for dateperiod in ([Jan 2012], [Feb 2012], [Mar 2012]) 
) piv 
order by SortOrder; 

Vedere SQL Fiddle with Demo.

Se si dispone di un numero imprecisato di allora che si intende utilizzare SQL dinamico del periodo desiderato Data:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT ',' + QUOTENAME(dateperiod) 
        from transactions 
        group by dateperiod, PeriodNumberOverall 
        order by PeriodNumberOverall 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT col, ' + @cols + ' 
      from 
      (
       select dateperiod, 
        t.col, value, c.SortOrder 
       from 
       (
        select dateperiod, 
        col, value 
        from transactions 
        unpivot 
        (
        value for col in (Transactions, Customers, Visits) 
       ) u 
       ) t 
       inner join 
       (
        select ''Transactions'' col, 1 SortOrder 
        union all 
        select ''Customers'' col, 2 SortOrder 
        union all 
        select ''Visits'' col, 3 SortOrder 
       ) c 
        on t.col = c.col 
      ) x 
      pivot 
      (
       sum(value) 
       for dateperiod in (' + @cols + ') 
      ) p 
      order by SortOrder' 

execute(@query) 

Vedi SQL Fiddle with Demo. Entrambi dare il risultato:

|   COL | JAN 2012 | FEB 2012 | MAR 2012 | 
------------------------------------------------- 
| Transactions |  100 |  200 |  300 | 
| Customers |  50 |  100 |  200 | 
|  Visits |  150 |  300 |  600 | 
+0

Grazie mille per le fantastiche risposte! L'unica domanda che ho rimane è che esiste un modo semplice per ordinare le metriche come le voglio? In tutte e tre le risposte le metriche sono state riordinate in ordine alfa. Grazie ancora! – user2234794

+0

@ user2234794 Vedere la mia modifica, ho aggiornato la mia risposta per includere un ordinamento sulle posizioni iniziali delle colonne – Taryn

+0

Grazie per l'aggiornamento. La "tabella" principale che utilizzerò per trasporre per la mia dashboard non farà parte dello schema - saranno elementi di dati (metriche/campi aggregati) estratti da più tabelle) in una tabella temporanea. C'è un altro modo di fare l'ordine se non sto tirando i miei campi da una singola tabella che esiste nel mio schema? Mi scuso se la domanda è semplice/di base - non sono un esperto di T-SQL da nessuna misura. – user2234794

2

È necessario creare dinamicamente un'istruzione SQL con gli operatori PIVOT e APPLY al volo e quindi eseguire tale comando. Se le tue metriche sono statiche (Transazioni, Clienti e Visite), quindi possiamo usare l'operatore CROSS APPLY con VALORI come sorgente di tabella.

Per SQL Server2008 +

DECLARE @cols nvarchar(max), 
     @query nvarchar(max) 
SELECT @cols = 
    STUFF((SELECT ',' + QUOTENAME(t.DatePeriod) AS ColName        
     FROM dbo.test62 t     
     FOR XML PATH(''), TYPE).value ('.', 'nvarchar(max)'), 1, 1, '')  

SET @query = 
'SELECT * 
    FROM (
     SELECT t.DatePeriod, COALESCE(o.Transactions, o.Customers, o.Visits) AS PvtVals, o.PvtColumns, o.OrderColumns 
     FROM dbo.test62 t CROSS APPLY (
             VALUES(t.Transactions, NULL, NULL, ''Transaction'', 1), 
              (NULL, t.Customers, NULL, ''Customers'', 2), 
              (NULL, NULL, t.Visits, ''Visits'', 3) 
             ) o (Transactions, Customers, Visits, PvtColumns, OrderColumns) 
     ) p 
    PIVOT 
    (  
    MAX(PvtVals) FOR DatePeriod IN (' + @cols + ') 
    ) AS pvt 
    ORDER BY pvt.OrderColumns ' 
EXEC(@query) 

Risultato:

PvtColumns Jan 2012 Fed 2012 Mar 2012 
Transaction 100  200  300 
Customers 50  100  200 
Visits  150  300  600 

Demo SQLFiddle

Per SQL Server 2005

DECLARE @cols nvarchar(max), 
     @query nvarchar(max) 
SELECT @cols = 
    STUFF((SELECT ',' + QUOTENAME(t.DatePeriod) AS ColName        
     FROM dbo.test62 t     
     FOR XML PATH(''), TYPE).value ('.', 'nvarchar(max)'), 1, 1, '')  

SET @query = 
'SELECT * 
    FROM (
     SELECT t.DatePeriod, COALESCE(o.Transactions, o.Customers, o.Visits) AS PvtVals, o.PvtColumns, o.OrderColumns 
     FROM dbo.test62 t CROSS APPLY (
             SELECT t.Transactions, NULL, NULL, ''Transaction'', 1 
             UNION ALL 
             SELECT NULL, t.Customers, NULL, ''Customers'', 2 
             UNION ALL 
             SELECT NULL, NULL, t.Visits, ''Visits'', 3 
             ) o (Transactions, Customers, Visits, PvtColumns, OrderColumns) 
     ) p 
    PIVOT 
    (  
    MAX(PvtVals) FOR DatePeriod IN (' + @cols + ') 
    ) AS pvt 
    ORDER BY pvt.OrderColumns' 
EXEC(@query) 
+0

+1 per CROSS APPLY;) – ljh

+1

'CROSS APPLY ... VALUES' non funziona nel 2005. È possibile utilizzare' CROSS APPLY (SELEZIONA t.Transactions, NULL, NULL, '' Transaction '' UNION ALL SELECT NULL, t . Clienti, NULL, '' Clienti '' UNIONE TUTTI ...) 'anche se –

+0

Grazie Martin per un chiarimento!;) Risposta aggiornata. BTW, se utilizzare CROSS APPLY (SELEZIONA Transazioni, Clienti, Visite, PvtColumns FROM (VALORI (t.Transactions, NULL, NULL, '' Transaction ''), (NULL, t.Customers, NULL, '' Clienti ''), (NULL, NULL, t.Visits, '' Visits '')) x (Transazioni, Clienti, Visite, PvtColumns)) o ... funzionerà? –

1

Se è possibile sapere quante diverso periodo data in anticipo, quindi è possibile utilizzare interrogazione fissa come segue:


;with CTE_UNIONTable 
as 
(
select [DatePeriod],[PeriodNumberOverall],[Transactions] as [value], 'Transactions' as subType from table1 
UNION ALL 
select [DatePeriod],[PeriodNumberOverall],[Customers] as [value], 'Customers' as subType from table1 
UNION ALL 
select [DatePeriod],[PeriodNumberOverall],[Visits] as [value], 'Visits' as subType from table1 
), CTE_MiddleResult 
as 
(
select * from CTE_UNIONTable 
    pivot 
    (
     max(value) 
     for DatePeriod in ([Jan 2012],[Feb 2012],[Mar 2012]) 
    ) as P 
    ) 
select SubType, max([Jan 2012]) as [Jan 2012] ,max([Feb 2012]) as [Feb 2012], max([Mar 2012]) as [Feb 2012] 
from CTE_MiddleResult 
group by SubType 

SQL FIDDLE DEMO

Se il numero di periodo di data è imprevedibile, quindi @Alexander già ha dato la soluzione, il codice seguente è solo un secondo parere, invece di utilizzare APPLICABILE, utilizzando UNION ALL


DECLARE @cols nvarchar(max), 
     @query nvarchar (max), 
     @selective nvarchar(max) 
SELECT @cols = 
    STUFF((SELECT ',' + QUOTENAME(t.DatePeriod) AS ColName        
     FROM table1 t     
     FOR XML PATH(''), TYPE).value ('.', 'nvarchar(max)'),1,1,'') 

SELECT @selective = 
    STUFF((SELECT ',MAX(' + QUOTENAME(t.DatePeriod) +') as ' + QUOTENAME(t.DatePeriod) AS ColName        
     FROM table1 t     
     FOR XML PATH(''), TYPE).value ('.', 'nvarchar(max)'),1,1,'') 

set @query = ' 
;with CTE_UNIONTable 
as 
(
select [DatePeriod],[PeriodNumberOverall],[Transactions] as [value], ''Transactions'' as subType from table1 
UNION ALL 
select [DatePeriod],[PeriodNumberOverall],[Customers] as [value], ''Customers'' as subType from table1 
UNION ALL 
select [DatePeriod],[PeriodNumberOverall],[Visits] as [value], ''Visits'' as subType from table1 
), CTE_MiddleResult 
as 
(
select * from CTE_UNIONTable 
    pivot 
    (
     max(value) 
     for DatePeriod in ('[email protected]+') 
    ) as P 
) 
select SubType,' + @selective + ' 
from CTE_MiddleResult 
group by SubType' 

exec(@query) 

SQL FIDDLE DEMO

+0

+1 per unione tutti;) –

+0

Grazie mille per le fantastiche risposte! L'unica domanda che ho rimane è che esiste un modo semplice per ordinare le metriche come le voglio? In tutte e tre le risposte le metriche sono state riordinate in ordine alfa. Grazie ancora! – user2234794

+0

Alla fine puoi aggiungere ORDER BY, ma asc o desc, quale ordine esatto vuoi, forse il codice deve aggiornarsi un po 'in base all'ordine che vuoi. – ljh

Problemi correlati