Sql server 接受多个Id值的T-SQL存储过程

Sql server 接受多个Id值的T-SQL存储过程,sql-server,tsql,stored-procedures,Sql Server,Tsql,Stored Procedures,是否有一种优雅的方法来处理将ID列表作为参数传递给存储过程 例如,我希望存储过程返回部门1、2、5、7、20。在过去,我传递了一个以逗号分隔的ID列表,如下面的代码,但这样做真的让我感觉脏兮兮的 我认为SQLServer2005是我唯一适用的限制 create procedure getDepartments @DepartmentIds varchar(max) as declare @Sql varchar(max) select @Sql = 'select [Nam

是否有一种优雅的方法来处理将ID列表作为参数传递给存储过程

例如,我希望存储过程返回部门1、2、5、7、20。在过去,我传递了一个以逗号分隔的ID列表,如下面的代码,但这样做真的让我感觉脏兮兮的

我认为SQLServer2005是我唯一适用的限制

create procedure getDepartments
  @DepartmentIds varchar(max)
as
  declare @Sql varchar(max)     
  select @Sql = 'select [Name] from Department where DepartmentId in (' + @DepartmentIds + ')'
  exec(@Sql)

是的,您当前的解决方案容易受到SQL注入攻击

我发现的最好的解决方案是使用一个函数,将文本拆分为单词。这里发布了一些单词,或者您可以使用它,然后将其加入到表中。比如:

SELECT d.[Name]
FROM Department d
    JOIN dbo.SplitWords(@DepartmentIds) w ON w.Value = d.DepartmentId
SELECT Dept.Name 
FROM Departments 
JOIN #tmpDept ON Departments.DepartmentID=#tmpDept.DeptID
ORDER BY Dept.Name
您可以使用XML

例如


哪个更重要?您需要什么。

过去16年来,Erland Sommarskog一直保持对这个问题的权威答案:

至少有十几种方法可以将数组或列表传递给查询;每个人都有自己独特的优点和缺点

. 仅限SQL Server 2008及更高版本,可能是最接近通用最佳方法的。 . 传递一个带分隔符的字符串并在其中循环。 . 仅限.NET语言的SQL Server 2005及更高版本。 . 非常适合插入多行;这可能有点过分了。 . 比简单的迭代方法具有更高的性能/复杂性。 . 固定长度提高了分隔字符串的速度 . 数字表和固定长度的变体,其中数字是在函数中生成的,而不是从表中获取的。 CTE。SQLServer2005及更高版本,仍然不会比迭代方法太复杂和更高的性能。 . 可能会很慢,并且会影响安全。 通过列表作为。繁琐且容易出错,但很简单。 . 使用charindex、patindex或类似方法的方法。
我真的不能推荐足够的知识来了解所有这些选项之间的权衡。

一个方法,你可能要考虑的是,如果你要大量使用这些值,首先要把它们写到一个临时表中。然后你就像平常一样加入

这样,您只需要解析一次

使用一个“拆分”自定义项是最容易的,但是有这么多人发布了这些例子,我想我应该走另一条路

本例将创建一个临时表,供您加入tmpDept,并用传入的部门id填充它。我假设你用逗号分隔它们,但是你当然可以把它改成你想要的任何形式

IF OBJECT_ID('tempdb..#tmpDept', 'U') IS NOT NULL
BEGIN
    DROP TABLE #tmpDept
END

SET @DepartmentIDs=REPLACE(@DepartmentIDs,' ','')

CREATE TABLE #tmpDept (DeptID INT)
DECLARE @DeptID INT
IF IsNumeric(@DepartmentIDs)=1
BEGIN
    SET @DeptID=@DepartmentIDs
    INSERT INTO #tmpDept (DeptID) SELECT @DeptID
END
ELSE
BEGIN
        WHILE CHARINDEX(',',@DepartmentIDs)>0
        BEGIN
            SET @DeptID=LEFT(@DepartmentIDs,CHARINDEX(',',@DepartmentIDs)-1)
            SET @DepartmentIDs=RIGHT(@DepartmentIDs,LEN(@DepartmentIDs)-CHARINDEX(',',@DepartmentIDs))
            INSERT INTO #tmpDept (DeptID) SELECT @DeptID
        END
END
这将允许您传入一个部门id,多个id之间带有逗号,甚至多个id之间带有逗号和空格

所以,如果你做了如下事情:

SELECT d.[Name]
FROM Department d
    JOIN dbo.SplitWords(@DepartmentIds) w ON w.Value = d.DepartmentId
SELECT Dept.Name 
FROM Departments 
JOIN #tmpDept ON Departments.DepartmentID=#tmpDept.DeptID
ORDER BY Dept.Name
您将看到您传入的所有部门ID的名称

同样,这可以通过使用函数填充临时表来简化。。。我这样做主要是为了消磨一些无聊


-Kevin Fairchild

如果要使用存储过程并传递以逗号分隔的部门ID列表,请使用超高速XML方法:

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

所有的功劳都归于Guru

我不确定它是否容易受到SQL注入攻击,除非存储的进程可以直接从不受信任的客户端调用,在这种情况下,您会遇到更大的问题。服务层代码应该从强类型数据(例如int[]DepartmentIds)生成@DepartmentIds字符串,在这种情况下就可以了。非常好的解决方案,@Matt Hamilton。不知道这是否对任何人都有帮助,但当我使用join dbo搜索文本字段时,我在SQLServer2008R上得到了更准确的结果。SplitWords@MyParameterArrayp在CHARINDEXp.value上,d.MyFieldToSearch>0是我刚找到的XML方法的变体。如果您使用的是SQL Server 2008,则可以使用表值参数。这对我很有帮助: