27

I'm trying to batch some SQL scripts. At the top I've declared some variables which I deem global in the sense of the term

So:

DECLARE @someVar1
DECLARE @someVar2
...etc.

GO

Some batch of SQL here that sets @someVar1 and @SomeVar2 to a value and uses it in the SQL statement

GO


Some batch of SQL here that sets @someVar1 and @SomeVar2 to a value and uses it in the SQL statement

GO
...

the declarations are out of scope...meaning when I run this, the subsequent batch scripts do not find those declarations. Is there a way to keep them global for all batch scripts that are utilizing or setting these variables for use?

John Parker
  • 54,048
  • 11
  • 129
  • 129
PositiveGuy
  • 46,620
  • 110
  • 305
  • 471

5 Answers5

25

Temporary tables do survive go's:

create table #vars (someVar1 varchar(10), someVar2 int)
insert #vars values ('abc',123)

Get value:

select someVar1 from #vars

Set value

update #vars set someVar1 = 'def'

Temporary tables are specific to your connection, so they're not more global than they have to be.

Andomar
  • 232,371
  • 49
  • 380
  • 404
  • seems like a lot of lines but I guess certainly much better than having to dup the same exact variable definitions in each GO statement in order to set them – PositiveGuy Mar 23 '11 at 20:03
  • I just wonder if creating a temp table to simply hold globals is an inefficient way of doing things?? I mean you're creating a new table entity for the sake of holding global vars....not sure – PositiveGuy Mar 23 '11 at 20:03
  • so you inserted default values then set them/ updated them? I have no default values to set here – PositiveGuy Mar 23 '11 at 20:06
  • also when you're updateing, your sending an update request every time...rather than use local variables which probably would be much more efficient? I'm not knocking your code, I'm just trying to figure out if this is an efficient way to do this. If not I'll just resort back to duping the declarations inside each GO batch – PositiveGuy Mar 23 '11 at 20:10
  • Also now I ran into problems when you want to use those temp table values in a sub-select. It is out of scope in the sub-select.. – PositiveGuy Mar 23 '11 at 20:25
  • @CoffeeAddict: You can always copy them to a local variable like `declare @i int; select @i = someVar2 from #vars;`. Or query them again in a subselect, like `select * from (select * from Table1 where col1 = (select someVar2 from #var))` – Andomar Mar 23 '11 at 20:33
  • Not sure if this is a recent change (or perhaps always the case) If one of the statements errors, between your go statements, I am seeing my #temp tables going away. Might be a gotcha depending on your scenario. – redevill Apr 22 '20 at 18:38
12

You can declare Scripting Variables, which can be defined explicitly by using the setvar command and don't go out of scope on the GO statement.

e.g.

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

For more info go to: http://technet.microsoft.com/en-us/library/ms188714.aspx

Oscar Fraxedas
  • 4,467
  • 3
  • 27
  • 32
  • If you want this value treated as a string, you need to enclose the either the use or the declaration in single quotes (but not both). e.g. `:setvar EchoMe MyDB\ngo\nselect '$(EchoMe)'` works as does `:setvar EchoMe 'MyDB'\ngo\nselect $(EchoMe)`. Without either single-quoted (`' '`) it encounters `Invalid column name 'MyDB'.`. With both single-quoted you get `Incorrect syntax was encountered while parsing :setvar.` If your value has spaces in it, you have to double-quote it in the declaration and single quote it either in the declaration or in the SELECT statement. (at least in Server 2008R2) – mpag Sep 16 '16 at 20:59
  • Unfortunately, it's not allowed to change these variables in SSDT PostDeployment script. All assignments are moved to the top of the scrip automatically. – Der_Meister Sep 29 '16 at 05:38
  • You might as well hard code everything with master in this example because you will not be able to override the setvar on an sqlcmd command line, if that was the intended purpose of the variable. – DSoa Apr 23 '18 at 15:56
4

There's no such thing as a global variable, but you could do something like this: Link

