使用列表输入构建SQL存储过程查询

时间:2013-11-14 19:14:48

标签: c# sql sql-server-2008

如何将名称列表传递给SQL参数,以便我可以进行WHERE IN(@myList)?

我正在为我们的网页进行“高级搜索”,用户可以在其中列出以逗号分隔的内容,以便为多个输入找到他们想要找到的内容。例如,可以有5个输入(名字,帐号,姓氏,......),对于每个输入,他们可以列出几个并用逗号分隔。

到目前为止,我的方法是为每个输入接收此字符串,并对其进行格式化,以便我可以在该字符串上使用“IN”子句。这可能吗?

IE用户“First Name”进入“Bob,Joe,Fred”,我会将该输入转换为

"'Bob', 'Joe', 'Fred'"

然后将其作为参数发送到存储过程。

Declare @firstNames

Select * from Users
where User.FirstName in firstNames

或者我应该将所有这些名称放入C#中的DataTable并将其传递给SQL吗?如果我应该走这条路,一些例子会有很多帮助!

谢谢!

3 个答案:

答案 0 :(得分:1)

每当我的查询有点像这样复杂时,我更愿意选择以下两种方式之一:

  1. 在C#中动态创建查询,基于字符串连接以获得更好的可读性而不是LINQ表达式树,并将其发送到SQL Server,或
  2. 在SQL Server中创建一个SP或Table-Valued Function,然后从C#中调用它,并将参数传递给它。
  3. 如果在C#中创建查询,它不可扩展,每次要更改逻辑时,都应该重新编译应用程序。

    如果是SP,因为它将是一个动态查询,而where子句应该根据输入参数创建,我使用exec (@query)

答案 1 :(得分:1)

假设您使用的是SQL Server,您可以创建一个表格式函数,例如将逗号分隔的值拆分为表格

CREATE FUNCTION dbo.Split(@String nvarchar(4000), @Delimiter char(1))
RETURNS @Results TABLE (Items nvarchar(4000))
AS
BEGIN
DECLARE @INDEX INT
DECLARE @SLICE nvarchar(4000)
-- HAVE TO SET TO 1 SO IT DOESNT EQUAL Z
--     ERO FIRST TIME IN LOOP
SELECT @INDEX = 1
WHILE @INDEX !=0
BEGIN
-- GET THE INDEX OF THE FIRST OCCURENCE OF THE SPLIT CHARACTER
SELECT @INDEX = CHARINDEX(@Delimiter,@STRING)
-- NOW PUSH EVERYTHING TO THE LEFT OF IT INTO THE SLICE VARIABLE
IF @INDEX !=0
SELECT @SLICE = LEFT(@STRING,@INDEX - 1)
ELSE
SELECT @SLICE = @STRING
-- PUT THE ITEM INTO THE RESULTS SET
INSERT INTO @Results(Items) VALUES(@SLICE)
-- CHOP THE ITEM REMOVED OFF THE MAIN STRING
SELECT @STRING = RIGHT(@STRING,LEN(@STRING) - @INDEX)
-- BREAK OUT IF WE ARE DONE
IF LEN(@STRING) = 0 BREAK
END
RETURN
END

然后你可以在你的SP中调用这样的函数

从用户中选择* User.FirstName在哪里( 选择项目FROM [dbo]。[Split](@ firstNames,','))

答案 2 :(得分:0)

在C#中,您可以向SQLCommand.CommandText添加参数列表。假设customerName是一个“'Bob','Joe','Fred'”的字符串,你可以这样做:

Dim command As New SqlCommand(commandText, connection)
        ' Add FirstName parameter for WHERE clause.
        command.Parameters.Add("@FirstName", SqlDbType.nvarchar)
        command.Parameters("@FirstName").Value = FirstName

在查询分析器中,你不能在@parameter中有一个列表,这是一个麻烦,但你可以从另一个源传入一个;例如你的C#调用代码。在WHERE子句中,您可以执行WHERE IN(@Name)。在我的测试中,我创建了一个临时表并执行WHERE(SELECT FirstName FROM #MyCustomerTempTable),然后在挂钩时用单例参数替换子查询。

来源:http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.parameters(v=vs.110).aspx

为命令添加参数的另一种方法(我经常使用)是:

' Add the input parameter and set its properties. 
Dim parameter As New SqlParameter()
parameter.ParameterName = "@FirstName"
parameter.SqlDbType = SqlDbType.NVarChar
parameter.Value = firstName

' Add the parameter to the Parameters collection.
command.Parameters.Add(parameter)

来源(向下滚动到示例): http://msdn.microsoft.com/en-us/library/yy6y35y8(v=vs.110).aspx

您还可以在C#中动态构建查询,或者执行string.replace并将@parameter替换为“my list of names”,但这些方法都不适合将参数对象添加到SQL Command对象。我建议你对SQL Command对象有一个很好的理解,这样你就可以构建它而不是操纵字符串。