2011-10-19 34 views
9

SQL Server(T-SQL)で動的列を持つpvotsを使用してSQLクエリを作成しています。 私の長い質問を送信するのではなく、単純化したモデルで問題を説明しています。SQL Serverで動的列をピボットする

私は2つのテーブルを作成:表1と表2を、以下のようにいくつかのエントリでそれらを移入:

表1:


Col_ID1 ............ ... COL_NAME

1 .........................月-11

2 ........ ................. Feb-11

3 ......................... 03月11

表2:


Col_ID2 ......アカウント.....アカウント名......金額

1 ............... 121 ......... ..電気............ 10000

2 ............... 121 ............電気は、 ........... 20000

3 ............... 121 .............電気............ 30000

1 ............... 122 .......電話.............. 100

2。 .............. 122 .......電話.............. 200

3 ... ............ 122 ...........電話.............. 300

私はPivotでは、列名をパラメトリックに生成する必要があります(入力から入力された日付に基づいてクレン)、ハードコードされていません。以下

クエリはうまく動作しますが、follとしてのみいくつかの列を与える:

月-11 ........... 02月11 ........ ...月-11

10,000.00 20,000.00 ...... ...... 30,000.00

100.00 ............... 200.00 .... ....... 300.00

foll:のように説明列も返すようにしたい

アカウント...........アカウント名........... 1月11日............ 2月11日.. ............ Mar-11

121 .................電気.......... ...... 10,000.00 ...... 20,000.00 .......... 30,000.00

122 .................電話................... 100。00 ........... 200.00 ............. 300.00

私の目的を達成できるように私のクエリを変更してもらえますか?

このクエリは、9月、2007年に博士アンドラスによって書かれた次の文書の適合である http://www.simple-talk.com/community/blogs/andras/archive/2007/09/14/37265.aspx

誰かがコードは、インジェクション攻撃の対象となり得ることに留意し、代わりに角括弧を連結するQUOTENAME関数を使用することが提案。

クエリでQuotenameを使用する方法を説明できますか。

どうもありがとう、

黎明(レオン・ライ) 。

。ここで

は私のクエリです:

------------------------ &移入table1を作成---------- ----------------------

CREATE TABLE Table1 
(Col_ID1 INT, 
Col_Name varchar(10)) 

INSERT INTO Table1 VALUES (1, 'Jan-11') 
INSERT INTO Table1 VALUES (2, 'Feb-11') 
INSERT INTO Table1 VALUES (3, 'Mar-11') 

--------------------- ----作成&人口テーブル2 ----------------------------------

CREATE TABLE Table2 
(Col_ID2 INT, 
Account varchar(10), 
AccountName varchar(20), 
Amount numeric(18,6)) 

INSERT INTO Table2 VALUES (1, 121, 'Electricity', 10000) 
INSERT INTO Table2 VALUES (2, 121, 'Electricity', 20000) 
INSERT INTO Table2 VALUES (3, 121, 'Electricity', 30000) 
INSERT INTO Table2 VALUES (1, 122, 'Telephone', 100)   
INSERT INTO Table2 VALUES (2, 122, 'Telephone', 200) 
INSERT INTO Table2 VALUES (3, 122, 'Telephone', 300) 

- ---------------------------------列見出しを作成する-------------- -----

DECLARE @cols NVARCHAR(2000) 
SELECT @cols = STUFF((SELECT DISTINCT TOP 100 PERCENT 
'],[' + t2.Col_Name 
FROM Table1 AS t2 
ORDER BY '],[' + t2.Col_Name 
FOR XML PATH('') 
), 1, 2, '') + ']' 

------------------------------------- create @query --- -------------------

DECLARE @query NVARCHAR(4000) 

SET @query = N'SELECT '+ 
@cols +' 

FROM 

------------------------ --subquery -----

(SELECT
t1.Col_Name,
t2.Account,
t2.Amount
FROM Table1 AS t1
JOIN Table2 AS t2 ON t1.Col_ID1 = t2.Col_ID2
) p

--------------------ピボット------------ -------------

