创建存储过程(如果尚不存在)

时间:2014-04-08 23:31:18

标签: sql sql-server tsql stored-procedures

我想检查是否存在存储过程列表。我希望这一切都在一个脚本中逐一完成。到目前为止,我有这种格式:

USE [myDatabase]
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_1')
BEGIN
CREATE PROCEDURE sp_1
AS
.................
END
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_2')
BEGIN
CREATE PROCEDURE sp_2
AS
.................
END
GO

等等。但是,我收到以下错误:

  

关键字'程序'附近的语法不正确。

为什么我没有正常工作?

9 个答案:

答案 0 :(得分:26)

CREATE PROCEDURE必须是批处理中的第一个语句。我通常做这样的事情:

IF EXISTS (
        SELECT type_desc, type
        FROM sys.procedures WITH(NOLOCK)
        WHERE NAME = 'procname'
            AND type = 'P'
      )
     DROP PROCEDURE dbo.procname
GO

CREATE PROC dbo.procname

AS
....

    GO
    GRANT EXECUTE ON dbo.MyProc TO MyUser 

(不要忘记授权声明,因为如果你重新创建你的proc,它们会丢失)

部署存储过程时需要考虑的另一件事是drop可以成功,create也会失败。如果出现问题,我总是编写带有回滚的SQL脚本。只是确保你不会在最后意外删除提交/回滚代码,否则你的DBA可能会在气管中重新启动你:)

BEGIN TRAN 
IF EXISTS (
       SELECT type_desc, type
       FROM sys.procedures WITH(NOLOCK)
       WHERE NAME = 'myProc'
           AND type = 'P'
     )
DROP PROCEDURE myProc GO
CREATE PROCEDURE myProc

AS
   --proc logic here

GO
-- BEGIN DO NOT REMOVE THIS CODE (it commits or rolls back the stored procedure drop) IF EXISTS (
       SELECT 1
       FROM sys.procedures WITH(NOLOCK)
       WHERE NAME = 'DatasetDeleteCleanup'
           AND type = 'P'
     )
COMMIT TRAN
ELSE
ROLLBACK TRAN
-- END DO NOT REMOVE THIS CODE

答案 1 :(得分:20)

我最近一直在使用的一个我非常喜欢的习语是:

if exists (select 1 from sys.objects where object_id = object_id('dbo.yourProc'))
   set noexec on
go
create procedure dbo.yourProc as
begin
   select 1 as [not yet implemented]
end
go
set noexec off
alter procedure dbo.yourProc as
begin
   /*body of procedure here*/
end

基本上,如果过程不存在,则创建存根,然后更改存根(如果刚刚创建)或预先存在的过程。关于这一点的好处是你不要删除一个删除所有权限的预先存在的过程。您也可能会在任何不存在的短暂瞬间内发生问题。

[编辑2018-02-09] - 在SQL 2016 SP1中,create proceduredrop procedure得到了一些语法糖,可以帮助解决这类问题。具体来说,您现在可以执行此操作:

create or alter dbo.yourProc as
go

drop procedure if exists dbo.yourProc;

两者都在预期的语句中提供幂等性(即,您可以多次运行它并获得所需的状态)。这就是我现在的做法(假设您使用的是支持它的SQL Server版本)。

答案 2 :(得分:9)

我知道已经接受了答案,但答案并未准确解决原始问题所要求的问题,即如果程序不存在则创建程序。以下始终有效,并且具有不需要删除过程的好处,如果使用sql身份验证,则可能会出现问题。

USE [MyDataBase]
GO

IF OBJECT_ID('mySchema.myProc') IS NULL
EXEC('CREATE PROCEDURE mySchema.myProc AS SET NOCOUNT ON;')
GO

ALTER PROCEDURE mySchema.myProc
    @DeclaredParmsGoHere    DataType

AS 
   BEGIN
       DECLARE @AnyVariablesINeed    Their DataType
   SELECT myColumn FROM myTable WHERE myIndex = @IndexParm

答案 3 :(得分:4)

于2020年9月更新

您可以使用CREATE OR ALTER语句(已在SQL Server 2016 SP1中添加):

如果数据库对象不存在,则CREATE OR ALTER语句通过创建数据库对象来充当普通CREATE语句,如果数据库对象已经存在,则其作用类似于普通ALTER语句。

答案 4 :(得分:2)

USE [myDatabase]
GO

IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_1')
BEGIN
  DROP PROCEDURE sp_1
END
GO   --<-- Add a Batch Separator here



CREATE PROCEDURE sp_1
AS
.................
END
GO

答案 5 :(得分:2)

我喜欢使用ALTER,因此我不会失去权限,如果您遇到语法错误,旧版本仍然存在:

BEGIN TRY
    --if procedure does not exist, create a simple version that the ALTER will replace.  if it does exist, the BEGIN CATCH will eliminate any error message or batch stoppage
    EXEC ('CREATE PROCEDURE AAAAAAAA AS DECLARE @A varchar(100); SET @A=ISNULL(OBJECT_NAME(@@PROCID), ''unknown'')+'' was not created!''; RAISERROR(@A,16,1);return 9999')
END TRY BEGIN CATCH END CATCH
GO

ALTER PROCEDURE AAAAAAAA 
(
     @ParamsHere varchar(10)
)
AS
PRINT 'HERE IN '+(OBJECT_NAME(@@PROCID))
GO

答案 6 :(得分:1)

如果您使用的是SQL Server 2016,那么有一个较短的版本来检查proc是否存在然后删除并重新创建它

USE [DATABASENAME]
GO
DROP PROCEDURE IF EXISTS <proc name>
GO
CREATE PROCEDURE <proc name>
AS
-- your script here
END
GO
GRANT EXECUTE ON <proc name> TO <username>

来源:https://blogs.msdn.microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-2016/

答案 7 :(得分:1)

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spGetRailItems]') AND type in (N'P', N'PC'))
BEGIN 
execute ('
CREATE PROCEDURE [dbo].[spGetRailItems]  
AS  
BEGIN  

Declare @isLiftedBagsEnable bit=1;  
select @isLiftedBagsEnable=cast(DataValu as bit) from setups where scope =''Rail Setting'' and dataName = ''isLiftedBagsEnable'';

IF @isLiftedBagsEnable=1
BEGIN
    IF EXISTS (SELECT * FROM ITEMCONFIG)
    BEGIN
        SELECT [Item],[Desc] FROM ProcData WHERE Item IN (SELECT Item FROM ItemConfig) ORDER BY [Desc]
    END
    ELSE
    BEGIN
        SELECT [Item],[Desc] FROM ProcData ORDER BY [Desc]
    END
END
ELSE
BEGIN
    SELECT [Item],[Desc] FROM ProcData ORDER BY [Desc]
END

END

')
END

exec spGetRailItems;

答案 8 :(得分:-2)

您可以执行以下操作:

DROP PROCEDURE IF EXISTS name_of_procedure;
CREATE PROCEDURE name_of_procedure(....)