Динамический SQL: OPENROWSET с @param и INSERT в @Table - PullRequest
0 голосов
/ 25 июня 2019

Я пытаюсь вставить в параметр @table, используя OPENROWSET с @param в цикле.Я адаптировал код из: Этот ответ , который демонстрирует использование динамического SQL для вставки параметра.

Код:

DECLARE @BuildTimes TABLE (
    BuildTableName VARCHAR(max) NULL
    ,BuildDate DATE NULL
)

DECLARE @days INT = 0;
DECLARE @startDate DATE = GETDATE();
DECLARE @buildDate DATE = GETDATE();
DECLARE @sql nvarchar(max);

WHILE (@days <=30)
BEGIN
    SET @buildDate = DATEADD(day, -1*@days, @startDate);
    SET @sql='INSERT INTO @BuildTimes
        SELECT * 
        FROM OPENROWSET(
                       ''SQLNCLI'',
                       ''SERVER=localhost;Trusted_Connection=yes;'',
                       ''EXEC [LOG].[BuildTimes] @buildDate = ''''' + CAST(@buildDate AS VARCHAR) +''''''')'

    PRINT @sql
    EXEC(@sql)
    SET @days = @days + 1
END

SELECT * FROM @BuildTimes

Ошибка:

Msg 1087, Level 15, State 2, Line 9
Must declare the table variable "@BuildTimes"

Я попытался запустить OPENROWSET как нединамический SQL без параметра, и все работает правильно.Что я делаю не так?

Ответы [ 3 ]

2 голосов
/ 25 июня 2019

Ваша таблица переменных @BuildTimes недоступна внутри динамического SQL. Даже если вы объявите это и загрузите его с динамическим SQL, вы не сможете прочитать результаты за пределами динамической области.

Решение состоит в том, чтобы использовать временную таблицу вместо переменной:

IF OBJECT_ID('tempdb..#BuildTimes') IS NOT NULL
    DROP TABLE #BuildTimes

CREATE TABLE #BuildTimes (
    BuildTableName VARCHAR(max) NULL
    ,BuildDate DATE NULL
)

DECLARE @days INT = 0;
DECLARE @startDate DATE = GETDATE();
DECLARE @buildDate DATE = GETDATE();
DECLARE @sql nvarchar(max);

WHILE (@days <=30)
BEGIN
    SET @buildDate = DATEADD(day, -1*@days, @startDate);
    SET @sql='INSERT INTO #BuildTimes
        SELECT * 
        FROM OPENROWSET(
                       ''SQLNCLI'',
                       ''SERVER=localhost;Trusted_Connection=yes;'',
                       ''EXEC [LOG].[BuildTimes] @buildDate = ''''' + CAST(@buildDate AS VARCHAR) +''''''')'

    PRINT @sql
    EXEC(@sql)
    SET @days = @days + 1
END

SELECT * FROM #BuildTimes

Таблица может быть прочитана вне EXEC, потому что она была создана снаружи, и она доступна внутри, потому что она остается в том же сеансе.

В качестве примечания, избегайте использования * всякий раз, когда вы ожидаете известный набор столбцов, поэтому, если новый столбец будет добавлен в базовые таблицы из SELECT, вы INSERT не сломаетесь.

1 голос
/ 25 июня 2019

Зачем вообще использовать динамический SQL, а не просто INSERT INTO?

DECLARE @BuildTimes table (BuildTableName varchar(MAX) NULL,
                           BuildDate date NULL);

DECLARE @days int = 0;
DECLARE @startDate date = GETDATE();
DECLARE @buildDate date = GETDATE();

WHILE (@days <= 30)
BEGIN

    SET @buildDate = DATEADD(day, -1*@days, @startDate);    
    INSERT INTO @BuildTimes (BuildTableName,
                             BuildDate)
    EXEC log.BuildTimes @buildDate;

    SET @days = @days + 1;

END;

SELECT BuildTableName,
       BuildDate
FROM @BuildTimes;
0 голосов
/ 25 июня 2019

Я обнаружил, что мне вообще не нужен динамический SQL / OPENROWSET для этого сценария.Следующий код дает желаемый результат:

DECLARE @BuildTimes TABLE (
    BaseTableName VARCHAR(max) NULL
    ,BuildDate DATE NULL
    ,StartDateTime DATETIME NULL
    ,FinishDateTime DATETIME NULL
    ,TimeTakenMinutes BIGINT NULL
)

DECLARE @days INT = 0;
DECLARE @startDate DATE = GETDATE();
DECLARE @thisBuildDate DATE = GETDATE();

WHILE (@days <=30)
BEGIN
    SET @thisBuildDate = DATEADD(day, -1*@days, @startDate);
    PRINT @thisBuildDate

    INSERT INTO @BuildTimes
    EXEC [LOG].[BuildTimes] @buildDate = @thisBuildDate
    SET @days = @days + 1
END

SELECT * FROM @BuildTimes
GO
...