Is there a way to persist a variable across a go?

SqlSql ServerSql Server-2008Sql Server-2012Sql Server-2000

Sql Problem Overview


Is there a way to persist a variable across a go?

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')

See this SO question for the 'USE @bob' line.

Sql Solutions


Solution 1 - Sql

Use a temporary table:

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

Solution 2 - Sql

The go command is used to split code into separate batches. If that is exactly what you want to do, then you should use it, but it means that the batches are actually separate, and you can't share variables between them.

In your case the solution is simple; you can just remove the go statements, they are not needed in that code.

Side note: You can't use a variable in a use statement, it has to be the name of a database.

Solution 3 - Sql

I prefer the this answer from this question https://stackoverflow.com/questions/5410690/global-variables-with-go

Which has the added benefit of being able to do what you originally wanted to do as well.

The caveat is that you need to turn on SQLCMD mode (under Query->SQLCMD) or turn it on by default for all query windows (Tools->Options then Query Results->By Default, open new queries in SQLCMD mode)

Then you can use the following type of code (completely ripped off from that same answer by Oscar E. Fraxedas Tormo)

--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

Solution 4 - Sql

If you are using SQL Server you can setup global variables for entire scripts like:

:setvar sourceDB "lalalallalal"

and use later in script as:

$(sourceDB)

Make sure SQLCMD mode is on in Server Managment Studi, you can do that via top menu Click Query and toggle SQLCMD Mode on.

More on topic can be found here: MS Documentation

Solution 5 - Sql

Temp tables are retained over GO statements, so...

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

It's not pretty, but it works

Solution 6 - Sql

Create your own stored procedures which save/load to a temporary table.

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

Then you can use this:

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)))

Output:

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

You can also use these:

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

Output of exec dbo.MyVariableList:

Name	Value
test	42

It turns out that being able to list all of the variables in a table is actually quite useful. So even if you do not load a variable later, its great for debugging purposes to see everything in one place.

This uses a temporary table with a ## prefix, so it's just enough to survive a GO statement. It is intended to be used within a single script.

And the stored procedures:

-- 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

Solution 7 - Sql

If you just need a binary yes/no (like if a column exists) then you can use SET NOEXEC ON to disable execution of statements. SET NOEXEC ON works across GO (across batches). But remember to turn EXEC back on with SET NOEXEC OFF at the end of the script.

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

This compiles statements but does not execute them. So you'll still get "compile errors" if you reference schema that doesn't exist. So it works to "turn off" the script 2nd run (what I'm doing), but does not work to turn off parts of the script on 1st run, because you'll still get compile errors if referencing columns or tables that don't exist yet.

Solution 8 - Sql

You can make use of NOEXEC follow he steps below:

Create table

#temp_procedure_version(procedure_version varchar(5),pointer varchar(20))

insert procedure versions and pointer to the version into a temp table #temp_procedure_version

--example procedure_version pointer

insert into temp_procedure_version values(1.0,'first version')

insert into temp_procedure_version values(2.0,'final version')

then retrieve the procedure version, you can use where condition as in the following statement

Select @ProcedureVersion=ProcedureVersion from #temp_procedure_version where pointer='first version'

IF (@ProcedureVersion='1.0')
    BEGIN
    SET NOEXEC OFF  --code execution on 
    END
ELSE
    BEGIN 
    SET NOEXEC ON  --code execution off
    END 

--insert procedure version 1.0 here

Create procedure version 1.0 as.....

SET NOEXEC OFF -- execution is ON

Select @ProcedureVersion=ProcedureVersion from #temp_procedure_version where pointer='final version'

IF (@ProcedureVersion='2.0')
    BEGIN
    SET NOEXEC OFF  --code execution on 
    END
ELSE
    BEGIN 
    SET NOEXEC ON  --code execution off
    END 

Create procedure version 2.0 as.....

SET NOEXEC OFF -- execution is ON

--drop the temp table

Drop table #temp_procedure_version

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNitroxDMView Question on Stackoverflow
Solution 1 - SqlRBarryYoungView Answer on Stackoverflow
Solution 2 - SqlGuffaView Answer on Stackoverflow
Solution 3 - SqlMatt VukomanovicView Answer on Stackoverflow
Solution 4 - SqlDanteTheSmithView Answer on Stackoverflow
Solution 5 - SqlRemco NonhebelView Answer on Stackoverflow
Solution 6 - SqlContangoView Answer on Stackoverflow
Solution 7 - SqlyzorgView Answer on Stackoverflow
Solution 8 - SqlViv PathaniaView Answer on Stackoverflow