Maison >base de données >tutoriel mysql >Comment générer dynamiquement des colonnes dans SQL à l'aide de la fonction PIVOT ?

Comment générer dynamiquement des colonnes dans SQL à l'aide de la fonction PIVOT ?

Susan Sarandon
Susan Sarandonoriginal
2025-01-09 15:42:45235parcourir

How to Dynamically Generate Columns in SQL Using the PIVOT Function?

Génération dynamique de colonnes en SQL à l'aide de la fonction PIVOT

Cet article aborde le défi de la création dynamique de colonnes en SQL pour représenter différents types de récompenses dans une base de données de récompenses clients. Les types de récompenses ne sont pas fixes et peuvent changer au fil du temps. Nous explorerons des solutions utilisant la fonction SQL PIVOT, démontrant des approches statiques et dynamiques, et incluant l'ajout d'une colonne totale pour des résultats complets.

Le problème :

Nous avons des tables de base de données pour les clients, leurs récompenses et les types de récompenses. Les types de récompenses sont dynamiques ; ils peuvent être ajoutés ou supprimés. L'objectif est de générer un ensemble de résultats avec une colonne pour chaque type de récompense, indiquant le nombre de ce type de récompense pour chaque client.

Solution statique (nombre fixe de types de récompenses) :

Si les types de récompenses sont connus à l'avance, une simple requête PIVOT suffit :

<code class="language-sql">SELECT name, [Bronze], [Silver], [Gold], [Platinum], [AnotherOne]
FROM
(
  SELECT c.name, cr.description, r.typeid
  FROM customers c
  LEFT JOIN rewards r ON c.id = r.customerid
  LEFT JOIN customerrewards cr ON r.typeid = cr.typeid
) x
PIVOT
(
  COUNT(typeid)
  FOR description IN ([Bronze], [Silver], [Gold], [Platinum], [AnotherOne])
) p;</code>

Cette requête fonctionne bien, mais seulement si les types de récompense (« Bronze », « Argent », etc.) sont prédéfinis.

Solution dynamique (nombre inconnu de types de récompenses) :

Pour un nombre dynamique de types de récompenses, nous avons besoin de SQL dynamique :

<code class="language-sql">DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT ',' + QUOTENAME(description)
                    FROM customerrewards
                    GROUP BY description, typeid
                    ORDER BY typeid
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)')
        ,1,1,'');

SET @query = 'SELECT name,' + @cols + ' FROM 
             (
                SELECT c.name, cr.description, r.typeid
                FROM customers c
                LEFT JOIN rewards r ON c.id = r.customerid
                LEFT JOIN customerrewards cr ON r.typeid = cr.typeid
            ) x
            PIVOT 
            (
                COUNT(typeid)
                FOR description IN (' + @cols + ')
            ) p;';

EXECUTE(@query);</code>

Ce code construit dynamiquement la requête SQL, en construisant la liste des colonnes à partir de la table customerrewards. Cela permet une adaptation à un certain nombre de types de récompenses.

Ajout d'une colonne Total :

Pour inclure le nombre total de récompenses par client, nous pouvons utiliser la fonction ROLLUP (les versions statiques et dynamiques sont présentées ci-dessous) :

Version statique avec total :

<code class="language-sql">SELECT name, SUM([Bronze]) Bronze, SUM([Silver]) Silver, 
  SUM([Gold]) Gold, SUM([Platinum]) Platinum, SUM([AnotherOne]) AnotherOne
FROM 
(
  SELECT name, [Bronze], [Silver], [Gold], [Platinum], [AnotherOne]
  FROM
  (
    SELECT c.name, cr.description, r.typeid
    FROM customers c
    LEFT JOIN rewards r ON c.id = r.customerid
    LEFT JOIN customerrewards cr ON r.typeid = cr.typeid
  ) x
  PIVOT
  (
    COUNT(typeid)
    FOR description IN ([Bronze], [Silver], [Gold], [Platinum], [AnotherOne])
  ) p
) x
GROUP BY name WITH ROLLUP;</code>

Version dynamique avec Total :

<code class="language-sql">DECLARE @cols AS NVARCHAR(MAX),
    @colsRollup AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX);

SELECT @cols = STUFF((SELECT ',' + QUOTENAME(description) 
                    FROM customerrewards
                    GROUP BY description, typeid
                    ORDER BY typeid
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');

SELECT @colsRollup 
      = STUFF((SELECT ', SUM(' + QUOTENAME(description) + ') AS ' + QUOTENAME(description)
                    FROM customerrewards
                    GROUP BY description, typeid
                    ORDER BY typeid
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'');


SET @query 
          = 'SELECT name, ' + @colsRollup + '
             FROM
             (
                SELECT name,' + @cols + ' FROM 
                 (
                    SELECT c.name, cr.description, r.typeid
                    FROM customers c
                    LEFT JOIN rewards r ON c.id = r.customerid
                    LEFT JOIN customerrewards cr ON r.typeid = cr.typeid
                ) x
                PIVOT 
                (
                    COUNT(typeid)
                    FOR description IN (' + @cols + ')
                ) p 
              ) x1
              GROUP BY name WITH ROLLUP;';

EXECUTE(@query);</code>

Ces exemples SQL dynamiques fournissent une solution robuste et flexible pour générer des rapports avec un nombre variable de colonnes de type de récompense, y compris une colonne de total utile. N'oubliez pas d'adapter les noms des tables et des colonnes pour qu'ils correspondent à votre schéma de base de données spécifique.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn