web-dev-qa-db-ja.com

可変数のパラメーターを持つストアード・プロシージャー

パラメータを渡さなければならないプロシージャを格納しましたが、問題は、パラメータがいくつ来るかわからないことです。1になる可能性があり、次の実行では5になる可能性があります。

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

ストアドプロシージャでこれらの可変数のパラメータを渡す方法を教えてもらえますか?ありがとう

19
CPDS

それをコンマ区切りのリストとして渡してから、分割関数を使用して、結果に対して結合することができます。

_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() を確認する必要があります。

20
Aaron Bertrand

ストアドプロシージャはオプションのパラメータをサポートします。 C#4と同様に、=を使用してデフォルト値を指定できます。例えば:

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

渡したくないパラメーターについては、nullに設定するか、cmd.Parametersにまったく追加しないでください。ストアドプロシージャにはデフォルト値があります

6
Andomar

SQLServerでは、TABLEパラメータをストアドプロシージャに渡すことができます。したがって、テーブルタイプCREATE TYPE LIST_OF_IDS AS TABLE (id int not null primary key)を定義し、このタイプの変数を受け入れるようにプロシージャを変更できます(読み取り専用である必要があります)。

5
a1ex07

その目的で 辞書 を使用することを検討しましたか?これにより、任意の数のパラメーターをキーと値のペアとして渡すことができます。次に、辞書を調べて、それらのパラメーターを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
2
Li0liQ

これは、区切り文字として,に基づいて文字列を分割するコードスニペットです。カンマをパラメータ化することもできます。これは、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
0
Tamas Rev