Есть ли способ сохранить переменную на ходу? - PullRequest
72 голосов
/ 02 июня 2009

Есть ли способ сохранить переменную на ходу?

Declare @bob as varchar(50);
Set @bob = 'SweetDB'; 
GO
USE @bob  --- see note below
GO
INSERT INTO @bob.[dbo].[ProjectVersion] ([DB_Name], [Script]) VALUES (@bob,'1.2')

См. Этот SO вопрос для строки 'USE @bob'.

Ответы [ 8 ]

103 голосов
/ 02 июня 2009

Использовать временную таблицу:

CREATE TABLE #variables
    (
    VarName VARCHAR(20) PRIMARY KEY,
    Value VARCHAR(255)
    )
GO

Insert into #variables Select 'Bob', 'SweetDB'
GO

Select Value From #variables Where VarName = 'Bob'
GO

DROP TABLE #variables
go
29 голосов
/ 02 июня 2009

Команда go используется для разделения кода на отдельные пакеты. Если это именно то, что вы хотите сделать, то вам следует использовать его, но это означает, что пакеты на самом деле разделены, и вы не можете делить переменные между ними.

В вашем случае решение простое; Вы можете просто удалить операторы go, они не нужны в этом коде.

Примечание: Вы не можете использовать переменную в операторе use, это должно быть имя базы данных.

12 голосов
/ 18 июня 2015

Я предпочитаю этот ответ на этот вопрос Глобальные переменные с GO

Что дает дополнительное преимущество, заключающееся в возможности делать то, что вы изначально хотели сделать.

Предостережение заключается в том, что вам нужно включить режим SQLCMD (в разделе Query-> SQLCMD) или включить его по умолчанию для всех окон запросов (Инструменты-> Параметры, затем Результаты запроса-> По умолчанию, открывать новые запросы в режиме SQLCMD. )

Затем вы можете использовать следующий тип кода (полностью сорванный с того же ответа Оскар Э. Фракседас Тормо )

--Declare the variable
:setvar MYDATABASE master
--Use the variable
USE $(MYDATABASE);
SELECT * FROM [dbo].[refresh_indexes]
GO
--Use again after a GO
SELECT * from $(MYDATABASE).[dbo].[refresh_indexes];
GO
1 голос
/ 31 августа 2017

Если вы используете SQL Server, вы можете настроить глобальные переменные для целых сценариев, например:

:setvar sourceDB "lalalallalal"

и использовать позже в скрипте как:

$(sourceDB)

Убедитесь, что режим SQLCMD включен в Server Managment Studi. Это можно сделать через главное меню. Нажмите Query и включите режим SQLCMD.

Подробнее о теме можно узнать здесь: Документация MS

1 голос
/ 02 июня 2009

Не уверен, поможет ли это

declare @s varchar(50)
set @s='Northwind'

declare @t nvarchar(100)
set @t = 'select * from ' + @s + '.[dbo].[Customers]'

execute sp_executesql @t
0 голосов
/ 07 июня 2019

Если вам просто нужен двоичный файл да / нет (например, если столбец существует), тогда вы можете использовать SET NOEXEC ON, чтобы отключить выполнение операторов. SET NOEXEC ON работает через GO (через партии). Но не забудьте включить EXEC обратно на с SET NOEXEC OFF в конце скрипта.

IF COL_LENGTH('StuffTable', 'EnableGA') IS NOT NULL
    SET NOEXEC ON -- script will not do anything when column already exists

ALTER TABLE dbo.StuffTable ADD EnableGA BIT NOT NULL CONSTRAINT DF_StuffTable_EnableGA DEFAULT(0)
ALTER TABLE dbo.StuffTable SET (LOCK_ESCALATION = TABLE)
GO
UPDATE dbo.StuffTable SET EnableGA = 1 WHERE StuffUrl IS NOT NULL
GO
SET NOEXEC OFF

Это компилирует операторы, но не выполняет их. Таким образом, вы все равно получите «ошибки компиляции», если будете ссылаться на несуществующую схему. Так что он работает, чтобы «отключить» скрипт 2-го запуска (что я делаю), но не работает, чтобы отключить части скрипта при 1-м запуске, потому что вы все равно получите ошибки компиляции, если ссылаетесь на столбцы или таблицы, еще не существует

