Хранимая процедура T-SQL, которая принимает несколько значений Id - PullRequest
145 голосов
/ 04 сентября 2008

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

Например, я хочу, чтобы отделы 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 ]

230 голосов
/ 04 сентября 2008

Эрланд Соммарског поддерживает авторитетный ответ на этот вопрос в течение последних 16 лет: Массивы и списки в SQL Server .

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

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

11 голосов
/ 04 сентября 2008

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

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

SELECT d.[Name]
FROM Department d
    JOIN dbo.SplitWords(@DepartmentIds) w ON w.Value = d.DepartmentId
4 голосов
/ 04 сентября 2008

Вы можете использовать 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

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

3 голосов
/ 04 сентября 2008

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

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

Проще всего использовать один из «разделенных» UDF, но так много людей опубликовали примеры, я подумал, что пойду другим путем;)

В этом примере будет создана временная таблица, к которой вы будете присоединяться (#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

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

1 голос
/ 04 марта 2013

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

Вся заслуга принадлежит Гуру Блог Брэда Шульца

0 голосов
/ 31 октября 2012

Попробуйте это:

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

очень просто.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...