Reputation: 12646
I am attempting to run some SQL queries if a table doesn't already exist, specifically:
Step 1 and 2 work fine, but when I try to do the third part, I get an error. Here is my code (don't need to read thoroughly - here for reference, skip to problem area below):
USE [MyDB]
GO
IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='fooTable' and xtype='U')
BEGIN
CREATE TABLE fooTable
(
ID INT NOT NULL IDENTITY(1,1),
SomeNumber INT NOT NULL,
SomeOtherTable_ID INT NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (SomeOtherTable_ID) REFERENCES SomeOtherTable(SomeOtherTable_ID)
);
INSERT INTO fooTable (SomeNumber, SomeOtherTable_ID)
VALUES (5, 1), (10, 1), (25, 1), (50, 1), (100, 1), (500, 1)
CREATE PROCEDURE myProcedureName
AS
SELECT SomeNumber from [fooTable]
END
The relevant trouble line is the third one here, it works fine OUTSIDE of the if statement:
CREATE PROCEDURE myProcedureName
AS
SELECT SomeNumber from [fooTable]
but if I try to run it in the if block, SELECT
gets underlined in red with the following:
Incorrect syntax near SELECT. Expecting EXTERNAL.
How do I run the stored procedure inside the if block? If it's relevant, this is in SQL Server using T-SQL.
Upvotes: 2
Views: 1101
Reputation: 32697
I like the following idiom:
if object_id('dbo.yourProc') is not null --object exists
set noexec on;
go
create procedure dbo.yourProc as
begin
select 'not implemented' as [message]
end
go
set noexec off;
go
alter procedure dbo.yourProc as
begin
«actual definition here»
end
go
What I like about this is that preserves any permissions that already exist on the procedure and is idempotent.
Upvotes: 0
Reputation: 48826
Stored procedures, triggers, functions, and several other object types need to be in their own batch. This can be achieved within an IF
block by wrapping the CREATE
statement in an EXEC(N'....')
:
IF (OBJECT_ID(N'dbo.footTable') IS NULL)
BEGIN
CREATE TABLE dbo.[fooTable]
(
ID INT NOT NULL IDENTITY(1, 1)
CONSTRAINT [PK_fooTable] PRIMARY KEY,
SomeNumber INT NOT NULL,
SomeOtherTable_ID INT NOT NULL
CONSTRAINT [FK_fooTable_SomeOtherTable] FOREIGN KEY
REFERENCES dbo.SomeOtherTable(SomeOtherTable_ID)
);
INSERT INTO dbo.fooTable (SomeNumber, SomeOtherTable_ID)
VALUES (5, 1), (10, 1), (25, 1), (50, 1), (100, 1), (500, 1);
EXEC(N'
CREATE PROCEDURE dbo.myProcedureName
AS
SELECT SomeNumber FROM [fooTable];
');
END;
Notes:
Be sure to include the capital-N
prefix on string literals containing dynamic SQL (as a best practice -- yes, not having it often works, but having it always works).
Don't use deprecated compatibility views such as sysobjects
. Starting with the release of SQL Server 2005, the proper system catalog views are in the sys
schema. In this case, it would be sys.objects
.
You should schema-qualify the objects: dbo.fooTable
instead of just fooTable
You should name your constraints: PK, FKs, etc.
Upvotes: 5
Reputation: 650
CREATE PROCEDURE needs to be in its own block. Move it out and do something like:
IF EXISTS ( SELECT * FROM sys.procedures WHERE NAME = 'myProcedureName' AND type = 'P')
DROP PROCEDURE myProcedureName
GO
CREATE PROCEDURE myProcedureName
AS
SELECT SomeNumber from [fooTable]
Upvotes: 1