【问题标题】:Passing parameter to IN SQL statement将参数传递给 IN SQL 语句
【发布时间】:2012-03-01 00:31:08
【问题描述】:

我收集了一些要从字符串变量内的 DB 列中查找的值,并试图将其作为 SQL StoredProcedure 中的参数传递。

ALTER PROCEDURE [dbo].[InkDB]
(
@ser nvarchar(255),
@svt nvarchar(255)
)
AS
SELECT DISTINCT Details from tbData WHERE (Name IN @svt AND Address=@ser)

这在尝试运行查询时给了我syntax error near @svt 消息。

在我的网页中,参数的值类似于 ('PersonA', 'Person B', 'Person C') 正在传递。在这种情况下如何使用IN 语句?

【问题讨论】:

标签: asp.net sql sql-server-2008


【解决方案1】:

我会用 XML 来做。在重复的问题中找不到这个解决方案,所以我在这里添加它。

您的 SP 可能如下所示:

alter procedure InkDB
  @ser nvarchar(255),
  @svt xml
as

declare @T table
(
  Name nvarchar(50)
)

insert into @T
select T.N.value('.', 'nvarchar(50)')
from @svt.nodes('/N') as T(N)

select distinct Details
from tbData 
where Name in (select Name from @T) and
      Address=@ser

你会这样称呼它。

exec InkDB '', '<N>PersonA</N><N>PersonB</N>'

【讨论】:

  • 这里的 T.N.value 是什么意思?您愿意提供一个包含详细说明的链接吗?
  • +1 这是使用“表值函数”减少逗号分隔值的代码。
  • @PankajGarg - .nodes.value 用于在 SQL Server 中解析和分解 XML。你可以在这里读更多关于它的内容。 Introduction to XQuery in SQL Server 2005
【解决方案2】:

动态查询

Alter procedure test
(
    @ser nvarchar(255),
    @svt nvarchar(255)
)
AS
BEGIN
   declare @sql nvarchar(Max)

   Set @sql='SELECT DISTINCT semester_code from mst_paper WHERE course_code IN ('+@svt+') AND branch_code='+@ser+''

   exec sp_executesql @sql
END

【讨论】:

  • 不推荐这种方法,因为它可能容易受到 SQL 注入的影响(除非调用代码确保@svt 参数的完整性)!
  • 不,这不会导致 SQL 注入。原因是 - 这是一个带有参数的存储过程。所以肯定会使用语言(c# 或 VB.Net)中的 SQL 参数。对吧?
  • @PankajGarg,如果@svt 或@ser 参数由连接用户输入组成,则恶意用户可以在查询中注入任何SQL!
  • 这是内联SQL的情况,而不是参数化查询。
  • @PankajGarg - 你错了。由于 SP 使用参数来动态构建和执行查询,它 对 SQL 注入开放。如果您使用'') select @@version -- 作为@svt 的参数,您将获得带有SQL Server 版本的第二个结果集。你当然可以做比这更狡猾的事情。
【解决方案3】:

这是一个常见错误 - 您将单个字符串类型的值(表达式)传递给 IN 运算符,但 IN 需要一个逗号分隔的值(表达式)列表,而不是单个字符串变量。

您需要在这里做的是有一个函数,它可以根据给定的分隔符将给定的参数拆分为多个值,然后将该列表与IN 关键字一起使用。例如,

SELECT DISTINCT Details from tbData WHERE Name IN (SELECT Val FROM dbo.efn_Split(@svt, ',')) AND Address=@ser

其中efn_Split 是一个表值函数,它将逗号分隔的值拆分到一个表中。请参阅这些各种 SO 问题以实现此类功能:
Split function equivalent in T-SQL?
How to split string using delimiter char using T-SQL?

另一种选择是构造 SQL 语句并使用sp_executesql 执行。

【讨论】:

    【解决方案4】:

    IN 需要如下:

    ... IN (@param1, @param2, ...)

    所以,你应该这样做:

    SELECT DISTINCT Details from tbData WHERE Name IN (@svt) AND Address=@ser
    

    更新:

    您在问题中提供的 alter procedure 语句在语法上不正确。我的回答提供了编写语句的正确语法,并且可以编译。

    再次阅读您的问题,我发现您实际上有两个问题。第一个是语法错误,第二个是在单个参数中传入逗号分隔列表。

    答案是您根本无法在运行时将逗号分隔的值列表提供给IN (...) 子句中使用的单个字符串类型参数。现在,关于第二点,我认为这不是解决问题的好设计/编程方法,但可以使用动态 SQL 或解析字符串参数中的每个值,将它们存储到临时表中,然后修改您的查询加入到那个,或使用(或使用表值函数并将解析的项目存储在那里,可以从中查询。

    以下是代码的更正语法,但它不能解决传递包含逗号分隔值列表的字符串的第二个方面。如上所述,这可以解决。

    对于语法错误,首先,您可以创建一个虚拟表来测试您的代码。注意,一个典型的数据库表应该有一个主键。这严格来说是一个用于测试语句的虚拟表:

    创建表 TbData( 名称 nvarchar(255), 详细信息 nvarchar(255), 地址 nvarchar(255) );

    然后,您可以创建初始存储过程:

    创建过程测试 ( @ser nvarchar(255), @svt nvarchar(255) ) 作为 开始 从 tbData WHERE Name IN (@ser) AND Address = @svt 中选择 DISTINCT 详细信息 结束

    最后,执行您询问过的更改存储过程语句:

    改变程序测试 ( @ser nvarchar(255), @svt nvarchar(255) ) 作为 开始 从 tbData WHERE Name IN (@ser) AND Address = @svt 中选择 DISTINCT 详细信息 结束

    【讨论】:

    • 将查询语句的 where 部分更改为 WHERE (Name IN (@svt) AND Address=@ser) 给了我 Incorrect syntax near ')' 错误。
    • 我认为你误解了这个问题。 @ser 包含一个逗号分隔的值字符串,例如PersonA,PersonB,PersonC,并且 OP 想要匹配任何值的行。您的查询只会返回 name 与整个字符串完全匹配的值。
    • 请不要对语法正确的答案投反对票,并且确实修复了Incorrect syntax 错误。我提供了额外的信息,这些信息应该可以引导您解决第二个问题,即逗号分隔值。我并不是说这是最好的做法,这是有争议的。
    猜你喜欢
    • 2011-08-07
    • 2012-05-09
    • 2011-06-11
    • 1970-01-01
    • 2020-11-24
    • 2018-10-04
    • 1970-01-01
    • 2020-04-23
    • 2016-03-26
    相关资源
    最近更新 更多