0 голосов
/ 06 апреля 2019

Создайте свои собственные хранимые процедуры, которые сохраняют / загружают во временную таблицу.

MyVariableSave   -- Saves variable to temporary table. 
MyVariableLoad   -- Loads variable from temporary table.

Тогда вы можете использовать это:

print('Test stored procedures for load/save of variables across GO statements:')

declare @MyVariable int = 42
exec dbo.MyVariableSave @Name = 'test', @Value=@MyVariable
print('  - Set @MyVariable = ' + CAST(@MyVariable AS VARCHAR(100)))

print('  - GO statement resets all variables')
GO -- This resets all variables including @MyVariable

declare @MyVariable int
exec dbo.MyVariableLoad 'test', @MyVariable output
print('  - Get @MyVariable = ' + CAST(@MyVariable AS VARCHAR(100)))

Выход:

Test stored procedures for load/save of variables across GO statements:
  - Set @MyVariable = 42
  - GO statement resets all variables
  - Get @MyVariable = 42

Вы также можете использовать это:

exec dbo.MyVariableList       -- Lists all variables in the temporary table.
exec dbo.MyVariableDeleteAll  -- Deletes all variables in the temporary table.

Выход exec dbo.MyVariableList:

Name    Value
test    42

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

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

И хранимые процедуры:

-- Stored procedure to save a variable to a temp table.
CREATE OR ALTER PROCEDURE MyVariableSave 
    @Name varchar(255),
    @Value varchar(MAX)
WITH EXECUTE AS CALLER
AS  
BEGIN
    SET NOCOUNT ON
    IF NOT EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        DROP TABLE IF EXISTS ##VariableLoadSave
        CREATE TABLE ##VariableLoadSave
        (
            Name varchar(255),
            Value varchar(MAX)
        )
    END
    UPDATE ##VariableLoadSave SET Value=@Value WHERE Name=@Name
    IF @@ROWCOUNT = 0
        INSERT INTO ##VariableLoadSave SELECT @Name, @Value
END
GO
-- Stored procedure to load a variable from a temp table.
CREATE OR ALTER PROCEDURE MyVariableLoad 
    @Name varchar(255),
    @Value varchar(MAX) OUT
WITH EXECUTE AS CALLER
AS  
BEGIN
    IF EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        IF NOT EXISTS(SELECT TOP 1 * FROM ##VariableLoadSave WHERE Name=@Name)
        BEGIN
            declare @ErrorMessage1 as varchar(200) = 'Error: cannot find saved variable to load: ' + @Name
            raiserror(@ErrorMessage1, 20, -1) with log
        END

        SELECT @Value=CAST(Value AS varchar(MAX)) FROM ##VariableLoadSave
        WHERE Name=@Name
    END
    ELSE
    BEGIN
        declare @ErrorMessage2 as varchar(200) = 'Error: cannot find saved variable to load: ' + @Name
        raiserror(@ErrorMessage2, 20, -1) with log
    END
END
GO
-- Stored procedure to list all saved variables.
CREATE OR ALTER PROCEDURE MyVariableList
WITH EXECUTE AS CALLER
AS  
BEGIN
    IF EXISTS (select TOP 1 * from tempdb.sys.objects where name = '##VariableLoadSave')
    BEGIN
        SELECT * FROM ##VariableLoadSave
        ORDER BY Name
    END
END
GO
-- Stored procedure to delete all saved variables.
CREATE OR ALTER PROCEDURE MyVariableDeleteAll
WITH EXECUTE AS CALLER
AS  
BEGIN
    DROP TABLE IF EXISTS ##VariableLoadSave
    CREATE TABLE ##VariableLoadSave
    (
        Name varchar(255),
        Value varchar(MAX)
    )
END
0 голосов
/ 18 сентября 2017

Временные таблицы сохраняются поверх операторов GO, поэтому ...

SELECT 'value1' as variable1, 'mydatabasename' as DbName INTO #TMP

-- get a variable from the temp table
DECLARE @dbName VARCHAR(10) = (select top 1 #TMP.DbName from #TMP)
EXEC ('USE ' + @dbName)
GO

-- get another variable from the temp table
DECLARE @value1 VARCHAR(10) = (select top 1 #TMP.variable1 from #TMP)

DROP TABLE #TMP

Это не красиво, но работает

...