2013-03-07 12 views
9

Mam do czynienia z następującym wyzwaniem. Muszę obracać dane tabeli dwukrotnie w tej samej kolumnie. Oto zrzut ekranu z danymi.Czy jest możliwe posiadanie wielu osi za pomocą tej samej kolumny przestawnej przy użyciu serwera SQL Server

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

Chcę mieć jeden wiersz dla każdego identyfikatora produktu zawierającego zarówno wartość nabywczą i wartość sprzedaży każdego roku. Próbowałem to zrobić, wybierając dwukrotnie kolumnę "rok", formatując ją tak, aby każdy rok sprzedaży był poprzedzany prefiksem "S", a każdy rok zakupu zaczynał się od "P", a użycie 2 czopów obracało się w ciągu 2 lat kolumny. Oto zapytań SQL (używane w 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 

wynik nie jest dokładnie to, co miałem nadzieję (patrz zdjęcie poniżej):

Actual situation: Too many rows

Jak widać, istnieje wciąż jest więcej niż jeden wiersz dla każdego identyfikatora przedmiotu. Czy istnieje sposób na zmniejszenie liczby wierszy do dokładnie jednego elementu? Aby wyglądało trochę jak zrzut ekranu Excel poniżej?

Desired situation: One row for each item ID

Odpowiedz

17

Moja sugestia to zastosowanie zarówno funkcji UNPIVOT, jak i PIVOT, aby uzyskać wynik.

Kolumny UNPIVOT zamieniają kolumny PurchasingValue i SellingValue w wiersze. Gdy to zrobisz, możesz przestawić dane do swojego wyniku.

Kod będą:

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; 

Zobacz SQL Fiddle with Demo. Wynikiem jest:

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

W SQL Server 2008+ można wykorzystać CROSS APPLY z VALUES wraz z PIVOT funkcję:

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 

Zobacz SQL Fiddle with Demo

+0

Dzięki za sugestię unpivot. To mi nie przyszło do głowy (i nie jestem pewien, czy miałoby to w przyszłości :-)) –

+1

@RobVermeulen Ta funkcja unpivot działa świetnie. Właśnie zaktualizowałem swoją odpowiedź wersją, która również używa "cross apply". Obie uzyskają taki sam wynik. – Taryn

+0

Czy "zastosowanie krzyżowe" byłoby szybsze? –

3

Użyj GROUP BY ItemID z funkcji zbiorczej SUM (ISNULL (wartość, 0)) na każdej z kolumn wyników.

2

Jeden łatwy sposób obracać wiele kolumn jest, aby po prostu użyj wyrażeń Aggregate (Case).

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]