2013-03-07 23 views
9

Sono di fronte alla seguente sfida. Devo ruotare i dati della tabella due volte sulla stessa colonna. Ecco uno screenshot dei dati.È possibile avere più pivot utilizzando la stessa colonna pivot utilizzando SQL Server

A list of items with a purchasing and a selling value for each year the items were sold

voglio avere una riga per ogni ID oggetto che contiene sia il valore di acquisto ed il valore di vendita per ogni anno. Ho provato a farlo selezionando due volte la colonna "anno", formattandola leggermente in modo che ogni anno di vendita venga preceduta da una "S" e ogni anno di acquisto inizia con una "P" e utilizzando 2 perni ruotano attorno ai 2 anni colonne. Ecco la query SQL (utilizzato in SQL Server 2008):

SELECT [Item ID], 
     [P2000],[P2001],[P2002],[P2003], 
     [S2000],[S2001],[S2002],[S2003] 
FROM 
(

SELECT [Item ID] 
     ,'P' + [Year] AS YearOfPurchase 
     ,'S' + [Year] AS YearOfSelling 

    ,[Purchasing value] 
    ,[Selling value] 
    FROM [ItemPrices] 
) AS ALIAS 

PIVOT 
(
MIN ([Purchasing value]) FOR [YearOfPurchase] in ([P2000],[P2001],[P2002],[P2003]) 
) 
AS pvt 

PIVOT 
(
MIN ([Selling value]) FOR [YearOfSelling] in ([S2000],[S2001],[S2002],[S2003]) 
) 
AS pvt2 

Il risultato non è esattamente quello che speravo (vedi immagine sotto):

Actual situation: Too many rows

Come si può vedere, ci sono ancora più di una riga per ogni ID oggetto. C'è un modo per ridurre il numero di righe a esattamente uno per articolo? In modo che assomigli un po 'allo screenshot di Excel qui sotto?

Desired situation: One row for each item ID

risposta

17

Il mio suggerimento sarebbe di applicare entrambe le funzioni UNPIVOT e PIVOT per ottenere il risultato.

Il UNPIVOT trasforma le colonne PurchasingValue e SellingValue in righe. Una volta fatto, puoi ruotare i dati nel risultato.

Il codice sarà:

select * 
from 
(
    select itemid, 
    case 
     when col = 'PurchasingValue' then 'P' 
     when col = 'SellingValue' then 'S' 
    end + cast(year as varchar(4)) new_col, 
    value 
    from yourtable 
    unpivot 
    (
    value 
    for col in ([PurchasingValue], [SellingValue]) 
) unpiv 
) src 
pivot 
(
    max(value) 
    for new_col in (P2000, P2001, P2002, P2003, 
        S2000, S2001, S2002, S2003) 
) piv; 

Vedi SQL Fiddle with Demo. Il risultato è:

| ITEMID | P2000 | P2001 | P2002 | P2003 | S2000 | S2001 | S2002 | S2003 | 
-------------------------------------------------------------------------- 
|  1 | 1000 | 1100 | 1200 | 1300 | 900 | 990 | 1080 | 1170 | 
|  2 | 500 | 550 | 600 | 650 | 450 | 495 | 540 | 585 | 

In SQL Server 2008+ è possibile utilizzare CROSS APPLY con VALUES con la funzione PIVOT:

select * 
from 
(
    select itemid, 
    col+cast(year as varchar(4)) new_col, 
    value 
    from yourtable 
    cross apply 
    (
    VALUES 
     (PurchasingValue, 'P'), 
     (SellingValue, 'S') 
    ) x (value, col) 
) src 
pivot 
(
    max(value) 
    for new_col in (P2000, P2001, P2002, P2003, 
        S2000, S2001, S2002, S2003) 
) piv 

Vedi SQL Fiddle with Demo

+0

Grazie per il suggerimento unpivot. Questo non mi è passato per la testa (e non sono sicuro se lo sarebbe in futuro :-)) –

+1

@RobVermeulen Sì, la funzione unpivot funziona alla grande. Ho appena aggiornato la mia risposta con una versione che usa anche la croce applicata. Entrambi otterranno lo stesso risultato. – Taryn

+0

La "croce applicata" sarebbe più veloce? –

3

Utilizzare un GROUP BY ItemID, con funzione somma aggregata (isnull (valore 0)) su ciascuno dei risultati colonne.

2

Un modo semplice per ruotare più colonne è quello di basta usare le espressioni Aggrega (caso).

SELECT [Item ID], 
     [P2000] = SUM(CASE WHEN [Year] = 2000 THEN [Purchasing value] END), 
     [P2001] = SUM(CASE WHEN [Year] = 2001 THEN [Purchasing value] END), 
     [P2002] = SUM(CASE WHEN [Year] = 2002 THEN [Purchasing value] END), 
     [P2003] = SUM(CASE WHEN [Year] = 2003 THEN [Purchasing value] END), 
     [S2000] = SUM(CASE WHEN [Year] = 2000 THEN [Selling value] END), 
     [S2001] = SUM(CASE WHEN [Year] = 2001 THEN [Selling value] END), 
     [S2002] = SUM(CASE WHEN [Year] = 2002 THEN [Selling value] END), 
     [S2003] = SUM(CASE WHEN [Year] = 2003 THEN [Selling value] END) 
FROM ItemPrices 
GROUP BY [Item ID]