2008-09-17 14 views
6

C#でのSqlCommandの使用where節のIN(リスト...)部分を含むクエリを作成しました。リストを生成する私の文字列リストをループするのではなく、クエリに必要なものです(sqlInjectionを考えると危険です)。C#のパラメータを使用したSqlCommandの文字列リスト

DataTable dt = new DataTable(); 
dt.Columns.Add("word", typeof(string)); 
foreach (String word in listOfWords) 
{ 
    dt.Rows.Add(word); 
} 
comm.Parameters.Add("LISTOFWORDS", System.Data.SqlDbType.Structured).Value = dt; 

しかし、これは動作しません:私はこのようなパラメータを追加しようとしたコードに続いて

SELECT blahblahblah WHERE blahblahblah IN @LISTOFWORDS 

:私は、私のようなパラメータを作成することができると考えました。

質問:

  • 私は不可能な何かをしようとしていますか?
  • 私は間違ったアプローチをとったのですか?
  • 私はこのアプローチに間違いがありますか?お時間を

感謝:)

答えて

3

あなたがしようとしていることは可能ですが、現在の方法を使用していません。これは、SQL Server 2008がパフォーマンス、セキュリティ、およびメモリの使用に関連するトレードオフになる前に、すべての可能なソリューションで非常に一般的な問題です。

This link shows some approaches for SQL Server 2000/2005

SQL Server 2008 supports passing a table value parameter.

私はこのことができます願っています。

+4

最初のリンクは2番目と同じポイントを指します – Matt

+0

良い解決策:) – graffic

3

あなたは、そのリストはどこから来るのかについて考えたいです。一般的に、その情報はどこかのデータベースにあります。あなたはこのようなサブクエリ使用することができ

SELECT * FROM [Table] WHERE ID IN (1,2,3) 

::の代わりに、この例では、

SELECT * FROM [Table] WHERE ID IN (SELECT TableID FROM [OtherTable] WHERE OtherTableID= @OtherTableID) 
+0

残念ながら、情報は別のテーブルにありません。いくつかのデータ収集の結果です。 しかし、今後の使用のために書き留めるべき良いアプローチです。ありがとう – graffic

0

を私は値のカンマ区切り文字列としてパラメータを設定することをお勧めとのSQLでSplit関数を使用しますその値を単一の列テーブルに変換し、IN機能を使用することができます。

http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=50648 - 私は右理解していれば、スプリット機能は

+0

かなりSqlインジェクションが発生しやすい:( – graffic

1

、あなたはSQLパラメータとしてリストを渡すしようとしています。

一部の人々

は、限られた成功を収めて前にこれをしようとしている:あなたは文字列としてリストを渡したい場合は

Passing Arrays to Stored Procedures

Arrays and Lists in SQL 2005

Passing Array of Values to SQL Server without String Manipulation

Using MS SQL 2005's XML capabilities to pass a list of values to a command

+0

最初のリンクは、テーブル変数について語っています。これは私がDataTAbleで作成したものですが、この場合はmssqlで飲み込むことができません。 – graffic

0

パラメータを使用すると、クエリを動的に構築できます。

DECLAREの@queryのVARCHAR(500) SETの@query =、

+1

かなりのSQLインジェクションが発生する可能性があります(しかし、ありがとう:) – graffic

0

私は同じ問題を抱えているために使用される '(+ @list + ')' を実行 (@query)何とか何とかWHERE blahblahでのSELECT'私は今、ADO.NET APIを介してこれを直接行う方法があると思います。

単語を魅力的なもの(とqueryidなど)に挿入してから、クエリから誘惑的なものを参照することをお勧めします。あるいは、クエリ文字列を動的に作成し、他の尺度(例えば、正規表現チェック)によってSQLインジェクションを避けることもできます。

+0

私は最初のオプション+バルクSQLインサートに行きます。おそらく、これは私にいくつかのSQLを節約することができますI/O – graffic

