基本的なピボット演算子に関する前回の記事では、ピボット演算子を使用して行を列に変換し、ピボットテーブルを作成する方法を説明しました。ピボットテーブルを作成するには、3つの主要なステップがあることがわかりました。最初のステップは、基本データを選択することでした。 2番目のステップは、基本データをテーブル値の式に変換することでした。最後のステップは、ピボット演算子を一時データに適用することで、ピボットテーブルが作成されました。
以下の例を見てください。
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
注: ダミーのデータベースとデータを作成するには、ピボット演算子に関する前の記事を参照してください。
ピボット演算子の制限
ただし、ピボット演算子には特定の制限があります。ピボット演算子内で、データをピボットする集計フィールドと列を指定する必要があります。最後に、作成する列見出しの個々の値も設定する必要があります。
前のセクションのスクリプトを実行すると、次の結果が得られます。
[テーブルID=35 /]
列の見出しは、city列内の個々の値です。これらの値は、クエリのピボット演算子内で指定しました。
ピボットテーブルを作成する上で最も面倒なのは、列見出しの値を手動で指定することです。これは、特にオンラインデータソースのデータが変更された場合に、ほとんどのエラーが発生しやすい部分です。次回このピボットテーブルを作成するまで、ピボット演算子で指定した値がデータベースに残るかどうかはわかりません。
たとえば、スクリプトでは、ピボットテーブルの見出しの値として、ロンドン、リバプール、リーズ、マンチェスターを指定しました。これらの値は、studentテーブルのСity列に存在していました。どういうわけかこれらの値の1つ以上が削除または更新された場合はどうなりますか?このような場合、nullが返されます。
より良いアプローチは、ピボットテーブルを生成しようとしている列から値の完全なセットを返す動的クエリを作成することです。
動的ピボットテーブルの作成
このセクションでは、動的ピボットテーブルを作成する方法を説明します。
これは、ピボットテーブルを生成しようとしている列の値を手動で指定する必要がないことを意味します。代わりに、これらの値を動的に設定します。この目的のために、「QUOTENAME」関数を使用します。
いつものように、新しいコードを試す前に、十分にバックアップされていることを確認してください。よくわからない場合は、MSSQLデータベースのバックアップに関するこの記事を参照してください。
QUOTENAME関数
「QUOTENAME」機能は、選択した結果をフォーマットします。動的ピボットについて説明する前に、「QUOTENAME」関数の簡単な実例を確認する価値があります。
次のクエリを見てください。
USE schooldb SELECT QUOTENAME(city)+ ',' FROM student
デフォルトでは、「QUOTENAME」関数は選択されたアイテムを角かっこで囲みます。上記のクエリの出力は次のようになります:
[テーブルID=36 /]
列名を変数に格納する
列の値を角かっこで囲んでいますが、ピボット演算子で値を次の形式で指定する必要があります。
「[リーズ]、[リバプール]、[ロンドン]、[マンチェスター]」
これを行うには、変数が必要になります。
USE schooldb DECLARE @CityNames NVARCHAR(MAX) = '' SELECT @CityNames += QUOTENAME(city)+ ',' FROM ( SELECT DISTINCT city FROM student ) AS CITIES PRINT @CityNames
上記のクエリでは、変数「@CityNames」を宣言し、空の文字列で初期化しました。次に、SELECTステートメントを使用して、city列から個別の都市名を選択し、それらを「@CityNames」変数に繰り返し格納しました。各反復で、都市列の個別の値とコンマが「@CityNames」変数に追加されます。
次に、この変数に格納されている値を出力しました。上記のクエリの結果は次のようになります:
「[リーズ]、[リバプール]、[ロンドン]、[マンチェスター]、」
出力を見ると、最後の値の後にコンマがあります。それは必要ありません。
末尾のカンマを削除する
末尾のコンマを削除するには、最初の引数として文字列を受け取るLEFT関数を使用します。 2番目の引数は、最初の文字から始まるその文字列から返される文字数です。次のクエリを見てください:
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」変数に格納されている値の左側にあるすべての文字を、最初の要素から取得しました。 2番目の引数では、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
これはまさに実行したいクエリのタイプです。ただし、これは文字列形式です。最後のステップは、テキスト文字列として保存されているこのSQLクエリを実行することです。これを行うには、動的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
上記のクエリを実行すると、次の結果が表示されます。
[テーブルID=37 /]
ただし、今回は、ピボットテーブルの見出しの値を手動で指定しませんでした。代わりに、見出しは動的に計算され、動的なピボットテーブルになります。