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

Sea*_*yth 22 sql t-sql sql-server 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
Run Code Online (Sandbox Code Playgroud)

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

关键字"过程"附近的语法不正确.

为什么我的工作不正常呢?

Cod*_*ian 32

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 
Run Code Online (Sandbox Code Playgroud)

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

在部署存储过程时要考虑的另一件事是丢弃可以成功并且创建失败.如果出现问题,我总是编写带有回滚的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
Run Code Online (Sandbox Code Playgroud)


Ben*_*hul 23

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

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
Run Code Online (Sandbox Code Playgroud)

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

[编辑2018年2月9日] -在SQL 2016 SP1,create proceduredrop procedure得到了一些语法糖,随着这种事情有帮助.具体来说,您现在可以这样做:

create or alter dbo.yourProc as
go

drop procedure if exists dbo.yourProc;
Run Code Online (Sandbox Code Playgroud)

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

  • +1我之前从未见过这种方法.巧妙地使用NOEXEC! (4认同)
  • 你甚至不需要虚拟语句(选择1作为[尚未实现]),只需"创建过程dbo.yourProc as"就可以了. (3认同)
  • 我没有发明它,但我是从这里得到的:https://www.simple-talk.com/sql/database-administration/automating-sql-server-database-deployments-scripting-details/ (2认同)
  • 这应该是接受的答案。 (2认同)
  • @AjVJsy - 如果我今天必须这样做,我可能会这样做。你在四年内学到东西。:) 但!如果我今天必须这样做并且我使用的是最新版本的 SQL Server,我会发出一个“创建或更改过程”;以上所有都是不存在的解决方法。 (2认同)

Ron*_*Ron 15

我知道有一个已接受的答案,但答案并没有完全解决原始问题所要求的问题,即如果不存在则创建程序.以下始终有效,并且具有不需要删除过程的好处,如果使用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
Run Code Online (Sandbox Code Playgroud)


Isk*_*der 10

2020 年 9 月更新

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

CREATE OR ALTER声明的行为像一个正常CREATE通过创建数据库对象如果数据库对象不存在和作品像一个正常的声明ALTER语句,如果数据库对象已经存在。


小智 6

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;
Run Code Online (Sandbox Code Playgroud)

  • 逃避撇号似乎很麻烦。 (2认同)

Nil*_*dri 5

以防万一,如果您使用的是 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>
Run Code Online (Sandbox Code Playgroud)

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