When executing the following in SSMS;
if not exists (select * from sys.databases where name = 'SWFUAT')
begin
print 'The UAT database (SWFUAT) does not exist...'
set noexec on;
end
go
use SWFUAT;
go
The following is displayed;
The UAT database (SWFUAT) does not exist...
Msg 911, Level 16, State 1, Line 20
Database 'SWFUAT' does not exist. Make sure that the name is entered correctly.
Shouldn't the compiler just ignore the "use" statement?
If I understand your question correctly then you want to execute
use SWFUAT;
only when the SWFUAT database is exist.
Unfortunately because of this remark
USE is executed at both compile and execution time and takes effect immediately. Therefore, statements that appear in a batch after the USE statement are executed in the specified database.
described here you can't simply use the SET NOEXEC in your case.
To achieve what you need you should replace your code with for example this
if not exists (select * from sys.databases where name = 'SWFUAT')
begin
print 'The UAT database (SWFUAT) does not exist...'
end else begin
use SWFUAT;
end
go
Related
I have a script that checks for the existence of the database and if it doesn't exist exits gracefully with some instructions for the user. However when the database doesn't exist, SSMS flags the USE statement as an error and generates its own error without even running my script. So in the following code, the line
SSTDB doesnot exist. Run 1MakeSSTDB.sql first. Exiting script.
never gets executed. If I comment out the USE SSTDB line, then the script works as expected. Any ideas how to get this to work? (Using SqlServer 2014.)
USE master
GO
IF NOT EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE ('[' + name + ']' = N'SSTDB' OR name = N'SSTDB'))
BEGIN
Print 'SSTDB doesnot exist. Run 1MakeSSTDB.sql first. Exiting script.'
END
ELSE
BEGIN
Print 'exists'
USE SSTDB
END
Print 'done'
Error message from SSMS:
Msg 911, Level 16, State 1, Line 14
Database 'SSTDB' does not exist. Make sure that the name is entered correctly.
Yeah SSMS always validates the existence of objects even if you used an IF block like this.
One way to do what you want is to use dynamic sql, like this:
USE master
GO
IF NOT EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE ('[' + name + ']' = N'SSTDB' OR name = N'SSTDB'))
BEGIN
Print 'SSTDB doesnot exist. Run 1MakeSSTDB.sql first. Exiting script.'
END
ELSE
BEGIN
Print 'exists'
DECLARE #sql varchar(max) =
'USE SSTDB;
--All code here uses SSTDB database
'
EXECUTE (#sql);
END
--All code here still uses master database
Print 'done'
You can make a fairly reliable version by doing what SSDT does:
Use SQLCMD mode
Test for SQLCMD mode in case the user forgot to enable it, using SET NOEXEC ON
Set the whole script to exit on error instead of continuing execution
This is adapted from the SSDT template code:
:on error exit
:setvar dbname SSTDB
/*
Detect SQLCMD mode and disable script execution if SQLCMD mode is not supported.
To re-enable the script after enabling SQLCMD mode, execute the following line:
SET NOEXEC OFF;
*/
:setvar __IsSqlCmdEnabled "True"
GO
IF N'$(__IsSqlCmdEnabled)' NOT LIKE N'True'
BEGIN
PRINT N'SQLCMD mode must be enabled to successfully execute this script.';
SET NOEXEC ON;
END
GO
IF NOT EXISTS (SELECT name
FROM master.dbo.sysdatabases
WHERE ( name = N'SSTDB' OR name = N'SSTDB')
) RAISERROR( 'SSTDB doesnot exist. Run 1MakeSSTDB.sql first. Exiting script.', 11, 1 )
GO
PRINT 'Starting script.'
USE $(dbname)
-- Do work
PRINT 'End script'
GO
Also - side issue - the square brackets '[' + name + ']' looks broken. The sysdatabases table does not use them, and you don't have them on the right side of that WHERE condition.
Typically in a SQL Server script I will have a USE [database] statement at the start. This would be for a Schema Table creation script for example.
The script is assuming that the database already exists. However, to prevent accidentally running the script against a master database, I just want the script to terminate execution.
So error checking and try...catch does not work.
Error Check
USE [MYDATABASE]
IF ##ERROR <> 0
BEGIN
RAISERROR ('Cannot find database so skipping script creation', 1, 1);
GOTO AbortScript
END
...
AbortScript:
PRINT 'Aborted!'
Try Catch
BEGIN TRY
USE [MYDATABASE]
PRINT 'xxxx'
END TRY
BEGIN CATCH
PRINT 'OOps Errored'
END CATCH
Can you trap these errors? I am currently using SQL Server 2008 R2.
Check if the database exists first:
IF (NOT EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = 'mydatabase'))
BEGIN
RAISERROR ('Cannot find database so skipping script creation', 1, 1);
GOTO AbortScript
END;
USE [MYDATABASE]
I've been trying to abort a large SQL script that includes many batches (marked with "GO"). Unfortunately you can't use a GOTO block, IF block, or TRY-CATCH to skip multiple batches, but you can turn off command execution, which has the same effect.
IF EXISTS (SELECT 1 FROM sys.tables WHERE name = 'MyTable')
SET NOEXEC ON
(Don't forget to SET NOEXEC OFF at the end of your script)
Detailed reference here.
I am creating a deployment package which will run a stored procedure that's in VSS. I am able to do this but my problem is this. I have more or less 30 databases which I need to deploy to and I only have two databases which doesn't need to get the update. With that, I included the following codes to the .sql file which the batch file runs:
IF OBJECT_ID('CONFIG') IS NULL OR DB_NAME() LIKE '%SampleDB%'
BEGIN
PRINT 'This is not a store database. Skipping this database.'
SET NOEXEC ON
RETURN
END
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE ID = OBJECT_ID(N'[dbo].[sp_ThisIsMySampleProcedure]'))
DROP PROCEDURE [dbo].[sp_ThisIsMySampleProcedure]
GO
SET QUOTED_IDENTIFIER OFF
GO
SET ANSI_NULLS OFF
GO
CREATE PROCEDURE [dbo].[sp_ThisIsMySampleProcedure]
-- Everything else follows...
This sql code runs perfectly on SQL Server. Whenever I run it against Sample DB, it automatically skips proceeding to the checking if the procedure exists and everything after that.
But whenever I try to run it against SampleDB using my batch file, it prompts the error message but continues to run the procedure disregarding my RETURN keyword. So the message would look like this:
This is not a store database. Skipping this database.
Msg 3701, Level 11, State 5, Line 8
Cannot drop the procedure 'sp_ThisIsMySampleProcedure', because it does not exist or you do not have permission.
I understand that the error message is correct because the procedure really doesn't exist on my SampleDB. But why does it still keep running when I have the RETURN keyword there after it satisfied the condition to skip running the entire script?
Thank you!
EDIT:
Okay, I think people doesn't understand me completely. This is the scenario: My procedure (see above) works well on SQL Server Management Studio. What I mean is that whenever I try to run it on SampleDB, it gives me the message This is not a store database. Skipping this database.
But whenever I try to run my Batch-File which executes this stored procedure, I get this message on the command prompt:
This is not a store database. Skipping this database.
Msg 3701, Level 11, State 5, Line 8
Cannot drop the procedure 'sp_ThisIsMySampleProcedure', because it does not exist or you do not have permission.
Which basically means that the batch-file continued executing the whole SQL Script regardless that the first condition was satisfied.
My question is how do I make the batch-file know that whenever SQL Server throws the message This is not a store database. Skipping this database. the batch-file will immediately stop the execution of the sql file.
First. The keyword GO divides the file into separate requests. Each request separately processed by the server. RETURN exits only from first request, other requests will be run.
Try this:
select 1
RETURN
select 2
go
select 3
go
Second, SET NOEXEC ON is dangerous thing, it blocks all subsequent execution. Try this:
select 1
SET NOEXEC ON
RETURN
select 2
go
select 3
go
SET NOEXEC OFF
go
You can create procedure on all servers, but return from it in the beginig if database name like something. Or you can remove GO and create stored proc with dynamic SQL:
IF DB_NAME() like '%mydb%'
BEGIN
EXEC dbo.sp_executesql #statement = N'
CREATE PROCEDURE [dbo].[my proc]
AS
BEGIN
select 1
END'
END
I am performing the below operation. I am getting the error and unable to find what the error is.Could any one help me finding it.
a) Check for the availability of DESTINATION data base. If it is not exist, create the data base and move the tables to the data base.
b) If the table exists in the DESTINATION data base then no process required for the table.
if db_id('Destination')is null
begin
Create database Destination
select * into TabDestination from [Source].[dbo].[TabSource]
end
else
begin
use Destination
go
if('TabDestination' in (select name from sys.objects where type = 'u'))
insert into TabDestination select * from [Source].[dbo].[TabSource]
end
I am getting fallowing error
Msg 911, Level 16, State 1, Line 8
Database 'Destination' does not exist. Make sure that the name is entered correctly.
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near 'end'.
Your problem is with the USE, from the documentation:
USE is executed at both compile and execution time...
If the database specified doesn't exist at compile time then the query will fail. You can see this by trying to run the following query:
IF 1 = 2
BEGIN
USE NonexistantDatabase
END
This query fails despite the fact that the USE statement is never executed.
You should instead change your query to use database qualified names, for example:
INSERT INTO Destination.dbo.Table SELECT * FROM Source.dbo.Table
Few problems here:
After Create database Destination you need to use that database before you do the select * into TabDestination... as you will create TabDestination in some other DB.
The Go in the middle of the begin...end block won't work.
To specify your database for the inserts to TabDesitination you'd be better to use the fully qualified name of the table than calling Use, eg Insert Destiation.dbo.TabDestination...
You need to use If Exists (select... for the second if statement.
Because your Database may not exists when the script compiles, a lot of the sql needs to be exec'd dynamically.
So your script could be re-written as:
if db_id('Destination')is null
begin
Create database Destination
exec ('select * into Destination.dbo.TabDestination from [Source].[dbo].[TabSource]')
end
else
begin
if exists (select name from Destination.sys.objects where name = 'TabDestination' and type = 'u')
insert into Destination.dbo.TabDestination select * from [Source].[dbo].[TabSource]
end
A variation on #Jon Egerton's answer, however there is one case you've neglected to cover: the database exists but the table does not.
DECLARE #sql NVARCHAR(MAX) = N'SELECT *
INTO Destination.dbo.TabDestination
FROM Source.dbo.TabSource;';
IF DB_ID('Destination') IS NULL
BEGIN
PRINT 'Creating database...';
CREATE DATABASE Destination;
PRINT 'Selecting into new table...';
EXEC sp_executeSQL #sql;
END
ELSE
BEGIN
IF EXISTS (SELECT 1 FROM Destination.sys.tables WHERE schema_id = 1
AND name = N'TabDestination')
BEGIN
PRINT 'Inserting into existing table...';
INSERT Destination.dbo.TabDestination SELECT * FROM Source.dbo.TabSource;
END
ELSE
BEGIN
PRINT 'Selecting into new table...';
EXEC sp_executeSQL #sql;
END
END
EDIT
Added PRINT statements for debugging purposes, as I suggested in the follow-up to #Jon's answer.
You just need to get rid of the GO command, its a batch separator so it breaks your begin/end. Oh and you can't use USE like that either.
This has been a nagging issue for me for some time and I would love to know the reason why these SQL Batch commands aren't working.
I have a table that I use to hold configuration settings for a system. When a new setting is added, we add a new field to the table. During an update, I need to change a slew of databases on the server with the same script. Generally, they are all in the same state and I can just do the following:
Alter Table Configuration Add ShowClassesInCheckin bit;
GO
Update Configuration Set ShowClassesInCheckin=ShowFacilitiesInCheckin;
GO
This works fine. However, sometimes one or two databases get updated so I want to write conditional logic to make these changes only if the field doesn't already exist:
if Not Exists(select * from sys.columns where Name = N'ShowClassesInCheckin' AND Object_ID = Object_ID(N'Configuration'))
BEGIN
Alter Table Configuration Add ShowClassesInCheckin bit;
Update Configuration Set ShowClassesInCheckin=ShowFacilitiesInCheckin;
END;
GO
In this case, I get an error: "Invalid column name 'ShowClassesInCheckin'" Now, this makes sense in that the Alter Table isn't comitted in the batch before the Update is called (it doesn't work without the "GO" between the Alter and Update). But that doesn't help...I still don't know how to I achieve what I am after...
The entire SQL script is parsed before it's executed. During the parsing phase, the column will not exist, so the parser generates an error. The error is raised before the first line of the script is executed.
The solution is dynamic SQL:
exec (N'Update Configuration Set ShowClassesInCheckin=ShowFacilitiesInCheckin;')
This won't get parsed before the exec is reached, and by then, the column will exist.
An alternative that should work is to re-introduce the go. This means that you need to use something else as the condition for the update, possibly based on database name.
if Not Exists(select * from sys.columns where Name = N'ShowClassesInCheckin' AND Object_ID = Object_ID(N'Configuration'))
BEGIN
Alter Table Configuration Add ShowClassesInCheckin bit;
END;
GO
if *new condition here*
BEGIN
Update Configuration Set ShowClassesInCheckin=ShowFacilitiesInCheckin;
END;
GO