如何在创建存储过程之前检查存储过程是否存在

时间:2010-01-15 14:13:34

标签: sql sql-server tsql stored-procedures

我有一个SQL脚本,每次客户端执行“数据库管理”功能时都必须运行该脚本。该脚本包括在客户端数据库上创建存储过程。其中一些客户端在运行脚本时可能已经有了存储过程,有些可能没有。我需要将缺少的存储过程添加到客户端数据库中,但是我尝试弯曲T-SQL语法并不重要,我得到了

  

CREATE / ALTER PROCEDURE'必须是查询批处理中的第一个语句

我在创作作品之前就已经读过了,但是我不喜欢这样做。

IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'MyProc')
DROP PROCEDURE MyProc
GO

CREATE PROCEDURE MyProc
...

如何添加对存储过程是否存在的检查,如果它不存在则创建它,但如果它存在则更改它?

18 个答案:

答案 0 :(得分:426)

我意识到这已被标记为已回答,但我们过去常常这样做:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND OBJECT_ID = OBJECT_ID('dbo.MyProc'))
   exec('CREATE PROCEDURE [dbo].[MyProc] AS BEGIN SET NOCOUNT ON; END')
GO

ALTER PROCEDURE [dbo].[MyProc] 
AS
  ....

只是为了避免丢弃程序。

答案 1 :(得分:163)

您可以在任何能够运行查询的位置运行过程代码。

只需复制AS之后的所有内容:

BEGIN
    DECLARE @myvar INT
    SELECT  *
    FROM    mytable
    WHERE   @myvar ...
END

此代码与存储过程执行的操作完全相同,但不存储在数据库端。

这与PL/SQL中所谓的匿名程序非常相似。

<强>更新

你的问题标题有点令人困惑。

如果您只需要创建一个不存在的过程,那么您的代码就可以了。

以下是创建脚本中的SSMS输出:

IF EXISTS ( SELECT  *
            FROM    sys.objects
            WHERE   object_id = OBJECT_ID(N'myproc')
                    AND type IN ( N'P', N'PC' ) ) 
DROP …
CREATE …

<强>更新

包含架构时如何执行此操作的示例:

IF EXISTS ( SELECT * 
            FROM   sysobjects 
            WHERE  id = object_id(N'[dbo].[MyProc]') 
                   and OBJECTPROPERTY(id, N'IsProcedure') = 1 )
BEGIN
    DROP PROCEDURE [dbo].[MyProc]
END

在上面的示例中, dbo 是架构。

<强>更新

在SQL Server 2016+中,您可以执行

CREATE OR ALTER PROCEDURE dbo.MyProc

答案 2 :(得分:112)

如果您正在寻找在删除数据库对象之前检查数据库对象的最简单方法,那么这是一种方式(示例使用SPROC,就像上面的示例一样,但可以针对表,索引等进行修改... ):

IF (OBJECT_ID('MyProcedure') IS NOT NULL)
  DROP PROCEDURE MyProcedure
GO

这是快速而优雅的,但您需要确保在所有对象类型中都有唯一的对象名称,因为它没有考虑到这一点。

我希望这有帮助!

答案 3 :(得分:27)

我知道你想要修改一个程序(如果它存在的话),只有当它不存在时才删除它&#34;但我相信只是总是丢弃程序然后重新创建它更简单。以下是仅在已存在的情况下放弃该过程的方法:

IF OBJECT_ID('MyProcedure', 'P') IS NOT NULL
    DROP PROCEDURE MyProcedure
GO

第二个参数告诉OBJECT_ID仅查找object_type = 'P'which are stored procedures:

的对象
  

AF =聚合函数(CLR)

     

C = CHECK约束

     

D = DEFAULT(约束或独立)

     

F = FOREIGN KEY约束

     

FN = SQL标量函数

     

FS =汇编(CLR)标量函数

     

FT =汇编(CLR)表值函数

     

IF = SQL内联表值函数

     

IT =内部表

     

P = SQL存储过程

     

PC =汇编(CLR)存储过程

     

PG =计划指南

     

PK = PRIMARY KEY约束

     

R =规则(旧式,独立)

     

RF =复制过滤器程序

     

S =系统基表

     

SN =同义词

     

SO =序列对象

     

TF = SQL table-valued-function

您可以通过以下方式获取完整的选项列表:

SELECT name 
FROM master..spt_values
WHERE type = 'O9T'

答案 4 :(得分:20)

从SQL SERVER 2016开始,您可以使用新的DROP PROCEDURE IF EXISTS DROP { PROC | PROCEDURE } [ IF EXISTS ] { [ schema_name. ] procedure } [ ,...n ]

参考: https://msdn.microsoft.com/en-us/library/ms174969.aspx

答案 5 :(得分:17)

我知道这是一篇非常古老的帖子,但由于它出现在热门搜索结果中,因此为使用 SQL Server 2016 SP1 的用户添加了最新更新 -

create or alter procedure procTest
as
begin
 print (1)
end;
go

这会创建一个存储过程(如果尚不存在),但如果存在则会更改它。

Reference

答案 6 :(得分:7)

我有同样的错误。我知道这个帖子已经死了但我想在“匿名程序”之外设置另一个选项。

我解决了这个问题:

  1. 检查存储过程是否存在:

    IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='my_procedure') BEGIN
        print 'exists'  -- or watever you want
    END ELSE BEGIN
        print 'doesn''texists'   -- or watever you want
    END
    
  2. "CREATE/ALTER PROCEDURE' must be the first statement in a query batch"仍在那里。我这样解决了:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE -- view procedure function or anything you want ...
    
  3. 我最终得到了这段代码:

    IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID('my_procedure'))
    BEGIN
        DROP PROCEDURE my_procedure
    END
    
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROCEDURE [dbo].my_procedure ...
    

