Как передать список в качестве параметра в хранимой процедуре?
Глядя на передачу списка идентификаторов пользователей, чтобы вернуть имена списков. У меня есть план обработки выданных имен (с COALESCE что-то или другое), но попытка найти лучший способ передать список идентификаторов пользователей.
Чувства моего sproc будут выглядеть примерно так:
create procedure [dbo].[get_user_names]
@user_id_list, --which would equal a list of incoming ID numbers like (5,44,72,81,126)
@username varchar (30) output
as
select last_name+', '+first_name
from user_mstr
where user_id in @user_id_list
Передача значений для @user_id_list - моя главная проблема здесь.
Ответы
Ответ 1
Предпочтительным методом передачи массива значений хранимой процедуре в SQL-сервере является использование табличных параметров.
Сначала вы определяете тип следующим образом:
CREATE TYPE UserList AS TABLE ( UserID INT );
Затем вы используете этот тип в хранимой процедуре:
create procedure [dbo].[get_user_names]
@user_id_list UserList READONLY,
@username varchar (30) output
as
select last_name+', '+first_name
from user_mstr
where user_id in (SELECT UserID FROM @user_id_list)
Итак, прежде чем вы вызываете эту хранимую процедуру, вы заполняете переменную таблицы:
DECLARE @UL UserList;
INSERT @UL VALUES (5),(44),(72),(81),(126)
И, наконец, вызовите SP:
EXEC dbo.get_user_names @UL, @username OUTPUT;
Ответ 2
Насколько я могу судить, есть три основных претендента: Табличные параметры, строка списка с разделителями и строка JSON.
С 2016 года вы можете использовать встроенный STRING_SPLIT, если вам нужен маршрут с разделителями: https://docs.microsoft.com/en-us/sql/t-sql/functions/string-split-transact-sql
Вероятно, это будет самый простой/самый простой/простой подход.
Также с 2016 года JSON может передаваться как nvarchar и использоваться с OPENJSON: https://docs.microsoft.com/en-us/sql/t-sql/functions/openjson-transact-sql
Это, вероятно, лучше, если у вас есть более структурированный набор данных для передачи, который может быть значительно изменчив в своей схеме.
Кажется, что TVP раньше были каноническим способом передачи более структурированных параметров, и они все еще хороши, если вам нужна такая структура, явность и базовая проверка значения/типа. Хотя они могут быть немного более громоздкими для потребителя. Если у вас нет 2016+, это, вероятно, вариант по умолчанию/лучший.
Я думаю, что это компромисс между любым из этих конкретных соображений, а также вашим предпочтением быть явным относительно структуры ваших параметров, то есть, даже если у вас 2016+, вы можете предпочесть явно указать тип/схему параметра, а не чем передать строку и разобрать ее как-нибудь.
Ответ 3
Я решил эту проблему следующим образом:
- В С# я построил переменную String.
string userId = "";
- Я помещаю свой элемент списка в эту переменную. Я разделил ",".
например: в С#
userId= "5,44,72,81,126";
и отправить на SQL-сервер
SqlParameter param = cmd.Parameters.AddWithValue("@user_id_list",userId);
- Я создаю раздельную функцию в SQL-сервере. Для преобразования моего полученного списка (типа
NVARCHAR(Max)
) в таблицу.
CREATE FUNCTION dbo.SplitInts
(
@List VARCHAR(MAX),
@Delimiter VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM
( SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(@List, @Delimiter, '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
- В основной процедуре Хранилища, используя приведенную ниже команду, я использую список записей.
SELECT user_id = элемент FROM dbo.SplitInts(@user_id_list, ',');
Ответ 4
Вы можете попробовать следующее:
create procedure [dbo].[get_user_names]
@user_id_list varchar(2000), -- You can use any max length
@username varchar (30) output
as
select last_name+', '+first_name
from user_mstr
where user_id in (Select ID from dbo.SplitString( @user_id_list, ',') )
И вот пользовательская функция для SplitString:
Create FUNCTION [dbo].[SplitString]
(
@Input NVARCHAR(MAX),
@Character CHAR(1)
)
RETURNS @Output TABLE (
Item NVARCHAR(1000)
)
AS
BEGIN
DECLARE @StartIndex INT, @EndIndex INT
SET @StartIndex = 1
IF SUBSTRING(@Input, LEN(@Input) - 1, LEN(@Input)) <> @Character
BEGIN
SET @Input = @Input + @Character
END
WHILE CHARINDEX(@Character, @Input) > 0
BEGIN
SET @EndIndex = CHARINDEX(@Character, @Input)
INSERT INTO @Output(Item)
SELECT SUBSTRING(@Input, @StartIndex, @EndIndex - 1)
SET @Input = SUBSTRING(@Input, @EndIndex + 1, LEN(@Input))
END
RETURN
END
Ответ 5
Azure DB, Azure Data WH и SQL Server 2016, вы можете использовать STRING_SPLIT для достижения результата, аналогичного описанному @sparrow.
Переработка кода из @sparrow
where user_id in (Select value from STRING_SPLIT( @user_id_list, ',')
Простой и эффективный способ принятия списка значений в хранимую процедуру
Ответ 6
Возможно, вы могли бы использовать:
select last_name+', '+first_name
from user_mstr
where ',' + @user_id_list + ',' like '%,' + convert(nvarchar, user_id) + ',%'
Ответ 7
Вы можете использовать этот простой метод inline для построения параметра string_list_type (работает в SQL Server 2014):
declare @p1 dbo.string_list_type
insert into @p1 values(N'myFirstString')
insert into @p1 values(N'mySecondString')
Пример использования хранимой процедуры:
exec MyStoredProc @[email protected]