В предишната ми статия за основния оператор на въртене видяхме как може да се използва въртящ оператор за преобразуване на редове в колони, което води до централни таблици. Видяхме, че има три основни стъпки за създаване на централна таблица. Първата стъпка беше изборът на основните данни. Втората стъпка беше преобразуването на базовите данни в израз с таблично стойности, а последната стъпка включваше прилагане на въртящ се оператор към временните данни, което доведе до обобщената таблица.
Разгледайте примера по-долу.
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
Забележка: За да създадете фиктивна база данни и данни, вижте предишната статия за Pivot оператора.
Ограничения на Pivot оператора
Въпреки това, има определени ограничения на оператора на въртене. Вътре в оператора за въртене трябва да посочим обобщеното поле и колони, върху които искаме да завъртим нашите данни. И накрая, ние също трябва да зададем отделните стойности за заглавията на колоните, които искаме да създадем.
Ако изпълним скрипта от предишния раздел, ще получим следния резултат:
[table id=35 /]
Заглавията на колоните са отделните стойности в колоната за град. Ние посочихме тези стойности вътре в оператора за въртене в нашата заявка.
Най-досадната част от създаването на обобщени таблици е ръчното определяне на стойностите за заглавията на колоните. Това е частта, която е склонна към повечето грешки, особено ако данните във вашия онлайн източник на данни се променят. Не можем да бъдем сигурни, че стойностите, които посочихме в оператора за въртене, ще останат в базата данни, докато не създадем тази обобщена таблица следващия път.
Например, в нашия скрипт ние посочихме Лондон, Ливърпул, Лийдс и Манчестър като стойности за заглавия на нашата основна таблица. Тези стойности съществуваха в колоната Сград на таблицата на учениците. Ами ако по някакъв начин една или повече от тези стойности бъдат изтрити или актуализирани? В такива случаи ще бъде върнато null.
По-добър подход би бил да създадете динамична заявка, която ще върне пълен набор от стойности от колоната, от която се опитвате да генерирате своята централна таблица.
Създаване на динамична обобщена таблица
В този раздел ще видим как да създадем динамична централна таблица.
Това означава, че няма да е необходимо ръчно да задаваме стойностите за колоната, от която се опитваме да генерираме нашата основна таблица. Вместо това ще задаваме тези стойности динамично. За тази цел ще използваме функцията „QUOTENAME“.
Както винаги, уверете се, че сте добре архивирани, преди да експериментирате с нов код. Вижте тази статия за архивиране на MS SQL бази данни, ако не сте сигурни.
Функция QUOTENAME
Функцията “QUOTENAME” форматира избраните резултати. Преди да обясните динамичното завъртане, си струва да разгледате бърз работен пример за функцията „QUOTENAME“.
Разгледайте следната заявка.
USE schooldb SELECT QUOTENAME(city)+ ',' FROM student
По подразбиране функцията “QUOTENAME” обвива избраните елементи с квадратни скоби. Резултатът от горната заявка изглежда така:
[table id=36 /]
Съхранение на имената на колони в променлива
Въпреки че сме обвили стойностите на колоните с квадратни скоби, трябва да посочим стойностите в оператора за въртене в този формат:
„[Лийдс], [Ливърпул], [Лондон], [Манчестър]“
За да направим това, ще ни трябва променлива.
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES PRINT @CityNames
В горната заявка декларирахме променлива „@CityNames“ и я инициализирахме с празен низ. След това използвахме оператор SELECT, за да изберем различни имена на градове от колоната за град и да ги съхраняваме итеративно в променливата „@CityNames“. При всяка итерация към променливата „@CityNames“ ще бъде добавена отделна стойност в колоната за град заедно със запетая.
След това отпечатахме стойността, съхранена в тази променлива. Резултатът от горната заявка ще изглежда така:
„[Лийдс], [Ливърпул], [Лондон], [Манчестър],”
Ако погледнете изхода, след последната стойност има запетая. Нямаме нужда от това.
Премахване на запетая в края
За да премахнем крайна запетая, ще използваме функция LEFT, която приема низ като първи аргумент. Вторият аргумент е броят на знаците, които трябва да бъдат върнати от този низ, започвайки от първия знак. Разгледайте следната заявка:
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
Тук обърнете внимание на този ред от скрипта:
SET @CityNames = LEFT(@CityNames, LEN(@CityNames)-1)
В този ред на скрипта използвахме функцията LEFT, за да получим всички знаци от лявата страна на стойността, съхранена в променливата „@CityNames“, като се започне от първия елемент. Във втория аргумент използвахме функцията LEN, за да изчислим броя на стойностните елементи, съхранени във функцията „@CityNames“ и накрая извадихме 1 от нея. Това премахва последната запетая от низа. Резултатът ще изглежда така:
[Лийдс], [Ливърпул], [Лондон], [Манчестър]
Преобразуване на SQL заявка в низ
Сега, надяваме се, можем да използваме променливата „@CityNames“ вътре в нашия центров оператор по следния начин:
PIVOT( AVG(total_score) FOR city IN ( @CityNames )
Въпреки това, не можем да използваме променлива в нашия центров оператор. Алтернативният подход е да преобразуваме нашата пълна SQL заявка в низ. Вътре в този низ ще закачим нашата променлива „@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
Тук декларирахме променлива „@Query“ и съхранихме нашата SQL заявка в тази променлива. Вътре в оператора за въртене, ние обединихме стойността, съхранена в променливата „@CityNames“. За да видим как изглежда изпълнената заявка, ние отпечатахме стойността на променливата “@Query”. Получената заявка ще изглежда така в изхода:
SELECT * FROM (SELECT city, total_score FROM student ) AS StudentTable PIVOT( AVG(total_score) FOR city IN ([Leeds],[Liverpool],[London],[Manchester]) ) AS StudentPivotTable
Това е точно този тип заявка, която искаме да изпълним. Това обаче е във формат String. Последната стъпка е да изпълните тази SQL заявка, съхранена като текстов низ. За да направим това, ще използваме Dynamic SQL.
Изпълнение на динамичен SQL
Ние използваме вградената процедура “sp_executesql” за изпълнение на динамичен SQL. Ще използваме тази съхранена процедура, за да изпълним заявката, съхранена в променливата @Query. Нашата последна заявка, която създава динамична централна таблица, изглежда така:
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
Когато изпълните горната заявка, трябва да видите следния резултат:
[table id=37 /]
Този път обаче не посочихме ръчно стойностите за заглавията на обобщената таблица. Вместо това заглавията са изчислени динамично, което води до динамична обобщена таблица.