Alan K
Alan K

Reputation: 2017

Script to create a schema using a variable

I'm surprised that this hasn't come up before but I haven't found anything in searches either here or elsewhere. I found something vaguely similar which indicates that the problem is that the Use command in my script lasts only for that one line, but there was no indication of how to work around that.

What I'm trying to do: Create a generic script to create a "template" database with all of my common schemas and tables. All of the variables (such as the database name) are intended to be set in the header so that they can be changed as needed and the script can be just run without needing to do any risky search and replace operations to change hard coded values.

What the problem is: I can't get the schemas to generate in the right database; they're all generating in Master. Trying to explicitly set the database didn't help; I just received runtime errors.

My skill level: Long time Access user but still in the foothills of exploring SQL Server. I'm sure (well, hoping) this this will be ridiculously easy for someone further up the slope.

Does anyone know how I can do something like this? (Existing code shown below.)

DECLARE @DBName NVARCHAR(50) = 'TheDBName';

-- Assume that there's a bunch of code to drop and create the database goes here.
-- This code executes correctly.

SET @SQL = 'Use [' + @DBName + ']';

Print @SQL;

EXEC(@SQL);

SET @Counter = 1;

WHILE @Counter <=3

    BEGIN
        SET @SQL = 'CREATE SCHEMA [' +
        CASE @Counter
            WHEN 1 THEN 'Schema1'
            WHEN 2 THEN 'Schema2'
            WHEN 3 THEN 'Schema3'
        END

        SET @SQL = @SQL + '] AUTHORIZATION [dbo]';

        PRINT 'Creating Schemas, ' + @SQL;

        Exec(@SQL);

    SET @Counter = @Counter + 1;    
END

Upvotes: 2

Views: 5562

Answers (3)

Mikael Eriksson
Mikael Eriksson

Reputation: 138960

The use command only changes the current db in the scope you are in and dynamic SQL runs in a scope of its own.

Try this from master

declare @SQL nvarchar(max)
set @SQL  = N'use tempdb; print db_name()'
exec(@SQL)
print db_name()

Result:

tempdb
master

Try this:

DECLARE @DBName NVARCHAR(50) = 'TheDBName';
DECLARE @SQL NVARCHAR(max)
DECLARE @SQLMain NVARCHAR(max)
DECLARE @Counter int

SET @SQLMain = 'Use [' + @DBName + ']; exec(@SQL)';


SET @Counter = 1;

WHILE @Counter <=3
BEGIN
  SET @SQL = 'CREATE SCHEMA [' +
        CASE @Counter
            WHEN 1 THEN 'Schema1'
            WHEN 2 THEN 'Schema2'
            WHEN 3 THEN 'Schema3'
        END

  SET @SQL = @SQL + '] AUTHORIZATION [dbo]';

  EXEC sp_executesql @SQLMain, N'@SQL nvarchar(max)', @SQL;

  SET @Counter = @Counter + 1;
END

Upvotes: 6

Pondlife
Pondlife

Reputation: 16240

Other answers have explained your immediate problem but since this is really a deployment issue, as a general solution you might want to try using SQLCMD variables that you can then set at runtime from the command line. This would allow you to pass the database name and/or schema names into scripts dynamically so you can then automate your deployment using batch files or VS database projects.

Upvotes: 0

Oleg Dok
Oleg Dok

Reputation: 21756

If you run USE statement inside EXEC() then run other statements also in EXEC()

but

you have to use USE databasename stmt. in every EXEC()

Upvotes: 0

Related Questions