Есть ли способ сохранить переменную на протяжении всего перехода?
-
06-09-2019 - |
Вопрос
Есть ли способ сохранить переменную на протяжении всего перехода?
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')
Видишь это ИТАК вопрос по поводу строки "ИСПОЛЬЗОВАТЬ @bob".
Решение
Тот Самый go
команда используется для разделения кода на отдельные пакеты.Если это именно то, что вы хотите сделать, то вам следует использовать это, но это означает, что пакеты фактически разделены, и вы не можете совместно использовать переменные между ними.
В вашем случае решение простое;вы можете просто удалить go
операторы, они не нужны в этом коде.
Боковое примечание:Вы не можете использовать переменную в use
оператор, это должно быть имя базы данных.
Другие советы
Используйте временную таблицу:
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
Я предпочитаю это ответьте на этот вопрос Глобальные переменные с помощью GO
Что имеет дополнительное преимущество в том, что вы также можете делать то, что вы изначально хотели делать.
Предостережение заключается в том, что вам нужно включить режим SQLCMD (в разделе Запрос-> 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
Не уверен, поможет ли это
declare @s varchar(50)
set @s='Northwind'
declare @t nvarchar(100)
set @t = 'select * from ' + @s + '.[dbo].[Customers]'
execute sp_executesql @t
Если вы используете SQL Server, вы можете настроить глобальные переменные для целых сценариев, таких как:
:setvar sourceDB "lalalallalal"
и использовать позже в скрипте как:
$(sourceDB)
Убедитесь, что режим SQLCMD включен в студии управления сервером, вы можете сделать это через верхнее меню, выбрав пункт Запрос и включив режим SQLCMD.
Подробнее по теме можно найти здесь:Документация MS
Временные таблицы сохраняются поверх инструкций 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
Это некрасиво, но это работает
Создайте свои собственные хранимые процедуры, которые сохраняются / загружаются во временную таблицу.
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
Если вам просто нужен двоичный код yes / no (например, если столбец существует), то вы можете использовать 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-м запуске, потому что вы все равно получите ошибки компиляции, если ссылаетесь на столбцы или таблицы, которые еще не существуют.