我有webservice,它传递了一组int。 我想按如下方式执行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);
}
答案 0 :(得分:30)
你不能(不幸的是)那样做。 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)
答案 1 :(得分: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,那么整个数据库函数都会失败。我将错误处理作为最终用户的练习。
答案 2 :(得分:6)
注意:我通常不会使用非参数化查询。但是,在这个实例中,鉴于我们正在处理一个整数数组,你可以做这样的事情,它会更有效率。但是,鉴于每个人似乎都想降级答案,因为它不符合他们的有效建议标准,我将提交另一个表现可怕但可能在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";
答案 3 :(得分: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's Blog
答案 4 :(得分:1)
访问T-SQL stored procedure that accepts multiple Id values,了解有关如何执行此操作的建议。
答案 5 :(得分:1)
我使用这种方法并为我工作。
我的变量act =我在字符串中的ID列表。
act =&#34; 1,2,3,4&#34;
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);
答案 6 :(得分:0)
[的WebMethod]
public MiniEvent [] getAdminEvents(int buildingID ,DateTime startDate)
...
SqlParameter buildID = new SqlParameter(“@ buildingIDs”, buildingIDs );
也许我过于详细,但这个方法接受一个int,而不是一个int数组。如果您希望传入一个数组,则需要更新方法定义以获得一个int数组。一旦获得该数组,如果计划在SQL查询中使用它,则需要将数组转换为字符串。
答案 7 :(得分:0)
你可以用它。在SQLServer中执行以在您的数据库上创建一个函数(仅一次):
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
});
此函数在“array”上获取文本内部逗号,并创建一个表,其值为int,称为ID。当您在DB上使用此功能时,您可以在任何项目中使用。
感谢Microsoft MSDN。
Igo S Ventura
Microsoft MVA
Sistema ArideSá
igo1-2@hotmail.com
P.S。:我来自巴西。向我的英语道歉... XD
答案 8 :(得分: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...
}