Подтвердить что ты не робот

Хранимая процедура с переменным числом параметров

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

cmd.Parameters.Add(new SqlParameter("@id", id)

Может ли кто-нибудь помочь, как я могу передать это переменное количество параметров в хранимой процедуре? Благодаря

4b9b3361

Ответ 1

Вы можете передать его в виде списка, разделенного запятыми, затем использовать функцию split и присоединиться к результатам.

CREATE FUNCTION dbo.SplitInts
(
   @List       VARCHAR(MAX),
   @Delimiter  CHAR(1)
)
RETURNS TABLE
AS
   RETURN 
   (
       SELECT Item = CONVERT(INT, Item)
       FROM
       (
           SELECT Item = x.i.value('(./text())[1]', 'INT')
           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
   );

Теперь ваша хранимая процедура:

CREATE PROCEDURE dbo.doStuff
    @List VARCHAR(MAX)
AS
BEGIN
    SET NOCOUNT ON;

    SELECT cols FROM dbo.table AS t
        INNER JOIN dbo.SplitInts(@List, ',') AS list
        ON t.ID = list.Item;
END
GO

Затем, чтобы назвать это:

EXEC dbo.doStuff @List = '1, 2, 3, ...';

Вы можете увидеть некоторые фон, другие варианты и сравнения производительности здесь:

Однако на SQL Server 2016 или выше вы должны посмотреть STRING_SPLIT() и STRING_AGG():

Ответ 2

Хранимые процедуры поддерживают необязательные параметры. Как и С# 4, вы можете указать значение по умолчанию с помощью =. Например:

create procedure dbo.doStuff(
     @stuffId int = null, 
     @stuffSubId int = null, 
     ...)
as
...

Для параметров, которые вы не хотите передавать, либо установите их на null, либо не добавьте их в cmd.Parameters вообще. Они будут иметь значение по умолчанию в хранимой процедуре

Ответ 3

SQLServer позволяет передать параметр TABLE в хранимую процедуру. Таким образом, вы можете определить тип таблицы, CREATE TYPE LIST_OF_IDS AS TABLE (id int not null primary key), изменить свою процедуру, чтобы принять переменную этого типа (она должна быть только для чтения).

Ответ 4

Рассматривали ли вы с помощью словарь для этой цели? Это позволит вам передавать любое количество параметров в виде пар ключ-значение. Тогда вам нужно просто пройти через словарь и добавить эти параметры в cmd.

void DoStuff(Dictionary<string, object> parameters)
{
    // some code
    foreach(var param in parameters)
    {
        cmd.Parameters.Add(new SqlParameter(param.Key, param.Value);
    }
    // some code
}

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

CREATE PROCEDURE DoStuff(
     @id INT = NULL,
     @value INT = NULL,
     -- the list of parameters with their default values goes here
     )
AS
-- procedure body

Ответ 5

Вот фрагмент кода, который разбивает строку на основе , качестве разделителя. Вы можете даже параметризовать запятую. Он полезен для систем, у которых еще String_split функции String_split:

  DECLARE @startindex INT
  DECLARE @commaindex INT
  DECLARE @paramAsString VARCHAR(MAX) -- this represents the input param
  DECLARE @param VARCHAR (1024)
  DECLARE @paramsTable TABLE(param VARCHAR(1024) NOT NULL) -- the splitted params come here

  SET @startindex = 1
  WHILE @startindex < LEN(@paramAsString)
  BEGIN
    SET @commaindex = CHARINDEX(',', @paramAsString, @startindex)

    IF @commaindex = 0
    BEGIN
      SET @param = SUBSTRING(@paramAsString, @startindex, LEN(@paramAsString))
      SET @startindex = LEN(@settlementEntities)
    END
    ELSE
    BEGIN
      SET @param = SUBSTRING(@paramAsString, @startindex, (@commaindex - @startindex))
      SET @startindex = @commaindex + 1
    END
    IF @se IS NOT NULL AND 0 < LEN(RTRIM(LTRIM(@param)))
    BEGIN
      SET @param = RTRIM(LTRIM(@param))
      INSERT INTO @paramsTable (param) VALUES (@param)
    END
  END