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

StackOverflow https://stackoverflow.com/questions/43249

Вопрос

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

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

Решение

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

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

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

Другие советы

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

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

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

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

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

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

Таким образом, вы выполняете синтаксический анализ только один раз.

Проще всего использовать один из "Разделенных" 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

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

Сверхбыстрый 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)  +'%')

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top