In mijn vorige artikel over de basis-spil-operator, hebben we gezien hoe de pivot-operator kan worden gebruikt om rijen naar kolommen te converteren, wat resulteert in draaitabellen. We zagen dat er drie hoofdstappen waren om een draaitabel te maken. De eerste stap was het selecteren van de basisgegevens. De tweede stap was het converteren van de basisgegevens naar een tabelwaarde-expressie, en de laatste stap omvatte het toepassen van een pivot-operator op de tijdelijke gegevens, wat resulteerde in de draaitabel.
Bekijk het onderstaande voorbeeld.
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
Opmerking: Zie het vorige artikel over de Pivot Operator om de dummy-database en -gegevens te maken.
Beperkingen van Pivot Operator
Er zijn echter bepaalde beperkingen van de pivot-operator. Binnen de pivot-operator moeten we het aggregatieveld en de kolommen specificeren waarop we onze gegevens willen draaien. Ten slotte moeten we ook de individuele waarden instellen voor de kolomkoppen die we willen maken.
Als we het script uit de vorige sectie zouden uitvoeren, zouden we het volgende resultaat krijgen:
[tabel id=35 /]
De koppen van de kolommen zijn de individuele waarden binnen de stadskolom. We hebben deze waarden gespecificeerd in de pivot-operator in onze zoekopdracht.
Het meest vervelende deel van het maken van draaitabellen is het handmatig specificeren van de waarden voor de kolomkoppen. Dit is het gedeelte dat vatbaar is voor de meeste fouten, vooral als de gegevens in uw online gegevensbron veranderen. We kunnen er niet zeker van zijn dat de waarden die we hebben opgegeven in de pivot-operator in de database zullen blijven totdat we deze draaitabel de volgende keer maken.
In ons script hebben we bijvoorbeeld Londen, Liverpool, Leeds en Manchester gespecificeerd als waarden voor koppen van onze draaitabel. Deze waarden stonden in de kolom 'ity' van de studententabel. Wat als een of meer van deze waarden op de een of andere manier worden verwijderd of bijgewerkt? In dergelijke gevallen wordt null geretourneerd.
Een betere benadering zou zijn om een dynamische query te maken die een volledige set waarden retourneert uit de kolom waaruit u uw draaitabel probeert te genereren.
Een dynamische draaitabel maken
In dit gedeelte zullen we zien hoe u een dynamische draaitabel maakt.
Dit betekent dat we de waarden voor de kolom waaruit we onze draaitabel proberen te genereren, niet handmatig hoeven op te geven. In plaats daarvan zullen we deze waarden dynamisch instellen. Hiervoor gebruiken we de functie "QUOTENAME".
Zorg zoals altijd voor een goede back-up voordat u met een nieuwe code gaat experimenteren. Raadpleeg dit artikel over het maken van back-ups van MS SQL-databases als u het niet zeker weet.
QUOTENAME-functie
De functie "QUOTENAME" maakt geselecteerde resultaten op. Voordat we dynamische pivot uitleggen, is het de moeite waard om een snel werkend voorbeeld van de functie "QUOTENAME" te bekijken.
Bekijk de volgende vraag.
USE schooldb SELECT QUOTENAME(city)+ ',' FROM student
Standaard plaatst de functie "QUOTENAME" de geselecteerde items tussen vierkante haken. De uitvoer van de bovenstaande query ziet er als volgt uit:
[tabel id=36 /]
Kolomnamen opslaan in een variabele
Hoewel we de kolomwaarden tussen vierkante haken hebben geplaatst, moeten we de waarden in de pivot-operator in dit formaat specificeren:
“[Leeds],[Liverpool],[Londen],[Manchester]”
Hiervoor hebben we een variabele nodig.
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES PRINT @CityNames
In de bovenstaande query hebben we een variabele "@CityNames" gedeclareerd en geïnitialiseerd met een lege tekenreeks. Vervolgens gebruikten we een SELECT-instructie om verschillende stadsnamen uit de stadskolom te selecteren en deze iteratief op te slaan in de variabele "@CityNames". In elke iteratie wordt een afzonderlijke waarde in de stadskolom samen met een komma toegevoegd aan de variabele "@CityNames".
Vervolgens hebben we de waarde afgedrukt die in deze variabele is opgeslagen. Het resultaat van de bovenstaande zoekopdracht ziet er als volgt uit:
“[Leeds],[Liverpool],[Londen],[Manchester],”
Als je naar de uitvoer kijkt, staat er een komma achter de laatste waarde. Dat hebben we niet nodig.
Een laatste komma verwijderen
Om een afsluitende komma te verwijderen, gebruiken we een LEFT-functie die een string als eerste argument neemt. Het tweede argument is het aantal tekens dat moet worden geretourneerd uit die tekenreeks vanaf het eerste teken. Bekijk de volgende vraag:
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
Let hier op deze regel van het script:
SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)
In deze regel van het script hebben we de functie LEFT gebruikt om alle tekens aan de linkerkant van de waarde te krijgen die is opgeslagen in de variabele "@CityNames", beginnend bij het eerste element. In het tweede argument hebben we de LEN-functie gebruikt om het aantal waarde-elementen te berekenen dat is opgeslagen in de functie "@CityNames", en ten slotte hebben we er 1 van afgetrokken. Hiermee wordt de volgkomma uit de tekenreeks verwijderd. De uitvoer ziet er als volgt uit:
[Leeds],[Liverpool],[Londen],[Manchester]
SQL-query converteren naar string
Nu kunnen we hopelijk de variabele "@CityNames" in onze pivot-operator als volgt gebruiken:
PIVOT( AVG(total_score) FOR city IN ( @CityNames )
We kunnen echter geen variabele gebruiken in onze pivot-operator. De alternatieve benadering is om onze volledige SQL-query om te zetten in een string. Binnen deze string zullen we onze "@CityNames" variabele haken.
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
Hier hebben we een variabele "@Query" gedeclareerd en onze SQL-query in deze variabele opgeslagen. Binnen de pivot-operator hebben we de waarde samengevoegd die is opgeslagen in de variabele "@CityNames". Om te zien hoe de uitgevoerde query eruitziet, hebben we de waarde van de variabele "@Query" afgedrukt. De resulterende query ziet er als volgt uit in de uitvoer:
SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN ([Leeds],[Liverpool],[London],[Manchester]) ) AS StudentPivotTable
Dit is precies het type query dat we willen uitvoeren. Dit is echter in het String-formaat. De laatste stap is het uitvoeren van deze SQL-query die is opgeslagen als een tekenreeks. Om dit te doen, gebruiken we dynamische SQL.
Dynamische SQL uitvoeren
We gebruiken de ingebouwde procedure "sp_executesql" om dynamische SQL uit te voeren. We zullen deze opgeslagen procedure gebruiken om de query uit te voeren die is opgeslagen in de @Query-variabele. Onze laatste query die een dynamische draaitabel maakt, ziet er als volgt uit:
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
Wanneer u de bovenstaande query uitvoert, zou u het volgende resultaat moeten zien:
[tabel id=37 /]
Deze keer hebben we de waarden voor de koppen van de draaitabel echter niet handmatig opgegeven. In plaats daarvan zijn de koppen dynamisch berekend, wat resulteert in een dynamische draaitabel.