web-dev-qa-db-fra.com

Est-il possible d'avoir plusieurs pivots en utilisant la même colonne de pivot en utilisant SQL Server

Je suis confronté au défi suivant. J'ai besoin de faire pivoter les données du tableau deux fois sur la même colonne. Voici une capture d'écran des données.

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

Je veux avoir une ligne pour chaque ID d'article contenant à la fois la valeur d'achat et la valeur de vente pour chaque année. J'ai essayé de le faire en sélectionnant deux fois la colonne "année", en la formatant un peu pour que chaque année de vente soit précédée d'un "S" et chaque année d'achat commence par un "P", et en utilisant 2 pivots pour faire pivoter les colonnes de 2 ans . Voici la requête SQL (utilisée dans 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

Le résultat n'est pas exactement ce que j'espérais (voir image ci-dessous):

Actual situation: Too many rows

Comme vous pouvez le voir, il existe toujours plus d'une ligne pour chaque ID d'élément. Existe-t-il un moyen de réduire le nombre de lignes à exactement un par article? Pour que cela ressemble un peu à la capture d'écran Excel ci-dessous?

Desired situation: One row for each item ID

17
Rob Vermeulen

Ma suggestion serait d'appliquer à la fois les fonctions UNPIVOT et PIVOT pour obtenir le résultat.

UNPIVOT transformera les colonnes PurchasingValue et SellingValue en lignes. Une fois cela fait, vous pouvez faire pivoter les données dans votre résultat.

Le code sera:

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;

Voir SQL Fiddle with Demo . Le résultat est:

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

Dans SQL Server 2008+, vous pouvez utiliser CROSS APPLY avec VALUES avec la fonction 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

Voir SQL Fiddle with Demo

24
Taryn

Un moyen simple de faire pivoter plusieurs colonnes consiste à simplement utiliser des expressions d'agrégation (cas).

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]
8
JamieD77

Utilisez un GROUP BY ItemID, avec la fonction d'agrégation SUM (isnull (valeur, 0)) sur chacune des colonnes de résultats.

4
Pieter Geerkens