Хранимая процедура 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 Server 2008 и выше, и, вероятно, ближе всего к универсальному "лучшему" подходу.
- в Итерационный Метод. Передайте строку с разделителями и выполните цикл через нее.
- использование CLR. SQL Server 2005 и выше только на языках .NET.
- XML. Очень хорошо для вставки многих строк; может быть излишним для выбора.
- таблица чисел. Высокая производительность/сложность, чем простой итерационный метод.
- элементы фиксированной длины. Фиксированная длина улучшает скорость над разделителями строка
Да, ваше текущее решение подвержено атакам 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) +'%')
очень удобно.