Intの配列が渡されるwebserviceがあります。次のようにselectステートメントを実行したいのですが、エラーが発生し続けます。配列を文字列に変更する必要がありますか?
[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);
}
(残念ながら)それはできません。 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)
まず、関数と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以外のものを渡すと、データベース関数全体が失敗します。そのためのエラー処理は、エンドユーザーの演習として残しておきます。
注:私は一般的に、パラメータ化されていないクエリを使用するためではありません。ただし、このインスタンスでは、整数配列を処理していることを考えると、couldを実行すると、より効率的になります。ただし、有効なアドバイスの基準を満たしていないため、全員が回答をダウングレードしたいと考えているため、恐ろしく実行されるがおそらく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";
安全でないコードやユーザー定義関数を必要としない超高速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))
すべてのクレジットは達人になります Brad Schulzのブログ
複数のId値を受け入れるT-SQLストアドプロシージャ にアクセスして、これを行う方法のアイデアをご覧ください。
私はそのアプローチを使用し、私のために働きます。
私の変数act = stringのIDのリスト。
act = "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);
[WebMethod]
public MiniEvent [] getAdminEvents(int buildingID、DateTime startDate)
...
SqlParameter buildID = new SqlParameter( "@ buildingIDs"、 buildingIDs);
おそらく私は詳しく説明しすぎていますが、このメソッドはintの配列ではなく単一のintを受け入れます。配列を渡す場合、メソッド定義を更新してint配列を持つ必要があります。その配列を取得したら、SQLクエリで使用する予定がある場合は、配列を文字列に変換する必要があります。
これが私が考えた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...
}
これを使用できます。 SQLServerで実行して、DBに関数を作成します(1回のみ):
IF EXISTS(
SELECT *
FROM sysobjects
WHERE name = 'FN_RETORNA_ID_FROM_VARCHAR_TO_TABLE_INT')
BEGIN
DROP FUNCTION FN_RETORNA_ID_FROM_VARCHAR_TO_TABLE_INT
END
GO
CREATE FUNCTION [dbo].FN_RETORNA_ID_FROM_VARCHAR_TO_TABLE_INT (@IDList VARCHAR(8000))
RETURNS
@IDListTable TABLE (ID INT)
AS
BEGIN
DECLARE
--@IDList VARCHAR(100),
@LastCommaPosition INT,
@NextCommaPosition INT,
@EndOfStringPosition INT,
@StartOfStringPosition INT,
@LengthOfString INT,
@IDString VARCHAR(100),
@IDValue INT
--SET @IDList = '11,12,113'
SET @LastCommaPosition = 0
SET @NextCommaPosition = -1
IF LTRIM(RTRIM(@IDList)) <> ''
BEGIN
WHILE(@NextCommaPosition <> 0)
BEGIN
SET @NextCommaPosition = CHARINDEX(',',@IDList,@LastCommaPosition + 1)
IF @NextCommaPosition = 0
SET @EndOfStringPosition = LEN(@IDList)
ELSE
SET @EndOfStringPosition = @NextCommaPosition - 1
SET @StartOfStringPosition = @LastCommaPosition + 1
SET @LengthOfString = (@EndOfStringPosition + 1) - @StartOfStringPosition
SET @IDString = SUBSTRING(@IDList,@StartOfStringPosition,@LengthOfString)
IF @IDString <> ''
INSERT @IDListTable VALUES(@IDString)
SET @LastCommaPosition = @NextCommaPosition
END --WHILE(@NextCommaPosition <> 0)
END --IF LTRIM(RTRIM(@IDList)) <> ''
RETURN
ErrorBlock:
RETURN
END --FUNCTION
関数を作成した後、コードでこれを呼び出す必要があります。
command.CommandText = @"SELECT id,
startDateTime, endDateTime From
tb_bookings WHERE buildingID IN
(SELECT ID FROM FN_RETORNA_ID_FROM_VARCHAR_TO_TABLE_INT(@buildingIDs))) AND startDateTime <=
@fromDate";
command.Parameters.Add(new SqlParameter(){
DbType = DbType.String,
ParameterName = "@buildingIDs",
Value = "1,2,3,4,5" //Enter the parameters here separated with commas
});
この関数は、「配列」のテキスト内部コンマを取得し、IDと呼ばれるこの値をintとしてテーブルを作成します。この機能がDB上にある場合、任意のプロジェクトで使用できます。
Microsoft MSDNに感謝します。
イゴSベンチュラ
Microsoft MVA
システマ・アリ・デ・サー
追伸:私はブラジル出身です。私の英語を謝罪... XD