Why can't I use create schema in a begin/end block in SQL Management Studio?
Schema creations must be the only statement in a batch. One way to get around it is like so:
IF (NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'acme'))
BEGIN
EXEC ('CREATE SCHEMA [acme] AUTHORIZATION [dbo]')
END
Can't create schema inside begin block
The error message is a bit of a red herring here.... Execute the following to see what the "real" error is:
SELECT * FROM sys.schemas
CREATE SCHEMA Test
Msg 111, Level 15, State 1, Line 2
'CREATE SCHEMA' must be the first statement in a query batch.
To get around this problem you can use the EXEC
function:
IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = 'Test')
BEGIN
EXEC ('CREATE SCHEMA Test;');
END;
Create Schema MS SQL won't work in IF-Statement
CREATE SCHEMA
is one of these statements that must be alone in batch.
Try:
IF (SCHEMA_ID('AM') IS NULL)
BEGIN
EXEC ('CREATE SCHEMA [AM]')
END
For more info see : Why can't I use "create schema" in a begin/end block in SQL Management Studio?
TSQL - How to use GO inside of a BEGIN .. END block?
I had the same problem and finally managed to solve it using SET NOEXEC.
IF not whatever
BEGIN
SET NOEXEC ON;
END
ALTER TABLE dbo.EMPLOYEE ADD COLUMN EMP_IS_ADMIN BIT NOT NULL
GO
UPDATE dbo.EMPLOYEE SET EMP_IS_ADMIN = whatever
SET NOEXEC OFF;
Many inserts inside a begin-end block
To counter the huge else block, you could use any one the the following 3 strategies.
STRATEGY 1
Use Bulk insert from SQL Server. Just dump all your data into a csv file and use the following statement in your else block. Store the csv file on your computer and give it's UNC path after FROM in statement below. This way you will only have a single line in your else block.
BULK INSERT dbo.MyTable
FROM '\\share\somepath\myTableInsertData.csv'
WITH (FORMAT = 'CSV');
STRATEGY 2
Write a stored procedure that inserts only x
rows at a time. You could then call this stored procedure in a While loop
and your else block would be very small. You would call this stored procedure repeatedly in a while loop from your original SQL and then the else block would end being just a few lines of t-sql code.
Note that you can control how many rows are inserted by the stored procedure at a time by using an appropriate value for the variable @numberOfRowsAtaTime
. I have used 1000 so in a single call of stored procedure 1000 rows get inserted.
Of course, based on your business rules you can script the stored procedure's insert statements. If you have a pattern in your INSERTS then you could script that pattern into the stored procedure logic below.
Stored Procedure
CREATE PROCEDURE dbo.insertXRows
@startIndex INT,
@numberOfRows INT
AS
BEGIN
SET NOCOUNT ON;
DECLARE @counter INT;
SET @counter = @startIndex;
WHILE @counter < (@startIndex + @numberOfRows -1)
BEGIN
-- Insert statements for rows goes here
--INSERT FOR @counter -- @counter would be different for each iteration
SET @counter = @counter + 1;
END
END
GO
Your SQL
IF EXISTS (SELECT * FROM [MyTable])
BEGIN
PRINT 'No need to insert data'
--Stop executing script
END
ELSE
BEGIN
declare @insertRowCounter int;
set @insertRowCounter = 1;
declare @numberOfRowsAtaTime int;
set @numberOfRowsAtaTime = 1000;
WHILE @insertRowCounter <= 150000
EXEC dbo.insertXRows @insertRowCounter, @numberOfRowsAtaTime -- insert 1000 rows at a time
SET @insertRowCounter = @insertRowCounter + @numberOfRowsAtaTime;
END
END
STRATEGY 3
Come up with 10 stored procedures so that each stored procedure has 15000 INSERTS. Then simply call these 10 stored procedures from your else block.
10 stored procedures
CREATE PROCEDURE dbo.insertProc1
AS
BEGIN
SET NOCOUNT ON;
--INSERT1
--INSERT2
--INSERT15000
END
END
GO
CREATE PROCEDURE dbo.insertProc2
AS
BEGIN
SET NOCOUNT ON;
--INSERT15001
--INSERT15002
--INSERT3000
END
END
GO
Your SQL
IF EXISTS (SELECT * FROM [MyTable])
BEGIN
PRINT 'No need to insert data'
--Stop executing script
END
ELSE
BEGIN
EXEC insertProc1
EXEC insertProc2
EXEC insertProc3
EXEC insertProc4
EXEC insertProc5
EXEC insertProc6
EXEC insertProc7
EXEC insertProc8
EXEC insertProc9
EXEC insertProc10
END
Create new database with schema from code
SSMS generated scripts contain go
. In SSMS go
ends a batch, but it is not so with ADO.NET's ExecuteCommand
.
Split the script on go
, and send each part separately using ExecuteCommand()
.
Running the script locally (or remotely) using SSMS should also work.
I'm not sure what you mean with "variable database name". In ADO.NET you can set the database in the connection string. In SSMS, you can use use <dbname>
or the dropdown box in the query toolbar.
Views as Stored Procedures in Schema Change script
Since you are running schema update, you should comply minimal things like
- make it repeatable
- have it in your versioning system
- and test it in your testing environment before running in production.
In order to make it re-runable it's common practice to check if the object exists and drop it, and then to create it again.
Dynamic SQL will not add any functionality that the IF
clause has.
For example:
IF EXISTS(SELECT * FROM sys.views WHERE name = 'MyView')
BEGIN
DROP VIEW [MyView]
END
GO
CREATE VIEW MyView AS
SELECT [Columns list ]
FROM [MyTable]
GO
The only case that I know which justifies dynamic SQL
is if you want to preserve grant
/ deny
, in such case you can use following syntax.
IF NOT EXISTS(SELECT * FROM sys.views WHERE name = 'MyView')
BEGIN
EXEC sp_executesql N'CREATE VIEW MyView AS SELECT 1 AS Dummy'
END
GO
ALTER VIEW MyView AS
SELECT [Columns list ]
FROM [MyTable]
go
GRANT ....
I wouldn't create a Dynamic SQL
to fill the few times that I have to repeat the names in any of the scripts below. IMHO the deployment script should be as plain as possible.
Related Topics
Why Is Parameterized SQL Generated by Nhibernate Just as Fast as a Stored Procedure
Diff Between Top 1 1 and Select 1 in SQL Select Query
Cakephp See the Compiled SQL Query Before Execution
Import Fixed Width Text to SQL
How to Bulk Insert a File into a *Temporary* Table Where the Filename Is a Variable
How to Insert Multiple Rows into Oracle with a Sequence Value
Is Possible to Reuse Subqueries
SQL Server Xp_Delete_File Not Deleting Files
Sql: Is There a Possibility to Convert Numbers (1,2,3,4...) to Letters (A,B,C,D...)
Oracle: Getting Maximum Value of a Group
How to Select the Last 10 Rows of an SQL Table Which Has No Id Field
Inline Blob/Binary Data Types in SQL/Jdbc
SQL Code to Insert Multiple Rows in Ms-Access Table
What's the Simplest Way to Import an SQLite SQL File into a Web SQL Database
Postgresql Alter Column Data Type to Timestamp Without Time Zone