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

Création d'un tableau croisé dynamique dynamique avec la fonction QUOTENAME

Dans mon article précédent sur l'opérateur de pivot de base, nous avons vu comment l'opérateur de pivot pouvait être utilisé pour convertir des lignes en colonnes, résultant en des tableaux croisés dynamiques. Nous avons vu qu'il y avait trois étapes principales pour créer un tableau croisé dynamique. La première étape consistait à sélectionner les données de base. La deuxième étape consistait à convertir les données de base en une expression table, et la dernière étape consistait à appliquer un opérateur de pivot aux données temporaires, ce qui a abouti au tableau croisé dynamique.

Jetez un œil à l'exemple ci-dessous.

USE schooldb

SELECT * FROM

(SELECT 
	city,
	total_score
FROM 
	student
)
AS StudentTable
PIVOT(
	AVG(total_score)
	FOR city IN ([London],[Liverpool],[Leeds],[Manchester])
) AS StudentPivotTable

Remarque : Pour créer la base de données et les données factices, consultez l'article précédent sur l'opérateur pivot.

Limites de l'opérateur pivot

Cependant, il existe certaines limitations de l'opérateur de pivot. À l'intérieur de l'opérateur pivot, nous devons spécifier le champ agrégé et les colonnes sur lesquelles nous voulons faire pivoter nos données. Enfin, nous devons également définir les valeurs individuelles des en-têtes de colonne que nous voulons créer.

Si nous exécutions le script de la section précédente, nous obtiendrions le résultat suivant :

[identifiant de table=35 /]

Les en-têtes des colonnes sont les valeurs individuelles à l'intérieur de la colonne de la ville. Nous avons spécifié ces valeurs dans l'opérateur pivot de notre requête.

La partie la plus fastidieuse de la création de tableaux croisés dynamiques consiste à spécifier manuellement les valeurs des en-têtes de colonne. C'est la partie qui est sujette à la plupart des erreurs, en particulier si les données de votre source de données en ligne changent. Nous ne pouvons pas être sûrs que les valeurs que nous avons spécifiées dans l'opérateur pivot resteront dans la base de données jusqu'à ce que nous créons ce tableau croisé dynamique la prochaine fois.

Par exemple, dans notre script, nous avons spécifié Londres, Liverpool, Leeds et Manchester comme valeurs pour les en-têtes de notre tableau croisé dynamique. Ces valeurs existaient dans la colonne Сity de la table des étudiants. Que se passe-t-il si, d'une manière ou d'une autre, une ou plusieurs de ces valeurs sont supprimées ou mises à jour ? Dans de tels cas, null sera renvoyé.

Une meilleure approche serait de créer une requête dynamique qui renverra un ensemble complet de valeurs à partir de la colonne à partir de laquelle vous essayez de générer votre tableau croisé dynamique.

Création d'un tableau croisé dynamique dynamique

Dans cette section, nous verrons comment créer un tableau croisé dynamique dynamique.

Cela signifie que nous n'aurons pas besoin de spécifier manuellement les valeurs de la colonne à partir de laquelle nous essayons de générer notre tableau croisé dynamique. Au lieu de cela, nous allons définir ces valeurs dynamiquement. Pour cela, nous utiliserons la fonction "QUOTENAME".

Comme toujours, assurez-vous d'être bien sauvegardé avant d'expérimenter un nouveau code. Consultez cet article sur la sauvegarde des bases de données MS SQL si vous n'êtes pas sûr.

Fonction QUOTENAME

La fonction « QUOTENAME » formate les résultats sélectionnés. Avant d'expliquer le pivot dynamique, il vaut la peine de regarder un exemple rapide de la fonction "QUOTENAME".

Examinez la requête suivante.

USE schooldb

SELECT QUOTENAME(city)+ ','
FROM student

Par défaut, la fonction "QUOTENAME" place les éléments sélectionnés entre crochets. Le résultat de la requête ci-dessus ressemble à ceci :

[identifiant de table=36 /]

Stocker les noms de colonne dans une variable

Bien que nous ayons placé les valeurs des colonnes entre crochets, nous devons spécifier les valeurs dans l'opérateur pivot dans ce format :

"[Leeds],[Liverpool],[Londres],[Manchester]"

Pour ce faire, nous aurons besoin d'une variable.

USE schooldb

DECLARE @CityNames NVARCHAR(MAX) = ''

SELECT  @CityNames +=   QUOTENAME(city)+ ','
FROM 
(
	SELECT DISTINCT city
	FROM student
) AS CITIES

PRINT @CityNames

Dans la requête ci-dessus, nous avons déclaré une variable "@CityNames" et l'avons initialisée avec une chaîne vide. Ensuite, nous avons utilisé une instruction SELECT pour sélectionner des noms de ville distincts dans la colonne de la ville et les stocker de manière itérative dans la variable « @CityNames ». À chaque itération, une valeur distincte dans la colonne de la ville ainsi qu'une virgule seront ajoutées à la variable "@CityNames".

