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

sql-server tsql stored-procedures

137141 просмотра

6 ответа

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

Например, я хочу, чтобы отделы 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)
Автор: JasonS Источник Размещён: 12.09.2019 01:48

Ответы (6)


231 плюса

Решение

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

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

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

Автор: Portman Размещён: 04.09.2008 01:32

11 плюса

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

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

SELECT d.[Name]
FROM Department d
    JOIN dbo.SplitWords(@DepartmentIds) w ON w.Value = d.DepartmentId
Автор: Matt Hamilton Размещён: 04.09.2008 06:55

3 плюса

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

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

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

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

Автор: Kevin Fairchild Размещён: 04.09.2008 04:36

3 плюса

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

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

Автор: Unsliced Размещён: 04.09.2008 07:05

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))

Вся заслуга в блоге Гуру Брэда Шульца

Автор: Nishant Размещён: 03.03.2013 10:19

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

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

Автор: user1006743 Размещён: 31.10.2012 03:12
Вопросы из категории :
32x32