Массоподобный доступ к переменным в T-SQL - PullRequest
8 голосов
/ 15 мая 2009

В моей хранимой процедуре у меня есть несколько похожих переменных @V1, @V2 ... @V20 (скажем, 20 из них), извлеченных из записи. Как бы я использовал динамический SQL для 20 вызовов другой хранимой процедуры, используя эти переменные в качестве параметров?

Конечно, @V[i] синтаксис неверен, но он выражает намерение

    fetch next from maincursor into @status, @V1, @V2, ...

    while @i<21
    begin
       -- ??? execute sp_executesql 'SecondSP', '@myParam int', @myParam=@V[i]
       -- or 
       -- ??? execute SecondSP @V[i]
       set @i = @i+1
    end

Ответы [ 4 ]

17 голосов
/ 15 мая 2009

Как уже говорили другие, настройте временную таблицу, вставьте в нее нужные вам значения. Затем «переберите» его, выполнив необходимый SQL из этих значений. Это позволит вам иметь от 0 до МНОГИЕ значения для выполнения, поэтому вам не нужно устанавливать переменную для каждого.

Ниже приведен полный пример того, как вы можете делать это без курсоров.

SET NOCOUNT ON

DECLARE @dict TABLE (
                    id          INT IDENTITY(1,1), -- a unique identity column for reference later
                    value       VARCHAR(50),       -- your parameter value to be passed into the procedure
                    executed    BIT                -- BIT to mark a record as being executed later
                    )

-- INSERT YOUR VALUES INTO @dict HERE
-- Set executed to 0 (so that the execution process will pick it up later)
-- This may be a SELECT statement into another table in your database to load the values into @dict
INSERT @dict
SELECT 'V1Value', 0 UNION ALL
SELECT 'V2Value', 0

DECLARE @currentid INT
DECLARE @currentvalue VARCHAR(50)
WHILE EXISTS(SELECT * FROM @dict WHERE executed = 0)
BEGIN
    -- Get the next record to execute
    SELECT 
    TOP 1   @currentid = id 
    FROM    @dict 
    WHERE   executed = 0

    -- Get the parameter value
    SELECT  @currentvalue = value
    FROM    @dict
    WHERE   id = @currentid

    -- EXECUTE THE SQL HERE
    --sp_executesql 'SecondSP', '@myParam int', @myParam = 
    PRINT   'SecondSP ' +  '@myParam int ' + '@myParam = ' + @currentvalue

    -- Mark record as having been executed
    UPDATE  d
    SET     executed = 1
    FROM    @dict d
    WHERE   id = @currentid
END
2 голосов
/ 15 мая 2009

Использовать # TempTable

Если вы находитесь на SQL Server 2005, вы можете создать #TempTable в родительской хранимой процедуре, и она доступна в дочерней хранимой процедуре, которую она вызывает.

CREATE TABLE #TempTable
(col1  datatype
,col2  datatype
,col3  datatype
)

INSERT INTO #TempTable
    (col1, col2, col3)
    SELECT 
        col1, col2, col3
        FROM ...

EXEC @ReturnCode=YourOtherProcedure

в рамках другой процедуры у вас есть доступ к #TempTable для выбора, удаления и т. Д. заставить эту дочернюю процедуру работать с набором данных, а не с одним элементом за раз

Помните, что в SQL циклы высасывают производительность!

0 голосов
/ 15 мая 2009

Это похоже на странный запрос - у вас всегда будет фиксированный набор переменных? Что если число изменится с 20 на 21 и т. Д., Вам постоянно придется объявлять новые переменные?

Возможно ли вместо извлечения значений в отдельные переменные возвращать их каждый в виде отдельных строк и просто проходить по ним в курсоре?

Если нет, и вы должны использовать отдельные переменные, как описано, вот одно из решений:

declare @V1 nvarchar(100)
set @V1 = 'hi'
declare @V2 nvarchar(100)
set @V2 = 'bye'
declare @V3 nvarchar(100)
set @V3 = 'test3'
declare @V4 nvarchar(100)
set @V4 = 'test4'
declare @V5 nvarchar(100)
set @V5 = 'end'

declare aCursor cursor for
select @V1 
union select @V2 union select @V3
union select @V4 union select @V5

open aCursor

declare @V nvarchar(100)
fetch next from aCursor into @V
while @@FETCH_STATUS = 0
begin
    exec TestParam @V

    fetch next from aCursor into @V

end

close aCursor
deallocate aCursor

Мне не очень нравится это решение, оно кажется грязным и не масштабируемым. Кроме того, в качестве дополнительного примечания - то, как вы сформулировали свой вопрос, похоже, спрашивает, есть ли массивы в T-SQL. По умолчанию их нет, хотя быстрый поиск в Google может указать вам обходные пути для этого, если они вам абсолютно необходимы.

0 голосов
/ 15 мая 2009

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

По сути, каждая строка в таблице рассматривается как ячейка массива с таблицей, содержащей один столбец.

Просто мысль. :)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...