答案 7 :(得分:5)

这是一种以这种方式使用它的方法和一些推理。编辑存储过程并不是很好,但有利有弊......

更新:您还可以在TRANSACTION中包装整个调用。在单个事务中包含许多存储过程,可以全部提交或全部回滚。包装在事务中的另一个优点是存储过程始终存在于其他SQL连接,只要它们不使用READ UNCOMMITTED事务隔离级别即可!

1)避免改变过程决策。我们的流程总是如果EXISTS DROP THEN CREATE。如果你采用相同的模式来假设新的PROC是所需的过程,那么为改变它而烦恼是因为你有一个IF EXISTS ALTER ELSE CREATE。

2)您必须将CREATE / ALTER作为批处理中的第一个调用,因此您无法在动态SQL之外的事务中包装一系列过程更新。基本上,如果您想要运行整个过程更新堆栈或将它们全部回滚而不恢复数据库备份,这是一种在一个批处理中执行所有操作的方法。

IF NOT EXISTS (select ss.name as SchemaName, sp.name as StoredProc 
    from sys.procedures sp
    join sys.schemas ss on sp.schema_id = ss.schema_id
    where ss.name = 'dbo' and sp.name = 'MyStoredProc')
BEGIN
    DECLARE @sql NVARCHAR(MAX)

    -- Not so aesthetically pleasing part. The actual proc definition is stored
    -- in our variable and then executed.
    SELECT @sql = 'CREATE PROCEDURE [dbo].[MyStoredProc]
(
@MyParam int
)
AS
SELECT @MyParam'
    EXEC sp_executesql @sql
END

答案 8 :(得分:4)

在Sql server 2008及更高版本中,您可以使用“INFORMATION_SCHEMA.ROUTINES

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES 
  WHERE ROUTINE_NAME = 'MySP'
        AND ROUTINE_TYPE = 'PROCEDURE') 

答案 9 :(得分:3)

如果存在则下降 是SQL Server 2016的新功能

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

DROP  PROCEDURE IF EXISTS dbo.[procname]

答案 10 :(得分:3)

这是我使用的脚本。有了它,我避免不必要地删除并重新创建存储过程。

IF NOT EXISTS (
    SELECT *
    FROM sys.objects
    WHERE object_id = OBJECT_ID(N'[dbo].[uspMyProcedure]')
    )
BEGIN
  EXEC sp_executesql N'CREATE PROCEDURE [dbo].[uspMyProcedure] AS select 1'
END
GO

ALTER PROCEDURE [dbo].[uspMyProcedure] 
    @variable1 INTEGER  
AS
BEGIN
   -- Stored procedure logic
END

答案 11 :(得分:3)

**在T-Sql中删除和重新创建存储过程的最简单方法是**

Use DatabaseName
go
If Object_Id('schema.storedprocname') is not null
begin
   drop procedure schema.storedprocname
end
go

create procedure schema.storedprocname
as

begin
end

答案 12 :(得分:3)

我显然没有投票或评论所需的声誉,但我只想说Geoff使用EXEC(sp_executesql可能更好)的答案绝对是可行的方法。删除然后重新创建存储过程最终会完成工作,但是有一段时间存储过程根本不存在,这可能非常糟糕,特别是如果这将是反复运行。我的应用程序遇到了各种各样的问题,因为后台线程正在执行IF EXISTS DROP ... CREATE,同时另一个线程正在尝试使用存储过程。

答案 13 :(得分:2)

检查存储过程是否存在

IF EXISTS (SELECT * FROM sys.objects 
            WHERE object_id = OBJECT_ID
             (N'[Schema].[Procedure_Name]') AND type IN (N'P', N'PC'))
BEGIN
       DROP PROCEDURE [Schema].[Procedure_Name]
       Print('Proceudre dropped => [Schema].[Procedure_Name]')
END

点击以下链接http://www.gurujipoint.com/2017/05/check-if-exist-for-trigger-function-and.html

,检查IF是否存在触发功能

答案 14 :(得分:1)

为什么你不像

那样简单
    IF EXISTS(SELECT * FROM sys.procedures WHERE NAME LIKE 'uspBlackListGetAll')
    BEGIN
         DROP PROCEDURE uspBlackListGetAll
    END
    GO

    CREATE Procedure uspBlackListGetAll

..........

答案 15 :(得分:0)

我好奇!为什么我不写

这样的整个查询
GO
create procedure [dbo].[spAddNewClass] @ClassName varchar(20),@ClassFee int
as
begin
insert into tblClass values (@ClassName,@ClassFee)
end

GO
create procedure [dbo].[spAddNewSection] @SectionName varchar(20),@ClassID       int
as
begin
insert into tblSection values(@SectionName,@ClassID)
end

Go
create procedure test
as
begin 
select * from tblstudent
end

我已经知道前两个程序已经存在sql会运行查询会给出前两个程序的错误但是仍然会创建最后一个程序 SQl本身就是在处理已经存在的东西,这是我一直对所有客户所做的事情!

答案 16 :(得分:0)

除了@Geoff的答案之外,我还创建了一个简单的工具,可以生成一个SQL文件,其中包含存储过程,视图,函数和触发器的语句。

MyDbUtils @ CodePlexenter image description here

答案 17 :(得分:-2)

创建程序如果不存在&#39;您的程序名称&#39; ()BEGIN ... END