Хранимая процедура T-SQL, которая принимает несколько значений Id

есть ли изящный способ обработки передачи списка идентификаторов в качестве параметра хранимой процедуре?

например, я хочу, чтобы отделы 1, 2, 5, 7, 20, возвращенный моей хранимой процедуры. В прошлом я передал список идентификаторов с разделителями-запятыми, как показано ниже, но чувствую себя очень грязным.

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 ответов


Ерланд сайт sommarskog поддерживал авторитетный ответ на этот вопрос за последние 16 лет: массивы и списки в SQL Server.

существует по крайней мере дюжина способов передать массив или список в запрос; каждый из них имеет свои уникальные плюсы и минусы.


Да, ваше текущее решение подвержено атакам SQL-инъекций.

лучшее решение, которое я нашел, - использовать функцию, которая разбивает текст на слова (здесь есть несколько сообщений, или вы можете использовать это из моего блога), а затем присоединитесь к своему столу. Что-то вроде:

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

один из методов, который вы можете рассмотреть, если вы собираетесь много работать со значениями, - это сначала записать их во временную таблицу. Тогда просто присоединяйся к нему, как обычно.

таким образом, вы анализируете только один раз.

проще всего использовать один из "Split" UDFs, но так много людей опубликовали примеры из них, я решил, что пойду другим путем;)

в этом примере будет создана временная таблица для присоединения (#tmpDept) и заполнения ее удостоверение департамента, которое вы сдали. Я предполагаю, что вы разделите их запятыми, но вы можете, конечно, изменить его на что угодно.

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

Это позволит вам передать один идентификатор отдела, несколько идентификаторов с запятыми между ними или даже несколько идентификаторов с запятыми и пробелами между ними.

Так что если вы сделали что-то вроде:

SELECT Dept.Name 
FROM Departments 
JOIN #tmpDept ON Departments.DepartmentID=#tmpDept.DeptID
ORDER BY Dept.Name

вы увидите имена всех идентификаторов отдела,которые вы передали...

снова, это можно упростить, используя функцию для заполнения временной таблицы... Я в основном делал это без одного, чтобы убить скуку : - P

-- Кевин Фэйрчайлд


вы можете использовать XML.

Е. Г.

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

который имеет все (больше?) того, что тебе нужно.


сверхбыстрый метод 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))

весь кредит идет гуру блог Брэда Шульца


Попробуй Это:

@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)  +'%')

очень удобно.