Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Tables de jointure et pivot du serveur SQL

Cela devrait fonctionner :

WITH Sales AS (
   SELECT
      S.SaleID,
      S.SoldBy,
      S.SalePrice,
      S.Margin,
      S.Date,
      I.SalePrice,
      I.Category
   FROM
      dbo.Sale S
      INNER JOIN dbo.SaleItem I
         ON S.SaleID = I.SaleID
)
SELECT *
FROM
   Sales
   PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P
;

Ou alternativement :

SELECT
   S.SaleID,
   S.SoldBy,
   S.SalePrice,
   S.Margin,
   S.Date,
   I.Books,
   I.Printing,
   I.DVD
FROM
   dbo.Sale S
   INNER JOIN (
      SELECT *
      FROM
         (SELECT SaleID, SalePrice, Category FROM dbo.SaleItem) I
         PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P
   ) I ON S.SaleID = I.SaleID
;

Ceux-ci ont le même ensemble de résultats et peuvent en fait être traités de la même manière par l'optimiseur de requête, mais peut-être pas. La grande différence entre en jeu lorsque vous commencez à mettre des conditions sur la Sale table—vous devriez tester et voir quelle requête fonctionne le mieux.

Remarque :il est crucial lors de l'utilisation de PIVOT que seules les colonnes qui doivent faire partie de la sortie résultante sont disponibles. C'est pourquoi les deux requêtes ci-dessus ont des sous-requêtes de table dérivées supplémentaires (SELECT ...) afin que seules des colonnes spécifiques soient exposées. Toutes les colonnes disponibles pour être vues par PIVOT qui ne sont pas répertoriés dans l'expression pivot seront implicitement regroupés et inclus dans la sortie finale. Ce ne sera probablement pas ce que vous voulez.

Puis-je suggérer, cependant, que vous effectuiez le pivotement dans la couche de présentation ? Si, par exemple, vous utilisez SSRS, il est assez facile d'utiliser un contrôle matriciel qui fera tout le pivotement pour vous. C'est mieux, car si vous ajoutez une nouvelle Category , vous n'aurez pas à modifier tout votre code SQL !

Il existe un moyen de trouver dynamiquement les noms de colonne à faire pivoter, mais cela implique du SQL dynamique. Je ne le recommande pas non plus comme le meilleur moyen, même si c'est possible.

Une autre façon qui pourrait le travail consisterait à prétraiter cette requête, c'est-à-dire à définir un déclencheur sur la Category table qui réécrit une vue pour contenir toutes les catégories existantes qui existent. Cela résout beaucoup d'autres problèmes que j'ai mentionnés, mais encore une fois, il est préférable d'utiliser la couche de présentation.

Remarque  :Si vos noms de colonnes (qui étaient auparavant des valeurs) comportent des espaces, sont des nombres ou commencent par un nombre, ou ne sont pas des identifiants valides, vous devez les mettre entre crochets comme dans PIVOT (Max(Value) FOR CategoryId IN ([1], [2], [3], [4])) P . Alternativement, vous pouvez modifier les valeurs avant qu'elles n'atteignent le PIVOT une partie de la requête pour ajouter quelques lettres ou supprimer des espaces, de sorte que la liste des colonnes n'ait pas besoin d'être échappée. Pour en savoir plus à ce sujet, consultez les règles relatives aux identifiants dans SQL Server.