1
  • 私は何か不可能なことを試みていますか?

いいえ、不可能ではありません。

  • 私は間違ったアプローチをとったのですか?

あなたのアプローチは

  • (少なくとも.NET 2で)働いていない私は、このアプローチでミスを持っていますか?

可能であれば、私は "Joel Coehoorn"ソリューション(2番目の回答)を試してみます。 それ以外の場合は、区切り文字で区切られたすべての値を含む「文字列」パラメータを送信することもできます。動的クエリを作成し(文字列からの値に基づいて構築する)、 "exec"を使用して実行します。

別の解決方法は、コードから直接クエリを構築することです。このように気にいら:

StringBuilder sb = new StringBuilder(); 
for (int i=0; i< listOfWords.Count; i++) 
{ 
    sb.AppendFormat("p{0},",i); 
    comm.Parameters.AddWithValue("p"+i.ToString(), listOfWords[i]); 
} 

comm.CommandText = string.Format(""SELECT blahblahblah WHERE blahblahblah IN ({0})", 
sb.ToString().TrimEnd(',')); 

コマンドは次のようになります。MSSQL2005で

SELECT blah WHERE blah IN (p0,p1,p2,p3...)...p0='aaa',p1='bbb' 

、 "IN" は256個の値のみを使用しています。

+0

最後のクエリでは、最初にp0が発生したときにエラーが発生します。 – micahhoover

0

これは古い質問ですが、私はこれを再利用するのが大好きで、他の人はそれが役に立つと思います。

最初に、区切られた入力を受け取り、項目がレコードに分割されたテーブルを返すSqlServerにFUNCTIONを作成する必要があります。

Select Id, Data from dbo.Split('123,234,345,456',',') 

と恐怖ではない、これはSQLインジェクション攻撃を受けやすくすることはできません:あなたは今、このような何かを行うことができ

ALTER FUNCTION [dbo].[Split] 
(
    @RowData nvarchar(max), 
    @SplitOn nvarchar(5) = ',' 
) 
RETURNS @RtnValue table 
(
    Id int identity(1,1), 
    Data nvarchar(100) 
) 
AS 
BEGIN 
    Declare @Cnt int 
    Set @Cnt = 1 

    While (Charindex(@SplitOn,@RowData)>0) 
    Begin 
     Insert Into @RtnValue (data) 
     Select 
      Data = ltrim(rtrim(Substring(@RowData,1,Charindex(@SplitOn,@RowData)-1))) 

     Set @RowData = Substring(@RowData,Charindex(@SplitOn,@RowData)+1,len(@RowData)) 
     Set @Cnt = @Cnt + 1 
    End 

    Insert Into @RtnValue (data) 
    Select Data = ltrim(rtrim(@RowData)) 

    Return 
END 

:ここ

は、このために、次のコードです。

次はあなたのカンマ区切りデータを受け取り、その後、あなたはこのSplit関数を使用するSQL文を書くことができますストアドプロシージャ書く:今、あなたはその周りのC#ラッパーを書くことができ

CREATE PROCEDURE [dbo].[findDuplicates] 
    @ids nvarchar(max) 
as 
begin 
    select ID 
     from SomeTable with (nolock) 
    where ID in (select Data from dbo.Split(@ids,',')) 
end 

を:

public void SomeFunction(List<int> ids) 
{ 
    var idsAsDelimitedString = string.Join(",", ids.Select(id => id.ToString()).ToArray()); 

    // ... or however you make your connection 
    var con = GetConnection(); 

    try 
    { 
     con.Open(); 

     var cmd = new SqlCommand("findDuplicates", con); 

     cmd.Parameters.Add(new SqlParameter("@ids", idsAsDelimitedString)); 

     var reader = cmd.ExecuteReader(); 

     // .... do something here. 

    } 
    catch (Exception) 
    { 
     // catch an exception? 
    } 
    finally 
    { 
     con.Close(); 
    } 
} 
関連する問題