31

intの配列が渡されるWebサービスがあります。次のように選択ステートメントを実行したいのですが、エラーが発生し続けます。配列を文字列に変更する必要がありますか?

[WebMethod]
public MiniEvent[] getAdminEvents(int buildingID, DateTime startDate)
{    
    command.CommandText = @"SELECT id,
                            startDateTime, endDateTime From
                            tb_bookings WHERE buildingID IN
                            (@buildingIDs) AND startDateTime <=
                            @fromDate";

    SqlParameter buildID = new SqlParameter("@buildingIDs", buildingIDs);
}
4

9 に答える 9

38

(残念ながら)それはできません。Sql パラメーターは単一の値にしかできないため、次のようにする必要があります。

WHERE buildingID IN (@buildingID1, @buildingID2, @buildingID3...)

もちろん、建物 ID の数を知るか、クエリを動的に作成する必要があります。

回避策*として、次のことを行いました。

WHERE buildingID IN (@buildingID)

command.CommandText = command.CommandText.Replace(
  "@buildingID", 
  string.Join(buildingIDs.Select(b => b.ToString()), ",")
);

これにより、ステートメントのテキストが数字に置き換えられ、次のようになります。

WHERE buildingID IN (1,2,3,4)
  • これは SQL インジェクションの脆弱性に近づいていますが、int 配列であるため安全です。任意の文字列は安全ではありませんが、Sql ステートメントを整数 (または日時、ブール値など) に埋め込む方法はありません。
于 2008-10-08T10:45:21.893 に答える
8

まず、関数と sproc が必要になります。関数はデータを分割し、テーブルを返します。

CREATE function IntegerCommaSplit(@ListofIds nvarchar(1000))
returns @rtn table (IntegerValue int)
AS
begin
While (Charindex(',',@ListofIds)>0)
Begin
    Insert Into @Rtn 
    Select ltrim(rtrim(Substring(@ListofIds,1,Charindex(',',@ListofIds)-1)))
    Set @ListofIds = Substring(@ListofIds,Charindex(',',@ListofIds)+len(','),len(@ListofIds))
end
Insert Into @Rtn 
    Select  ltrim(rtrim(@ListofIds))
return 
end

次に、それを使用するための sproc が必要です。

create procedure GetAdminEvents 
    @buildingids nvarchar(1000),
    @startdate datetime
as
SELECT id,startDateTime, endDateTime From
            tb_bookings t INNER JOIN 
dbo.IntegerCommaSplit(@buildingids) i
on i.IntegerValue = t.id
 WHERE startDateTime <= @fromDate

最後に、あなたのコード:

[WebMethod]
        public MiniEvent[] getAdminEvents(int[] buildingIDs, DateTime startDate)
        command.CommandText = @"exec GetAdminEvents";
 SqlParameter buildID= new SqlParameter("@buildingIDs", buildingIDs);

それはあなたの質問が求めたものをはるかに超えていますが、それはあなたが必要とすることをします.

注: int 以外のものを渡すと、データベース関数全体が失敗します。そのためのエラー処理は、エンド ユーザーの演習として残します。

于 2008-10-15T18:33:18.390 に答える
7

注:私は一般的に、パラメーター化されていないクエリを使用することは好みません。ただし、この場合、整数配列を扱っていることを考えると、そのようなことを行うことができ、より効率的です。ただし、有効なアドバイスの基準を満たしていないため、誰もが回答をダウングレードしたいと考えているため、恐ろしく実行されるがおそらくLINK2SQLで実行される別の回答を送信します。

質問が述べているように、int の配列があると仮定すると、次のコードを使用して、SQL が受け入れるコンマ区切りのリストを含む文字列を返すことができます。

private string SQLArrayToInString(Array a)
{
 StringBuilder sb = new StringBuilder();
 for (int i = 0; i < a.GetUpperBound(0); i++)
  sb.AppendFormat("{0},", a.GetValue(i));
 string retVal = sb.ToString();
 return retVal.Substring(0, retVal.Length - 1);
}

次に、これが int の配列であることを考えると、コマンドのパラメーター化をスキップして、次のように使用することをお勧めします。

command.CommandText = @"SELECT id,
            startDateTime, endDateTime From
            tb_bookings WHERE buildingID IN
            (" + SQLArrayToInString(buildingIDs) + ") AND startDateTime <=
            @fromDate";
于 2008-10-08T14:31:18.627 に答える
3

安全でないコードやユーザー定義関数を必要としない超高速の XML メソッド:

ストアド プロシージャを使用して、コンマ区切りの建物 ID のリストを渡すことができます。

Declare @XMLList xml
SET @XMLList=cast('<i>'+replace(@buildingIDs,',','</i><i>')+'</i>' as xml)
SELECT x.i.value('.','varchar(5)') from @XMLList.nodes('i') x(i))

すべてのクレジットは Guru Brad Schulz のブログに帰属します

于 2013-03-03T22:15:50.017 に答える
1

私はそのアプローチを使用し、私のために働いています。

私の変数 act = 文字列の ID のリスト。

行為=「1、2、3、4」

 command = new SqlCommand("SELECT x FROM y WHERE x.id IN (@actions)", conn);    
 command.Parameters.AddWithValue("@actions", act);
 command.CommandText = command.CommandText.Replace("@actions", act);
于 2016-08-26T15:20:23.733 に答える
1

これを行う方法のアイデアについては、複数の Id 値を受け入れるT-SQL ストアド プロシージャを参照してください。

于 2008-10-08T10:37:29.163 に答える
0

これが私が考えたLinqソリューションです。@item0、@item1、@item2、@item3 などのパラメーターとして、リスト内のすべてのアイテムを自動的に挿入します。

[WebMethod]
public MiniEvent[] getAdminEvents(Int32[] buildingIDs, DateTime startDate)
{
    // Gets a list with numbers from 0 to the max index in buildingIDs,
    // then transforms it into a list of strings using those numbers.
    String idParamString = String.Join(", ", (Enumerable.Range(0, buildingIDs.Length).Select(i => "@item" + i)).ToArray());
    command.CommandText = @"SELECT id,
                        startDateTime, endDateTime From
                        tb_bookings WHERE buildingID IN
                        (" + idParamString + @") AND startDateTime <=
                        @fromDate";
    // Reproduce the same parameters in idParamString 
    for (Int32 i = 0; i < buildingIDs.Length; i++)
            command.Parameters.Add(new SqlParameter ("@item" + i, buildingIDs[i]));
    command.Parameters.Add(new SqlParameter("@fromDate", startDate);
    // the rest of your code...
}
于 2016-11-25T10:49:29.003 に答える
0

【ウェブメソッド】

public MiniEvent[] getAdminEvents(int buildingID , DateTime startDate)

...

SqlParameter buildID= new SqlParameter("@buildingIDs", buildingIDs );

詳細すぎるかもしれませんが、このメソッドは int の配列ではなく、単一の int を受け入れます。配列を渡すことが予想される場合は、int 配列を持つようにメソッド定義を更新する必要があります。その配列を取得したら、それを SQL クエリで使用する場合は、配列を文字列に変換する必要があります。

于 2008-10-15T18:26:51.647 に答える