Below is an example of a simplified set of scripts that accurately reproduces an issue the exists in a more complex scripts being written for Prod.
When simulation.bat
is run before the sandbox
database exists, it works fine - the database is created along with the one populated table and one view. Here is the terminal output from that -
However, after the initial execution of the batch file, subsequent executions of it cause a database error message to surface even though set NOEXEC on;
was used in the if
block. It appears to choke on the view creation because the table doesn't exist. While it makes sense that the table doesn't exist, why is it trying to create the view at all when set NOEXEC on
has been set? How can the logic be modified to ensure that it does not try to create the view if the database already exists?
4 files -
simulation.bat
@echo off
sqlcmd -S TheServerName -E -d master -i .\Simulation.sql -v db_name=sandbox
pause
Simulation.sql
print 'database name $(db_name)';
--if database already exists then print a message and exit script, otherwise create database
if exists (select 1 from sys.databases where [name] = '$(db_name)')
begin
print '--- Database $(db_name) already exists - script execution aborted ---';
set NOEXEC on; --prevent execution of statements in this batch and batches that follow it
end;
if not exists (select 1 from sys.databases where [name] = '$(db_name)')
begin
create database $(db_name);
print '--- $(db_name) database created ---';
end;
go
use $(db_name);
go
:r .\Tally.sql
go
print 'Table creation is complete.';
go
:r .\vw_TallyRows.sql
go
print 'View creation is complete.';
go
set NOEXEC off; --allow execution of statements that follow
go
print 'Reached end of script.';
go
Tally.sql
create table Tally (n int not null primary key);
insert into Tally values (1), (2), (3), (4), (5), (6), (7), (8), (9), (10);
vw_TallyRows.sql
create view vw_TallyRows as
select rows = count(1) from dbo.Tally;
At some point, it occurred to me that if the database existed (as indicated by the line printed to the terminal in the 2nd screenshot) then the dbo.Tally
table should also exist. Based on that it didn't make sense that an invalid object name error message was appearing. The root cause: in Simulation.sql use $(db_name);
came after the block of code that checks whether or not the database exists.
Therefore, the solution was to rearrange the order of the statements at the beginning of the Simulation.sql script and add another existence check -
print 'database name $(db_name)';
if not exists (select 1 from sys.databases where [name] = '$(db_name)')
begin
create database $(db_name);
print '--- $(db_name) database created ---';
end;
go
use $(db_name);
go
if exists (select 1 from sys.databases where [name] = '$(db_name)') and exists (select distinct 1 from sys.all_objects where is_ms_shipped = 0)
begin
print '--- Database $(db_name) already exists - script execution aborted ---';
set NOEXEC on; --prevent execution of statements in this batch and batches that follow it
end;
go
--no change to remaining logic in script