1

テーブルを動的に作成し、作成したすべてのテーブルを結合する良い方法は何ですか?

バックグラウンド

データベースのさまざまな部分からデータを収集し、使用するために提示するストアド プロシージャを作成しようとしています。たとえば、アリスとボブの両方に請求書を送信したい場合、このストアド プロシージャは請求書のすべての情報を検索します。秘訣は、Alice と Bob が、私が持っているすべての情報を常に必要としているわけではないということです。ボブが免税対象であるがシムオリオンで取引している場合、為替レートに関する情報を含める必要がありますが、税金に関する情報は省略します。ストアド プロシージャに注文番号を付けて、顧客向けに書式設定された結果を取得したいと考えています。

これまでの私の解決策は、顧客の要件を保持するテーブルを作成することです。次に、ストアド プロシージャがテーブルをチェックします。通貨データが必要な場合は、 を作成して入力する@Currencyか、@Taxes税データなどを保持します。要件を確認し、必要に応じてテーブルを作成します。最後に、データを 1 つのレコード セットに結合する必要があります。

私の問題は、私が言っているエラーがあることです

キーワード「テーブル」付近の構文が正しくありません

AND というエラー

テーブル変数 @Summary を宣言する必要があります

@Summaryこれらのエラーは、動的 SQL を使用してテーブルを結合した場合にのみ表示されます。動的 SQL をコメント アウトし、ステートメントを作成するステートメントにコピー アンド ペーストすると、必要な結果が得られます。

コード

Microsoft SQL Server Management Studio で次の動的 SQL を使用しようとしました

create procedure <procedure> (@OrderNumber varchar(20)) AS

DECLARE @CustomerName varchar(35) -- retrieved based on @OrderNumber
DECLARE @SQLQuery nvarchar(500)
DECLARE @ParamDef nvarchar(500)

DECLARE @SummaryTable table
(
    ID varchar(20) --=@OrderNumber 
    , <Stuff>
)
SET @SQLQuery = 'Select * From @SummaryTable'
SET @ParamDef = '@SummaryTable table'

IF EXISTS(Select <TableName> from CustRequirements where <TableName> = 1 AND Customer = @CustomerName)
BEGIN
    --Create table
    DECLARE @<TableName> table
    (
        ID varchar(20)
        , <Stuff>
    )

    --Populate 
    Insert into <TableName> Select <RelevantData> From <DataSource> where <Condition based on @OrderNumber or @CustomerName>

    --Pepare Dynamic SQL
    Set @SQLQuery = @SQLQuery + ' FULL OUTER JOIN @<TableName> ON <TableName>.ID = SummaryTable.ID'
    SET @ParamDef = ', @<TableName> table'

END
            <repeat for other tables>

EXECUTE sp_executesql @SQLQuery, @ParamDef, @Summary, @LineItems, @Taxes, @Currency 

質問

私のコードに何か問題がありますか? これを行うより良い方法はありますか?私が考えたもう1つのオプションは、各ブランチの下部にステートメント全体IF Existsを含むツリーを作成することでした(IFでJOIN句を中断できないように見えるため)。問題は、n 個の可能なテーブルを結合するために 2^nステートメントが必要になることです。この場合、n は 20 または 30 の高さになる可能性があります。 JOINJOIN

4

2 に答える 2

1

コードに問題があると思います (おそらく 3 つの問題 -- 以下の「疑わしい」1 & 2 を参照) --

1) [OP のコメントの後、10/21 に変更] 大きな問題: 最後の "EXECUTE sp_executesql @SQLQuery..." で渡されるテーブル パラメーターが宣言されないことがあります。

1a) @Summary は実際には宣言されていません... @SummaryTable を宣言して設定してから、@Summary を使用します。それを@SummaryTableに変更するだけです(以下の(4)でそれを行いました)。これにより、2番目のエラーメッセージ(「テーブル変数@Summaryを宣言する必要があります」)が防止されると思います。

1b) 他のすべてのテーブルが時々宣言されます: それぞれの DECLARE ステートメントは "IF EXISTS" 内にあります。(I) 宣言を無条件に (IF EXISTS の外で) 行うが、それでも条件付きで INSERT... または (II) EXECUTE コマンドの形式を使用可能なものに応じて変えることをお勧めします。(未使用のテーブル変数に何かが必要だとは思いません....)以下のポイント4(10/21追加)で、自分のデータベースでテストしていない例を示します(そのテストにはもっと時間かかります)・・・では、その様子を教えてください。

2) [疑わしい 1] 大文字と小文字が混在する単純なケース ;) 行に注意してください...

Set @SQLQuery = @SqlQuery + ' FULL OUTER JOIN @<TableName> ON <TableName>.ID = SummaryTable.ID'

... 最初に大文字の「SQL」があり、次に大文字と小文字が混在する「Sql」があります。

これが「疑わしい」と言った理由 - サーバーの COLLATION で大文字と小文字が区別されない場合は、上で入力したもので問題ありません。

3) [疑問 2] '@TableName' と '@Table Name' (スペースあり) の両方があります。質問を投稿する際に、それがあなたの入力方法である可能性があることを理解しています。

ポイント(4)、回答への更新で追加-可能なコード

create procedure <procedure> (@OrderNumber varchar(20)) AS

DECLARE @CustomerName varchar(35) -- retrieved based on @OrderNumber
DECLARE @SQLQuery nvarchar(500)
DECLARE @ParamDef nvarchar(500)

DECLARE @SummaryTable table
(
    ID varchar(20) --=@OrderNumber 
    , <Stuff>
)
SET @SQLQuery = 'Select * From @SummaryTable'
SET @ParamDef = '@SummaryTable table'


--Create table variables, though they may not be populated
DECLARE @LineItems
(
    ID varchar(20)
    , <Stuff>
)
DECLARE @Taxes
(
    ID varchar(20)
    , <Stuff>
)
DECLARE @Currencytable
(
    ID varchar(20)
    , <Stuff>
)

IF EXISTS(Select <TableName> from CustRequirements where <TableName> = 1 AND Customer = @CustomerName)
BEGIN
    --Populate 
    Insert into <TableName> Select <RelevantData> From <DataSource> where <Condition based on @OrderNumber or @CustomerName>

    --Prepare Dynamic SQL
    Set @SQLQuery = @SQLQuery + ' FULL OUTER JOIN @<TableName> ON <TableName>.ID = SummaryTable.ID'
    SET @ParamDef = ', @<TableName> table'

END
            <repeat for other tables>

EXECUTE sp_executesql @SQLQuery, @ParamDef, @SummaryTable, @LineItems, @Taxes, @Currency
于 2013-10-19T03:22:29.423 に答える
0

私が使用することにした解決策は、テーブルを作成してALTER TABLEから、必要に応じて列を追加することです。

CREATE Table #Output 
(
    InvoiceNumber       varchar(20)
    , <stuff> 
)

IF EXISTS(Select <ThisSegment> FROM CustRequirements WHERE <ThisSegment> = 1 AND Customer = @CustomerName)
BEGIN
    ALTER TABLE #Output ADD <ThisSegment> <dataType>
    UPDATE #Output 
        SET <ThisSegment> = <data> from <DataSource> 
            WHERE <InvoiceNumber = DataSource.invoice> AND <Other conditions> 
END
<Repeat as needed> 
于 2013-10-22T16:19:57.050 に答える