Creating a stored procedure if it does not already exist - sql

I want to check if a list of stored procedures exist. I want this all to be done in 1 script, one by one. So far I have this format:
USE [myDatabase]
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_1')
BEGIN
CREATE PROCEDURE sp_1
AS
.................
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_2')
BEGIN
CREATE PROCEDURE sp_2
AS
.................
END
GO
and so on. However, I'm getting the following error:
Incorrect syntax near the keyword 'Procedure'.
Why isn't what I'm doing working correctly?

CREATE PROCEDURE must be the first statement in the batch. I usually do something like this:
IF EXISTS (
SELECT type_desc, type
FROM sys.procedures WITH(NOLOCK)
WHERE NAME = 'myProc'
AND type = 'P'
)
DROP PROCEDURE dbo.myProc
GO
CREATE PROC dbo.myProc
AS
....
GO
GRANT EXECUTE ON dbo.myProc TO MyUser
(don't forget grant statements since they'll be lost if you recreate your proc)
One other thing to consider when you are deploying stored procedures is that a drop can succeed and a create fail. I always write my SQL scripts with a rollback in the event of a problem. Just make sure you don't accidentally delete the commit/rollback code at the end, otherwise your DBA might crane-kick you in the trachea :)
BEGIN TRAN
IF EXISTS (
SELECT type_desc, type
FROM sys.procedures WITH(NOLOCK)
WHERE NAME = 'myProc'
AND type = 'P'
)
DROP PROCEDURE myProc GO
CREATE PROCEDURE myProc
AS
--proc logic here
GO
-- BEGIN DO NOT REMOVE THIS CODE (it commits or rolls back the stored procedure drop)
IF EXISTS(
SELECT 1
FROM sys.procedures WITH(NOLOCK)
WHERE NAME = 'myProc'
AND type = 'P'
)
COMMIT TRAN
ELSE
ROLLBACK TRAN
-- END DO NOT REMOVE THIS CODE

One idiom that I've been using lately that I like quite a lot is:
if exists (select 1 from sys.objects where object_id = object_id('dbo.yourProc'))
set noexec on
go
create procedure dbo.yourProc as
begin
select 1 as [not yet implemented]
end
go
set noexec off
alter procedure dbo.yourProc as
begin
/*body of procedure here*/
end
Essentially, you're creating a stub if the procedure doesn't exist and then altering either the stub (if it was just created) or the pre-existing procedure. The nice thing about this is that you don't drop a pre-existing procedure which drops all the permissions as well. You can also cause issues with any application that happens to want it in that brief instant where it doesn't exist.
[Edit 2018-02-09] - In SQL 2016 SP1, create procedure and drop procedure got some syntactic sugar that helps with this kind of thing. Specifically, you can now do this:
create or alter dbo.yourProc as
go
drop procedure if exists dbo.yourProc;
Both provide idempotency in the intended statement (i.e. you can run it multiple times and the desired state is achieved). This is how I'd do it now (assuming you're on a version of SQL Server that supports it).

I know that there's an accepted answer, but the answer does not address exactly what the original question asks, which is to CREATE the procedure if it does not exist. The following always works and has the benefit of not requiring dropping procedures which can be problematic if one is using sql authentication.
USE [MyDataBase]
GO
IF OBJECT_ID('mySchema.myProc') IS NULL
EXEC('CREATE PROCEDURE mySchema.myProc AS SET NOCOUNT ON;')
GO
ALTER PROCEDURE mySchema.myProc
#DeclaredParmsGoHere DataType
AS
BEGIN
DECLARE #AnyVariablesINeed Their DataType
SELECT myColumn FROM myTable WHERE myIndex = #IndexParm

