Выполнить функцию с несколькими значениями в одном параметре

У меня есть функция SQL, которая принимает параметр как BIGINT, как показано ниже:

FUNCTION [dbo].[fn_doc]
(
     @DocID         bigint           
)

Я хочу передать несколько идентификаторов документов и получить результаты. Для чего я делаю так:

declare @DocID   bigint
SET @DocID = (2949146,2949148,2949149,14016926,14025278,14016928,14016928,14025280,14025280)
select * from [fn_doc] (@DocID)

Мой вопрос: как в этом случае выполнить функцию с несколькими значениями для одного параметра?


person AskMe    schedule 31.10.2016    source источник
comment
Исследуйте в Интернете табличныеценные параметры P.   -  person TT.    schedule 31.10.2016
comment
Любая примерная ссылка, пожалуйста, для этого конкретного сценария?   -  person AskMe    schedule 31.10.2016
comment
Все сценарии одинаковые. Если вам нужно передать список значений в качестве параметра функции или SP, используйте TVP. Это общий совет. Много всего можно найти в Интернете, если вы ищете sql server table valued parameter. ГЛ!   -  person TT.    schedule 31.10.2016
comment
Привет! Этот вопрос решен? Вам нужна дополнительная помощь? Пожалуйста, позвольте мне одну подсказку: если этот вопрос решен, было бы очень любезно с вашей стороны поставить галочку напротив счетчика голосов за (лучший) ответ. Это 1) пометит эту проблему как решенную 2) подписчикам будет легче найти лучшее решение 3) заплатит баллы отвечающему и 4) заплатит баллы вам. Поскольку вы сами пересекли границу в 15 баллов, вас дополнительно попросят проголосовать за вклад. Это ТАК-способ сказать спасибо. Удачного кодирования!   -  person Shnugo    schedule 07.11.2016


Ответы (3)


Это не может работать

declare @DocID   bigint
SET @DocID = (2949146,2949148,2949149,14016926,14025278,14016928,14016928,14025280,14025280)

Переменная, объявленная как BIGINT, не может содержать ничего, кроме большого числа...

Вы пытаетесь передать строку с разделителями-запятыми, которая представляет собой список чисел.

Для этого нет встроенного функционала. Ни IN, ни какой-либо JOIN не будут делать это изначально.

У вас есть несколько вариантов

  • Динамический SQL для создания оператора select в виде строки и использования EXEC для получения результата (что-то вроде WHERE docid IN(100,200,300))
  • Создайте таблицу (переменную, временную или классическую), заполните ее своими значениями и используйте IN или JOIN в своей функции (у этого будут проблемы с параллельными действиями!)
  • Создайте TYPE для передачи списка в виде таблицы
  • Используйте какую-то операцию разделения, чтобы получить производную таблицу. Для этого варианта вы можете прочитать этот ответ (раздел "динамический IN")

Вот пост со списком подходов

person Shnugo    schedule 31.10.2016

быстро и грязно, но должно работать :-) это пример последнего предложения Shnugo

CREATE FUNCTION [dbo].[fn_doc] (@DocID as bigint)
RETURNS bigint
AS
BEGIN
    RETURN @DocID
END

/* your function parameter is a comma seperated list */
DECLARE @Parameter VARCHAR(200)
SET @Parameter = '2949146,2949148,2949149,14016926,14025278,14016928,14016928,14025280,14025280'

/* start and end current parameter */
DECLARE @start int, @end int
SET @start = 0
SET @end = 1

/* current parameter */
DECLARE @p NVARCHAR(200)

WHILE @end > 0
BEGIN
    SET @end = CHARINDEX(',', @Parameter, @start)
    IF @start < @end
       IF ISNUMERIC(SUBSTRING(@Parameter, @start, @end-@start)) = 1 
          SET @p = SUBSTRING(@Parameter, @start, @end-@start)
          PRINT [dbo].[fn_doc] (@p)
    SET @start = @end +1
END
person tgr    schedule 31.10.2016
comment
Это может быть грязно, но - точно! - это не быстро. - person Shnugo; 31.10.2016

Судя по всему, вы еще не вышли из леса. Итак, я оставлю вас с примером.


Создайте тип TABLE:

CREATE TYPE dbo.document_ids AS TABLE (
    document_id BIGINT
);
GO

Если вы можете гарантировать, что в качестве параметра будут переданы только различные значения document_id, вы можете извлечь выгоду из определения первичного ключа в поле document_id:

CREATE TYPE dbo.document_ids AS TABLE (
    document_id BIGINT PRIMARY KEY
);
GO

Создайте функции, зависящие от этого типа TABLE, одну со скалярным значением и одну с табличным значением:

CREATE FUNCTION dbo.fn_doc_sv (
    @doc_ids dbo.document_ids READONLY
)
RETURNS BIGINT
AS
BEGIN
    RETURN (SELECT SUM(document_id) FROM @doc_ids); 
END
GO

CREATE FUNCTION dbo.fn_doc_tv (
    @doc_ids dbo.document_ids READONLY
)
RETURNS TABLE
AS
    RETURN (SELECT document_id FROM @doc_ids);
GO

Использование обеих функций:

DECLARE @doc_ids dbo.document_ids;
INSERT INTO @doc_ids(document_id)VALUES(2949146),(2949148),(2949149),(14016926),(14025278),(14016928),(14016928),(14025280),(14025280);

SELECT dbo.fn_doc_sv(@doc_ids);

SELECT * FROM dbo.fn_doc_tv(@doc_ids);

Надеюсь, это проясняет для вас.

person TT.    schedule 01.11.2016