Ensuite, nous avons imprimé la valeur stockée dans cette variable. Le résultat de la requête ci-dessus ressemblera à ceci :

"[Leeds],[Liverpool],[Londres],[Manchester],"

Si vous regardez la sortie, il y a une virgule après la dernière valeur. Nous n'avons pas besoin de ça.

Supprimer une virgule de fin

Pour supprimer une virgule de fin, nous utiliserons une fonction LEFT qui prend une chaîne comme premier argument. Le deuxième argument est le nombre de caractères à renvoyer à partir de cette chaîne à partir du premier caractère. Examinez la requête suivante :

USE schooldb

DECLARE @CityNames NVARCHAR(MAX) = ''

SELECT  @CityNames +=   QUOTENAME(city)+ ','
FROM 
(
	SELECT DISTINCT city
	FROM student
) AS CITIES

SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)

PRINT @CityNames

Faites attention à cette ligne du script :

SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)

Dans cette ligne du script, nous avons utilisé la fonction LEFT pour obtenir tous les caractères à gauche de la valeur stockée dans la variable "@CityNames", à partir du premier élément. Dans le deuxième argument, nous avons utilisé la fonction LEN pour calculer le nombre d'éléments de valeur stockés dans la fonction "@CityNames" et enfin, nous en avons soustrait 1. Cela supprime la virgule de fin de la chaîne. La sortie ressemblera à ceci :

[Leeds],[Liverpool],[Londres],[Manchester]

Convertir une requête SQL en chaîne

Maintenant, espérons-le, nous pouvons utiliser la variable "@CityNames" dans notre opérateur pivot comme ceci :

PIVOT(
	AVG(total_score)
	FOR city IN ( @CityNames )

Cependant, nous ne pouvons pas utiliser une variable à l'intérieur de notre opérateur de pivot. L'approche alternative consiste à convertir notre requête SQL complète en une chaîne. À l'intérieur de cette chaîne, nous accrocherons notre variable "@CityNames".

USE schooldb

DECLARE @CityNames NVARCHAR(MAX) = ''
DECLARE @Query NVARCHAR(MAX) = '' 

SELECT  @CityNames +=   QUOTENAME(city)+ ','
FROM 
(
	SELECT DISTINCT city
	FROM student
) AS CITIES

SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)

SET @Query =
'SELECT * FROM

(SELECT 
	city,
	total_score
FROM 
	student
)
AS StudentTable
PIVOT(
	AVG(total_score)
	FOR city IN (' + @CityNames +')
) AS StudentPivotTable'

PRINT @Query

Ici, nous avons déclaré une variable "@Query" et stocké notre requête SQL dans cette variable. À l'intérieur de l'opérateur pivot, nous avons concaténé la valeur stockée dans la variable "@CityNames". Pour voir à quoi ressemble la requête exécutée, nous avons imprimé la valeur de la variable "@Query". La requête résultante ressemblera à ceci dans la sortie :

SELECT * FROM

(SELECT 
	city,
	total_score
FROM 
	student
)
AS StudentTable
PIVOT(
	AVG(total_score)
	FOR city IN ([Leeds],[Liverpool],[London],[Manchester])
) AS StudentPivotTable

C'est exactement le type de requête que nous voulons exécuter. Cependant, c'est au format String. La dernière étape consiste à exécuter cette requête SQL stockée sous forme de chaîne de texte. Pour ce faire, nous utiliserons Dynamic SQL.

Exécuter Dynamic SQL

Nous utilisons la procédure intégrée "sp_executesql" pour exécuter du SQL dynamique. Nous allons utiliser cette procédure stockée pour exécuter la requête stockée dans la variable @Query. Notre requête finale qui crée un tableau croisé dynamique ressemble à ceci :

USE schooldb

DECLARE @CityNames NVARCHAR(MAX) = ''
DECLARE @Query NVARCHAR(MAX) = '' 

SELECT  @CityNames +=   QUOTENAME(city)+ ','
FROM 
(
	SELECT DISTINCT city
	FROM student
) AS CITIES

SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)

SET @Query =
'SELECT * FROM

(SELECT 
	city,
	total_score
FROM 
	student
)
AS StudentTable
PIVOT(
	AVG(total_score)
	FOR city IN (' + @CityNames +')
) AS StudentPivotTable'

EXECUTE sp_executesql @Query

Lorsque vous exécutez la requête ci-dessus, vous devriez voir le résultat suivant :

[identifiant de table=37 /]

Cependant, cette fois, nous n'avons pas spécifié manuellement les valeurs des en-têtes du tableau croisé dynamique. Au lieu de cela, les en-têtes ont été calculés dynamiquement, ce qui a donné lieu à un tableau croisé dynamique dynamique.