Usage example:

EXEC sp_SetGlobalVariableValue 'Test1', 'test1'
EXEC sp_SetGlobalVariableValue 'Test2', 'test2'

GO

EXEC sp_GetGlobalVariableValue 'Test1'
EXEC sp_GetGlobalVariableValue 'Test2'

GO

EXEC sp_GetGlobalVariableValue 'Test1'
EXEC sp_GetGlobalVariableValue 'Test2'

GO

Using the stored procedures mentioned in the link above, I was able to set global variables and have them last between GO's.

Brosto
  • 4,445
  • 2
  • 34
  • 51
  • thanks I guess I should have looked up global variables. Found this on msdn "The names of some Transact-SQL system functions begin with two at signs (@@). Although in earlier versions of Microsoft SQL Server, the @@functions are referred to as global variables, they are not variables and do not have the same behaviors as variables. The @@functions are system functions, and their syntax usage follows the rules for functions." – PositiveGuy Mar 23 '11 at 19:53
  • so...I don't know if it's really supported anymore, this is saying it does not act like a variable and they are SYSTEM functions per this article: http://msdn.microsoft.com/en-us/library/ms187953.aspx – PositiveGuy Mar 23 '11 at 19:54
  • and even if I throw these variable definitions into a stored proc, it still doesn't see them in each GO statement – PositiveGuy Mar 23 '11 at 19:59
  • 1
    I don't believe the @@Variables you create will persist through a GO. The only time I've ever used those are inside a cursor, or something like SELECT @@VERSION. They should persist through a stored procedure. I'll update my post with an example. – Brosto Mar 23 '11 at 20:07
4

You may not need use batches, in which case you can get your variables to survive for a very long time. I'm not sure if this is best practice, but for example a function declaration would usually have to be the only statement in a batch like so:

Declare @batch_scope_var INT
GO --This is required

CREATE FUNCTION dbo.Half(@function_scope_var int)
RETURNS int
WITH EXECUTE AS CALLER
AS
BEGIN
    RETURN @function_scope_var/2
END
GO --This is required

SET @batch_scope_var = 4 --Bugger, this is now out of scope and won't execute!
print dbo.Half(@batch_scope_var)
GO

However you can re-write this using *sp_executesql* and avoid all those batches like so:

Declare @batch_scope_var INT

execute dbo.sp_executesql @statement = N'
CREATE FUNCTION dbo.Half(@function_scope_var int)
RETURNS int
WITH EXECUTE AS CALLER
AS
BEGIN
    RETURN @function_scope_var/2
END
'

SET @batch_scope_var = 4
print dbo.Half(@batch_scope_var)
GO

It really depends on the complexity of your script as to whether you want to do this as it can get a bit messy and you lose you syntax highlighting as soon as everything is in a giant string :)

idieeasy
  • 135
  • 2
  • 7
2

The variables are going out of scope because the GO statement signals the end of the batch. The Microsoft documentation topic Transact-SQL Variables has this example:

The scope of a variable lasts from the point it is declared until the end of the batch or stored procedure in which it is declared. For example, the following script generates a syntax error because the variable is declared in one batch and referenced in another:

USE AdventureWorks2008R2;
GO
DECLARE @MyVariable int;
SET @MyVariable = 1;
-- Terminate the batch by using the GO keyword.
GO 
-- @MyVariable has gone out of scope and no longer exists.

-- This SELECT statement generates a syntax error because it is
-- no longer legal to reference @MyVariable.
SELECT BusinessEntityID, NationalIDNumber, JobTitle
FROM HumanResources.Employee
WHERE BusinessEntityID = @MyVariable;

I think what you want to do is create a temporary table to store your "global" variables. See Andomar's answer for an example of how to do that. He's got one variable per row. I've also see temp tables that having a column for every global variable wanted and just single row is inserted into the table. This allows for each variable to have a different data type.

Adam Porad
  • 14,193
  • 3
  • 31
  • 56