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

时间:2008-09-04 06:27:27

标签: sql-server tsql stored-procedures

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

例如,我希望我的存储过程返回的部门1,2,5,7,20。在过去,我已经通过逗号分隔的id列表,如下面的代码,但感觉真的很脏。

我认为SQL Server 2005是我唯一适用的限制。

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

6 个答案:

答案 0 :(得分:230)

过去16年来,Erland Sommarskog一直保持对这个问题的权威答案: Arrays and Lists in SQL Server

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

我真的不能建议read the article来了解所有这些选项之间的权衡。

答案 1 :(得分:11)

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

我找到的最佳解决方案是使用将文本拆分为单词的函数(此处发布了一些,或者您可以使用this one from my blog),然后将其加入到您的表中。类似的东西:

SELECT d.[Name]
FROM Department d
    JOIN dbo.SplitWords(@DepartmentIds) w ON w.Value = d.DepartmentId

答案 2 :(得分:4)

您可以使用XML。

E.g。

declare @xmlstring as  varchar(100) 
set @xmlstring = '<args><arg value="42" /><arg2>-1</arg2></args>' 

declare @docid int 

exec sp_xml_preparedocument @docid output, @xmlstring

select  [id],parentid,nodetype,localname,[text]
from    openxml(@docid, '/args', 1) 

命令sp_xml_preparedocument是内置的。

这将产生输出:

id  parentid    nodetype    localname   text
0   NULL        1           args        NULL
2   0           1           arg         NULL
3   2           2           value       NULL
5   3           3           #text       42
4   0           1           arg2        NULL
6   4           3           #text       -1

拥有你所需要的所有(更多?)。

答案 3 :(得分:3)

如果您要使用这些值,可能需要考虑的一种方法是首先将它们写入临时表。然后你就像平常一样加入它。

这样,你只需解析一次。

最简单的方法是使用其中一个'Split'UDF,但是有很多人发布了这些例子,我想我会走另一条路;)

这个例子将创建一个临时表供你加入(#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 Dept.Name 
FROM Departments 
JOIN #tmpDept ON Departments.DepartmentID=#tmpDept.DeptID
ORDER BY Dept.Name

您会看到传入的所有部门ID的名称......

同样,这可以通过使用一个函数来填充临时表来简化...我主要是在没有一个只是为了杀死一些无聊的事情:-P

- Kevin Fairchild

答案 4 :(得分:1)

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

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 Brad Schulz's Blog

答案 5 :(得分:-2)

试试这个:

@list_of_params varchar(20) -- value 1, 2, 5, 7, 20 

SELECT d.[Name]
FROM Department d
where @list_of_params like ('%'+ CONVERT(VARCHAR(10),d.Id)  +'%')
很简单。