これは動作するはずです:
WITH Sales AS ( SELECT S.SaleID, S.SoldBy, S.SalePrice, S.Margin, S.Date, I.SalePrice, I.Category FROM dbo.Sale S INNER JOIN dbo.SaleItem I ON S.SaleID = I.SaleID ) SELECT * FROM Sales PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P ;
プレ>または代わりに:
SELECT S.SaleID, S.SoldBy, S.SalePrice, S.Margin, S.Date, I.Books, I.Printing, I.DVD FROM dbo.Sale S INNER JOIN ( SELECT * FROM (SELECT SaleID, SalePrice, Category FROM dbo.SaleItem) I PIVOT (Max(SalePrice) FOR Category IN (Books, Printing, DVD)) P ) I ON S.SaleID = I.SaleID ;
プレ>これらは同じ結果セットを持ち、実際にはクエリ オプティマイザーによって同じように扱われる可能性がありますが、そうでない可能性もあります。
Sale
に条件を設定し始めると、大きな違いが現れます。 table—どのクエリがよりうまく機能するかをテストして確認する必要があります。注:
PIVOT
を使用する場合は重要です 結果の出力の一部である必要がある列のみが使用可能であること。これが、上記の 2 つのクエリに追加の派生テーブル サブクエリ(SELECT ...)
がある理由です。 特定の列のみが公開されるようにします。PIVOT
で表示できるすべての列 ピボット式にリストされていないものは、暗黙的にグループ化され、最終出力に含まれます。これはおそらくあなたが望むものではないでしょう.ただし、プレゼンテーション層でピボットを行うことをお勧めしますか?たとえば、SSRS を使用している場合、すべてのピボットを行うマトリックス コントロールを使用するのは非常に簡単です。新しい
Category
を追加すると、それが最適です。 、すべての SQL コードを変更する必要はありません!ピボットする列名を動的に見つける方法はありますが、動的 SQL が必要です。可能ではありますが、最善の方法としてもあまりお勧めしません。
可能な別の方法
Category
にトリガーを設定するという意味で、このクエリを前処理します。 存在するすべての既存のカテゴリを含むようにビューを書き換えるテーブル。これにより、私が言及した他の多くの問題が解決されますが、繰り返しますが、プレゼンテーション層を使用するのが最善です.注意 :列名 (以前は値であった) にスペースが含まれている、数字である、数字で始まる、または有効な識別子ではない場合は、
PIVOT (Max(Value) FOR CategoryId IN ([1], [2], [3], [4])) P
.または、PIVOT
に到達する前に値を変更することもできます 列リストがエスケープする必要がないように、いくつかの文字を先頭に追加するかスペースを削除するクエリの一部。この詳細については、識別子のルールを確認してください。