PIVOT
(
Sum ([Amount])
FOR Col_Name IN
('+
@cols +')
) AS pvt '

---------------------- EXEC &ドロップ----------

EXECUTE(@query) 
drop table table1 
drop table table2 

=== ========================================== ==

こんにちはフィリップ、

お返事をありがとうたくさん。

提案されたクエリはスムーズに機能し、期待される画面を生成しますが、正確には私が望むものではありません。

まず、コードに感謝します。SELECT @cols = ISNULL(@cols + ''、 '')+ '[' + COL_NAME + ']'

それは簡単ですし、私のラインを置き換えません明らかに同じ効果を持つstuffとxmlパスを含んでいます。

私がしたいことを説明しましょう。

私はSap Business 1(会計パッケージ - またはERPと呼ぶ)でクエリを作成したいと考えています。 Sapは、Microsoft Server 2008でT-SQLを使用し、独自のクエリジェネレータを備えています。 ほとんど例外はありませんが、Sap SQLはT-SQLと似ています。

私は12ヶ月間にわたりすべての収入と支出のリストを毎月提供したいと思っています。

次のように(これは時々私のクエリを修正するために私を必要とするよう)しかし、私は、私の列見出しがハードコードされないようにする:

月 - 11、02月11、Mar-を12月11日

むしろ、ユーザーが入力画面に入力した日付から列見出しを動的に生成したいと考えています。

私が言及したように、私がフォーラムに投稿したクエリは、実際のクエリの単純化されたバージョンです。実際のクエリにはいくつかの変数があり、入力画面(Sap b1のQuery - Selection Criteriaボックスと呼ばれます)では、ユーザが日付を入力することができます。この日付は、列名を動的に決定するために使用されます。

これは、I入力は、入力画面で(2011年6月1日)'01 .06.11' を言うなら、この日付はなります私はピボットなど@cols、@query、このような複雑なツールを必要とする理由

ですSQLに渡され、foll:

Jun-11、Jul-11、Aug-11 ..... 5月12日のように列見出しの名前が決定されます。

I入力別の日付は、'01 .09.10' (2010年9月1日)は、列見出しが変更されると言う場合に:

9月 - 10、10月、10、... 8月 - 11

あなたは自分の見出しをハードコードしたようです。

私のクエリをもう一度見て、ハードコードされているのではなくパラメトリックに列名を生成できるものを提案できますか?これらの列を追加する

おかげ

黎明(レオン・ライ)

答えて

11

は非常に簡単です。最後のクエリはt2.AccountNameがサブクエリに追加してい

SELECT Account, AccountName, [Feb-11],[Jan-11],[Mar-11] FROM 
(SELECT 
t1.Col_Name, 
t2.Account, 
t2.AccountName, 
t2.Amount 
FROM Table1 AS t1 
JOIN Table2 AS t2 ON t1.Col_ID1 = t2.Col_ID2 
) p 
PIVOT 
(
Sum ([Amount]) 
FOR Col_Name IN 
([Feb-11],[Jan-11],[Mar-11]) 
) AS pvt 

だろう、とアカウントとアカウント名は、最初のSELECTに追加しました。ビルド声明にそれらを投げるとすれば完了です:SQLインジェクション、私は誰かが何とかTable1.Col_Name内で悪質なコードを埋め込む場合起こっていることを見ることができる唯一の方法については

DECLARE @query NVARCHAR(4000) 
SET @query = N'SELECT Account, AccountName, ' + @cols +' FROM 

(SELECT 
t1.Col_Name, 
t2.Account, 
t2.AccountName, 
t2.Amount 
FROM Table1 AS t1 
JOIN Table2 AS t2 ON t1.Col_ID1 = t2.Col_ID2 
) p 

PIVOT 
(
Sum ([Amount]) 
FOR Col_Name IN 
('+ 
@cols +') 
) AS pvt ' 

を、あなたが心配する必要がある場合それについては、この動的クエリを「ロックダウン」するよりも大きな問題があります。

また、私はXMLの方が好きではないので、その短いと読みやすいので、列のリスト(@Cols)を作成するために、次のように使用します。

DECLARE @cols NVARCHAR(2000)  
SELECT @cols = isnull(@cols + ',', '') + '[' + Col_Name + ']' 
FROM Table1 
ORDER BY Col_Name 
+0

こんにちはフィリップ、私はあなたの返信に質問を投稿しましたThanks Leon –

+0

これはばかげた良い答えです! – jTC

+0

''[' + Col_Name + ']''の代わりに 'quotename(Col_Name)'を使用してください。 – jnm2

1

これは編集がほぼ2番目の質問であるためです。 (詳細と詳細はなく、私は一般的なアウトラインと擬似コードしか提供できません - 私はSAPを知らない)

ピボットから始めましょう。おそらくmonthというラベルの列を生成する必要があります。この列は、Table1.Col_Name、varchar(10);それらの値が抽出され、列名としてピボットクエリに動的に追加されます。データベースにそのような列がない場合は、ユーザーが入力したデータに基づいてクエリ用に列を作成する必要があります。 - データには任意の値(年からミリ秒)が表示される日付時刻の列があります。 - ユーザーは「開始日」を指定します(常に1か月の最初ですか?)。あなたはそれと次の11ヶ月間の列を生成し、それぞれの目標月内のデータを集計する必要があります。

ステップ1、私はセットアップと12個のターゲット列を含む一時テーブルを移入したい:あなたはそれを表示するようラベルがフォーマットされ

CREATE TABLE #Months 
(
    Col_Name varchar(10) 
    ,MonthStart datetime 
    ,MonthEnd datetime 
) 

、MonthStartは、(月の絶対開始になります2011年10月1日00:00:00.000)、MonthEndは翌月の絶対的な開始日となります(2011年11月1日00:00:00.000)。これによりSELECT … from <table> where DataDate >= MontStart and DataDate < MonthEndを使用してその月のすべてのデータを取得できます。

次に、あなたのデータテーブルや集計、のようなもので、このテーブルに参加:

SELECT 
    mt.Col_Name 
    ,sum(dt.RawData) Amount 
from #Months mt 
    inner join MyData dt 
    on dt.DataDate >= mt.MonthStart 
    and dt.DataDate < mt.MonthEnd -- Yes, ON clauses don't have to be simple equivalencies! 
    inner join <other tables as necessary for Account, AccountName, etc.> 

プラグインこのピボット文の最も内側のクエリは、抽出物/使用して一時テーブルからCol_Namesのリストを構築します非XMLクエリー(私はそれ以外のものは何も知らない)、動的にビルドして実行することができます。

+0

フィリップ・レオン・ライ –

関連する問題