2

これは私が最近割っているナッツです

私が取り組んでいるアプリケーションには、SQL に対する高度な処理が含まれています。操作の 1 つは、コレクション内のアイテム名に基づいて、さまざまなテーブルから現在のコンテキスト内のオブジェクトのさまざまなメタデータを選択します。このために、「select...from...where...in()」の範囲が実行され、悪意のある SQL コードを防ぐために、「in()」句の内容を構築するために Sql パラメータが使用されます。

ただし、「in()」句を構築するためのアイテム コレクションが 2100 アイテムを超える場合、クエリごとに最大 2100 個の Sql パラメーターという Sql Server の制限により、これは失敗します。

私が現在試しているアプローチの 1 つは、「where in()」を使用する代わりに、すべてのアイテム名を格納するための #temp テーブルを作成し、元のクエリでテーブルを結合することです。これにより、.NET コードの配列に格納されたアイテム名をテーブルに入力する方法について頭を悩ませています。確かに、アイテムごとに個別の「挿入先」を発行するのではなく、すべてを一括して挿入する方法が必要ですか?

それ以外に、この問題を解決するための代替アプローチに非常に興味があります。

どうもありがとう

4

7 に答える 7

5

考えられる回避策の 1 つは、XML を照会する機能を使用し、'in' のすべてのデータを xml 列として単純に送信してから結合することです。

同じアプローチを使用して一時テーブルにデータを入力することもできますが、直接使用しないでください。

説明する必要がある短いサンプルを次に示します。

declare @wanted xml
set @wanted = '<ids><id>1</id><id>2</id></ids>'
select * 
from (select 1 Id union all select 3) SourceTable 
where Id in(select Id.value('.', 'int') from @wanted.nodes('/ids/id') as Foo(Id))

アプリケーションで xml を作成し、パラメーターとして渡すだけです。

于 2008-10-03T11:03:54.767 に答える
1

うーん、データのコンテキストや詳細、結果とパフォーマンスの問題をどのように使用しているかを知らなくても、代替案を提案しようとします. 複数のクエリに分割できますか? 今と同じことを行いますが、アイテムが 2100 以上のクエリを作成する代わりに、それぞれが 1050 のクエリを 2 つ作成し、結果をマージします。

于 2008-10-03T11:00:45.540 に答える
1

悪意のある SQL コードの防止: > ストアド プロシージャを使用します。

はい、SQL Server 2005 には一括挿入があります: http://msdn.microsoft.com/en-us/library/ms188365.aspx

于 2008-10-03T11:04:37.683 に答える
1

.NET 2.0 で導入された SqlBulkCopy クラスを利用できます。実際、使い方はとても簡単です。見てみな:

http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlbulkcopy.aspx

于 2008-10-03T11:20:37.090 に答える
0

SQLServer2008にはテーブルパラメータがあります。これはあなたが望むハンマーです。

于 2008-10-03T13:48:25.363 に答える
0

一括更新の問題については、データ テーブルを含むデータ アダプターを見てください。テーブル内のアイテムをバッチで挿入/更新できるパラメーターを設定でき、バッチ MSDN 記事でアイテムの数を選択できます

ビジネス上の問題またはドメインを詳しく調べて、クエリで項目をフィルター処理するより良い方法を判断する必要があるようです。IN() 句は、これを行うための最良の方法ではない場合があります。含めるアイテムの大きなリストの代わりに、データのカテゴリまたはフィルターを追加する方が良い場合があります。ビジネスの問題や状況を詳しく知らなければ、なんとも言えません。

于 2008-10-03T11:11:46.860 に答える
0

わかりました、これがあなたにとってどれほど良いか、またはパフォーマンスがどれほど良いかはわかりませんが、過去に同様のことを達成するために使用したコードを次に示します。

    CREATE FUNCTION [dbo].[Split](
    @list ntext
)
RETURNS @tbl TABLE (listpos int IDENTITY(1, 1) NOT NULL,
                          number  int NOT NULL) 
AS
BEGIN
    DECLARE @pos      int,
            @textpos  int,
            @chunklen smallint,
            @str      nvarchar(4000),
            @tmpstr   nvarchar(4000),
            @leftover nvarchar(4000)

    SET @textpos = 1
    SET @leftover = ''
    WHILE @textpos <= datalength(@list) / 2
    BEGIN
       SET @chunklen = 4000 - datalength(@leftover) / 2
       SET @tmpstr = ltrim(@leftover + substring(@list, @textpos, @chunklen))
       SET @textpos = @textpos + @chunklen

       SET @pos = charindex(',', @tmpstr)
       WHILE @pos > 0
       BEGIN
          SET @str = substring(@tmpstr, 1, @pos - 1)
          INSERT @tbl (number) VALUES(convert(int, @str))
          SET @tmpstr = ltrim(substring(@tmpstr, @pos + 1, len(@tmpstr)))
          SET @pos = charindex(',', @tmpstr)
       END

       SET @leftover = @tmpstr
    END

    IF ltrim(rtrim(@leftover)) <> ''
       INSERT @tbl (number) VALUES(convert(int, @leftover))

    RETURN
END

次に、他のストアド プロシージャで、次のようにコンマで区切られた ID の文字列を渡すことができます。

select a.number from split('1,2,3') a inner join myothertable b on a.number = b.ID

私が言うように、これはおそらく本当に悪いことです。なぜなら、これには多くの文字列操作が含まれており、関数をどこから取得したか思い出せません...しかし、それは選択するためにそこにあります...

元の文字列にインデックスを付ける必要が本当にない場合は、 listpos 列に入力するビットを取り除くこともできると思います。

于 2008-10-03T11:23:06.617 に答える