Updated on Sep 2020
You can use CREATE OR ALTER statement (was added in SQL Server 2016 SP1):
The CREATE OR ALTER statement acts like a normal CREATE statement by creating the database object if the database object does not exist and works like a normal ALTER statement if the database object already exists.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spGetRailItems]') AND type in (N'P', N'PC'))
BEGIN
execute ('
CREATE PROCEDURE [dbo].[spGetRailItems]
AS
BEGIN
Declare #isLiftedBagsEnable bit=1;
select #isLiftedBagsEnable=cast(DataValu as bit) from setups where scope =''Rail Setting'' and dataName = ''isLiftedBagsEnable'';
IF #isLiftedBagsEnable=1
BEGIN
IF EXISTS (SELECT * FROM ITEMCONFIG)
BEGIN
SELECT [Item],[Desc] FROM ProcData WHERE Item IN (SELECT Item FROM ItemConfig) ORDER BY [Desc]
END
ELSE
BEGIN
SELECT [Item],[Desc] FROM ProcData ORDER BY [Desc]
END
END
ELSE
BEGIN
SELECT [Item],[Desc] FROM ProcData ORDER BY [Desc]
END
END
')
END
exec spGetRailItems;

Just in case if you are using SQL server 2016, then there is a shorter version to check if the proc exist and then drop and recreate it
USE [DATABASENAME]
GO
DROP PROCEDURE IF EXISTS <proc name>
GO
CREATE PROCEDURE <proc name>
AS
-- your script here
END
GO
GRANT EXECUTE ON <proc name> TO <username>
Source : https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/

USE [myDatabase]
GO
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_1')
BEGIN
DROP PROCEDURE sp_1
END
GO --<-- Add a Batch Separator here
CREATE PROCEDURE sp_1
AS
.................
END
GO
In SQL Server 2017 and later versions you can use the "IF EXISTS" to drop a proc or even better you can use "CREATE OR ALTER PROCEDURE"
USE [myDatabase]
GO
DROP PROCEDURE IF EXISTS sp_1;
GO --<-- Add a Batch Separator here
CREATE OR ALTER PROCEDURE sp_1
AS
BEGIN
.................
END
GO
You can simply ignore the "DROP IF EXISTS" command and just use "CREATE OR ALTER"

I like to use ALTER so I don't lose permissions and if you have a syntax error the old version still exists:
BEGIN TRY
--if procedure does not exist, create a simple version that the ALTER will replace. if it does exist, the BEGIN CATCH will eliminate any error message or batch stoppage
EXEC ('CREATE PROCEDURE AAAAAAAA AS DECLARE #A varchar(100); SET #A=ISNULL(OBJECT_NAME(##PROCID), ''unknown'')+'' was not created!''; RAISERROR(#A,16,1);return 9999')
END TRY BEGIN CATCH END CATCH
GO
ALTER PROCEDURE AAAAAAAA
(
#ParamsHere varchar(10)
)
AS
PRINT 'HERE IN '+(OBJECT_NAME(##PROCID))
GO

you can execute the following:
DROP PROCEDURE IF EXISTS name_of_procedure;
CREATE PROCEDURE name_of_procedure(....)

Related

how to have dynamically create & alter in the sql script?

how to have dynamically create & alter in the sql script?
Instead of having
if exits - drop
we are looking to have
if exits - alter.
How to handle such scenario.
To clarify my comments above, SQL Server 2016 SP1 released a CREATE OR ALTER statement that will either create an object that doesn't already exists or modify the object if it does. This is only allowed on certain objects such as stored procedures, triggers, functions, and views. Tables, indexes, and other objects that are allocated storage cannot be used in by the CREATE OR ALTER statement. Also note that since they're persisted on disk, indexes views are not permitted to be used by this. A basic example of the syntax is below.
CREATE OR ALTER PROCEDURE SP_TestStoredProcedure
AS
BEGIN
SELECT
Column1,
Column2,
Column3
FROM YourTable
END
Here is a trick I've used.
-- for testing, not needed for real -- DROP PROCEDURE dbo.uspDoSomething
GO
IF NOT EXISTS ( SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_TYPE = 'PROCEDURE' and ROUTINE_NAME = 'uspDoSomething' )
BEGIN
EXEC ( 'CREATE PROCEDURE dbo.uspDoSomething(#i INT) AS BEGIN RAISERROR (''Stubbed version'' , 16, -1) END' )
END
GO
--test only
EXEC dbo.uspDoSomething 0
GO
ALTER PROCEDURE dbo.uspDoSomething(#PatientKey INT)
AS
BEGIN
SELECT ##VERSION
END
GO
--test only
EXEC dbo.uspDoSomething 0
GO
Remember, an ALTER does not change all the PERMISSIONS you have on the script.
A DROP/ADD needs permissions reapplied.
Note, you did not originally mention your sql-server version. This trick works with 2014 and before. Obviously, newer versions with CREATE OR ALTER would be preferred over EXEC with dynamic sql.

(SQL Server) SQL doesn't allow creating a procedure after checking if it exists or not

Below is the sql I am trying to use to check if the store procedure doesnot exists then create the procedure.
it throws an error: Incorrect syntax near the keyword 'PROCEDURE'
IF NOT EXISTS (SELECT * FROM SYS.procedures WHERE name = N'[Reports].[usp_EMS_Stats_DashboardPendingBookingSel]')
BEGIN
CREATE PROCEDURE [Reports].[usp_EMS_Stats_DashboardPendingBookingSel] #OrganisationID INT, #Category2 varchar(30) = NULL
AS
BEGIN
--SOME SQL..
END
END
The schema is not included in the name; the name is just usp_EMS_Stats_DashboardPendingBookingSel, and you can check the schema via
schema_id = SCHEMA_ID('Reports')
Aside: note that it is actually sys.procedures, not SYS.procedures - this is important if the server is configured to be case-sensitive.
ALTER PROC / CREATE PROC must be the first statement in a batch, so you need to be a little creative in how you do this. In the general case of wanting a re-runnable create-or-update script, the following approach works:
IF OBJECT_ID(N'[Reports].[usp_EMS_Stats_DashboardPendingBookingSel]') IS NULL
BEGIN
EXEC('CREATE PROCEDURE [Reports].[usp_EMS_Stats_DashboardPendingBookingSel] AS BEGIN PRINT ''impl'' END');
END
GO
ALTER PROCEDURE [Reports].[usp_EMS_Stats_DashboardPendingBookingSel] #OrganisationID INT, #Category2 varchar(30) = NULL
AS
BEGIN
PRINT 'HI'; -- your actual code here
END

How do I create a Stored Procedure if it doesn't exist in TSQL

I have tried this:
if object_id('a_proc22') is not null
CREATE PROCEDURE a_proc22 AS SELECT 1
go
but it gives me a syntax error.
But this seemed to compile:
if object_id('a_proc22') is not null
EXEC('CREATE PROCEDURE a_proc22 AS SELECT 1')
go
Why is the first one incorrect?
I'm guessing the error is something like "CREATE/ALTER PROCEDURE must be the first statement in a query", so, well, that means that CREATE PROCEDURE must be the first statement in a query. If you wrapped it up on an EXEC, then when its executed, it is the first statement on that query, so that's why it works.
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[a_proc22]')
AND TYPE IN (N'P', N'PC'))
DROP PROCEDURE [dbo].[a_proc22];
GO
CREATE PROCEDURE [dbo].[a_proc22]
AS
BEGIN
-- Code here
END
GO
if object_id('a_proc22') is not null
drop procedure a_proc22
go
create procedure a_proc22
AS
SELECT 1
The GO is the important thing here after the drop, you can't have create first, some SQL validation I guess for security purposes.
Your first statement is giving error because after if condition you can not place a create/alter procedure statement.
Try this
if Exists(select * from sys.procedures -- if exists then drop it
where name = 'a_proc22')
Drop procedure a_proc22
GO
CREATE PROCEDURE a_proc22 -- create the new procedure
AS
SELECT 1
go
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[a_proc22]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[a_proc22]
--and create here... Or you can remove the drop and create with if not exists
GO

How to check if a stored procedure exists before creating it

I have a SQL script that has to be run every time a client executes the "database management" functionality. The script includes creating stored procedures on the client database. Some of these clients might already have the stored procedure upon running the script, and some may not. I need to have the missing stored procedures added to the client database, but it doesn't matter how much I try to bend T-SQL syntax, I get
CREATE/ALTER PROCEDURE' must be the first statement in a query batch
I've read that dropping before creating works, but I don't like doing it that way.
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'MyProc')
DROP PROCEDURE MyProc
GO
CREATE PROCEDURE MyProc
...
How can I add check for the existence of a stored procedure and create it if it doesn't exist but alter it if it does exist?
I realize this has already been marked as answered, but we used to do it like this:
IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND OBJECT_ID = OBJECT_ID('dbo.MyProc'))
exec('CREATE PROCEDURE [dbo].[MyProc] AS BEGIN SET NOCOUNT ON; END')
GO
ALTER PROCEDURE [dbo].[MyProc]
AS
....
Just to avoid dropping the procedure.
You can run procedural code anywhere you are able to run a query.
Just copy everything after AS:
BEGIN
DECLARE #myvar INT
SELECT *
FROM mytable
WHERE #myvar ...
END
This code does exactly same things a stored proc would do, but is not stored on the database side.
That's much like what is called anonymous procedure in PL/SQL.
Update:
Your question title is a little bit confusing.
If you only need to create a procedure if it not exists, then your code is just fine.
Here's what SSMS outputs in the create script:
IF EXISTS ( SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'myproc')
AND type IN ( N'P', N'PC' ) )
DROP …
CREATE …
Update:
Example of how to do it when including the schema:
IF EXISTS ( SELECT *
FROM sysobjects
WHERE id = object_id(N'[dbo].[MyProc]')
and OBJECTPROPERTY(id, N'IsProcedure') = 1 )
BEGIN
DROP PROCEDURE [dbo].[MyProc]
END
In the example above, dbo is the schema.
Update:
In SQL Server 2016+, you can just do
CREATE OR ALTER PROCEDURE dbo.MyProc
If you're looking for the simplest way to check for a database object's existence before removing it, here's one way (example uses a SPROC, just like your example above but could be modified for tables, indexes, etc...):
IF (OBJECT_ID('MyProcedure') IS NOT NULL)
DROP PROCEDURE MyProcedure
GO
This is quick and elegant, but you need to make sure you have unique object names across all object types since it does not take that into account.
I know you want to "ALTER a procedure if it exists and create it if it does not exist", but I believe it is simpler to:
Drop the procedure (if it already exists) and then
Re-create it.
Like this:
IF OBJECT_ID('MyProcedure', 'P') IS NOT NULL
DROP PROCEDURE MyProcedure
GO
CREATE PROCEDURE MyProcedure AS
BEGIN
/* ..... */
END
GO
The second parameter tells OBJECT_ID to only look for objects with object_type = 'P', which are stored procedures:
AF = Aggregate function (CLR)
C = CHECK constraint
D = DEFAULT (constraint or stand-alone)
F = FOREIGN KEY constraint
FN = SQL scalar function
FS = Assembly (CLR) scalar-function
FT = Assembly (CLR) table-valued function
IF = SQL inline table-valued function
IT = Internal table
P = SQL Stored Procedure
PC = Assembly (CLR) stored-procedure
PG = Plan guide
PK = PRIMARY KEY constraint
R = Rule (old-style, stand-alone)
RF = Replication-filter-procedure
S = System base table
SN = Synonym
SO = Sequence object
TF = SQL table-valued-function
TR = Trigger
You can get the full list of options via:
SELECT name
FROM master..spt_values
WHERE type = 'O9T'
As of SQL SERVER 2016 you can use the new DROP PROCEDURE IF EXISTS.
DROP { PROC | PROCEDURE } [ IF EXISTS ] { [ schema_name. ] procedure } [ ,...n ]
Reference :
https://msdn.microsoft.com/en-us/library/ms174969.aspx
I know it is a very old post, but since this appears in the top search results hence adding the latest update for those using SQL Server 2016 SP1 -
create or alter procedure procTest
as
begin
print (1)
end;
go
This creates a Stored Procedure if does not already exist, but alters it if exists.
Reference
DROP IF EXISTS
is a new feature of SQL Server 2016
https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/
DROP PROCEDURE IF EXISTS dbo.[procname]
I had the same error. I know this thread is pretty much dead already but I want to set another option besides "anonymous procedure".
I solved it like this:
Check if the stored procedure exist:
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='my_procedure') BEGIN
print 'exists' -- or watever you want
END ELSE BEGIN
print 'doesn''texists' -- or watever you want
END
However the "CREATE/ALTER PROCEDURE' must be the first statement in a query batch" is still there. I solved it like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE -- view procedure function or anything you want ...
I end up with this code:
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID('my_procedure'))
BEGIN
DROP PROCEDURE my_procedure
END
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].my_procedure ...
Here's a method and some reasoning behind using it this way. It isn't as pretty to edit the stored proc but there are pros and cons...
UPDATE: You can also wrap this entire call in a TRANSACTION. Including many stored procedures in a single transaction which can all commit or all rollback. Another advantage of wrapping in a transaction is the stored procedure always exists for other SQL connections as long as they do not use the READ UNCOMMITTED transaction isolation level!
1) To avoid alters just as a process decision. Our processes are to always IF EXISTS DROP THEN CREATE. If you do the same pattern of assuming the new PROC is the desired proc, catering for alters is a bit harder because you would have an IF EXISTS ALTER ELSE CREATE.
2) You have to put CREATE/ALTER as the first call in a batch so you can't wrap a sequence of procedure updates in a transaction outside dynamic SQL. Basically if you want to run a whole stack of procedure updates or roll them all back without restoring a DB backup, this is a way to do everything in a single batch.
IF NOT EXISTS (select ss.name as SchemaName, sp.name as StoredProc
from sys.procedures sp
join sys.schemas ss on sp.schema_id = ss.schema_id
where ss.name = 'dbo' and sp.name = 'MyStoredProc')
BEGIN
DECLARE #sql NVARCHAR(MAX)
-- Not so aesthetically pleasing part. The actual proc definition is stored
-- in our variable and then executed.
SELECT #sql = 'CREATE PROCEDURE [dbo].[MyStoredProc]
(
#MyParam int
)
AS
SELECT #MyParam'
EXEC sp_executesql #sql
END
In Sql server 2008 onwards, you can use "INFORMATION_SCHEMA.ROUTINES"
IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES
WHERE ROUTINE_NAME = 'MySP'
AND ROUTINE_TYPE = 'PROCEDURE')
**The simplest way to drop and recreate a stored proc in T-Sql is **
Use DatabaseName
go
If Object_Id('schema.storedprocname') is not null
begin
drop procedure schema.storedprocname
end
go
create procedure schema.storedprocname
as
begin
end
Here is the script that I use. With it, I avoid unnecessarily dropping and recreating the stored procs.
IF NOT EXISTS (
SELECT *
FROM sys.objects
WHERE object_id = OBJECT_ID(N'[dbo].[uspMyProcedure]')
)
BEGIN
EXEC sp_executesql N'CREATE PROCEDURE [dbo].[uspMyProcedure] AS select 1'
END
GO
ALTER PROCEDURE [dbo].[uspMyProcedure]
#variable1 INTEGER
AS
BEGIN
-- Stored procedure logic
END
why don't you go the simple way like
IF EXISTS(SELECT * FROM sys.procedures WHERE NAME LIKE 'uspBlackListGetAll')
BEGIN
DROP PROCEDURE uspBlackListGetAll
END
GO
CREATE Procedure uspBlackListGetAll
..........
In addition to the answer from #Geoff I've created a simple tool which generates a SQL-file which statements for Stored Procedures, Views, Functions and Triggers.
See MyDbUtils # CodePlex.
I wonder! Why i don't write the whole query like
GO
create procedure [dbo].[spAddNewClass] #ClassName varchar(20),#ClassFee int
as
begin
insert into tblClass values (#ClassName,#ClassFee)
end
GO
create procedure [dbo].[spAddNewSection] #SectionName varchar(20),#ClassID int
as
begin
insert into tblSection values(#SectionName,#ClassID)
end
Go
create procedure test
as
begin
select * from tblstudent
end
i already know that first two procedures are already exist sql will run the query will give the error of first two procedures but still it will create the last procedure
SQl is itself taking care of what is already exist this is what i always do to all my clients!
CREATE Procedure IF NOT EXISTS 'Your proc-name' () BEGIN ... END

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

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.
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
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.
I prefer the this answer from this question
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
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
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
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
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.
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