如何检测存储过程是否已经存在


Answers:


160

如果删除并创建该过程,则将丢失安全设置。这可能会惹恼您的DBA或完全破坏您的应用程序。

我要做的是创建一个简单的存储过程(如果尚不存在)。之后,您可以根据自己的喜好更改存储过程。

IF object_id('YourSp') IS NULL
    EXEC ('create procedure dbo.YourSp as select 1')
GO
ALTER PROCEDURE dbo.YourSp
AS
...

这样,安全设置,注释和其他元数据将在部署中保留下来。


2
至少如果将其删除,就知道您必须重新添加权限。如果您运行此sql,您将不知道该存储过程是否具有正确的权限,因为您不知道是创建还是更改了它。
Liazy 2013年

@Liazy一个简单的解决方案是if object_id('YourSp') is null BEGIN ... END在创建存储过程之后在中添加代码以添加适当的权限。
2014年

4
认为另一个答案比较完整,因为它只提取存储过程的对象ID。不同类型使用相同的名称并不常见,但是可能会发生
workabyte 2014年

149

最干净的方法是测试它的存在,将其删除(如果存在),然后重新创建它。您不能在IF语句中嵌入“ create proc”语句。这应该做得很好:

IF OBJECT_ID('MySproc', 'P') IS NOT NULL
DROP PROC MySproc
GO

CREATE PROC MySproc
AS
BEGIN
    ...
END

1
这将起作用,但是它将删除应用于存储过程的所有安全性更改。
Andomar

18
安全更改也应该是脚本的一部分。这样,它将得到正确的记录。这是正确的方法。
Ender Wiggin 2012年

@EnderWiggin除非在设计时不知道安全性实现...如果开发人员不知道哪些用户需要执行权限,该怎么办?
Adriaan Davel

2
@AdriaanDavel l就是DBA的目的,而让DBA与开发人员交谈则称为管理。如果开发人员和DBA不能一起工作,则公司存在问题。此外,正确实施的系统不依赖用户特权来访问数据库,这就是服务帐户的目的,并且服务级别的安全性应适用于整个数据库,这样,DBA无需花费时间和金钱来调整安全性。单个存储。
肖恩·威尔逊

2
我不会让开发人员删除/重新创建属于商业产品的存储过程。仔细考虑一下,我也不会让DBA那样做。不过,我知道您要获得的是什么,即“如果DBA需要在商用产品的存储后部署中调整安全性,该怎么办”。我将重申,正确实施的系统不依赖于用户特权,并且服务级别的安全性应在整个数据库范围内应用。我已经与DBA进行过合作,该DBA将安装到演示/临时系统中,然后进行模式比较以确保升级是安全的,IMO正是他们雇用的。
肖恩·威尔逊

31

如果仅处理存储过程,则最简单的操作可能是删除proc,然后重新创建它。您可以使用SQL Server中的“生成脚本”向导来生成所有代码来执行此操作。

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[YourSproc]') AND type in (N'P', N'PC'))
DROP PROCEDURE [dbo].[YourSproc]

CREATE PROCEDURE YourSproc...

20

SQL Server 2016 CTP3您可以使用新的DIE 语句代替大IF包装

句法:

删除{PROC | 程序} [如果存在] {[schema_name。]过程} [,... n]

查询:

DROP PROCEDURE IF EXISTS usp_name

更多信息在这里


11
if not exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[xxx]') and OBJECTPROPERTY(id, N'IsProcedure') = 1)
BEGIN
CREATE PROCEDURE dbo.xxx

过程xxx名称在哪里


4

除了已经说过的内容之外,我还喜欢添加一种不同的方法并主张使用差异脚本部署策略。通过制作一系列从知名版本升级的无状态脚本,可以部署而不是始终检查当前状态并根据该状态进行操作的有状态脚本。我已经使用了这种策略,并且由于我的部署脚本现在全部都是“ IF”免费的,因此可以节省大量时间。


有趣!自发布此答案以来的五年中,您的数据库版本控制方法是否有了进一步的发展?
Thomas L Holaday

4

您可以编写查询,如下所示:

IF OBJECT_ID('ProcedureName','P') IS NOT NULL
    DROP PROC ProcedureName
GO

CREATE PROCEDURE [dbo].[ProcedureName]
...your query here....

更具体地讲上述语法:
OBJECT_ID是数据库中对象的唯一ID号,SQL Server在内部使用该ID号。由于我们传递的是过程名称,后跟您的对象类型P告诉SQL Server,您应该找到名为过程名称的对象,该对象的类型为过程,即P

此查询将找到该过程,如果可用,它将删除它并创建一个新过程。

有关OBJECT_ID和对象类型的详细信息,请访问: SYS.Objects



0

我有一个存储的过程,该过程允许客户扩展验证,如果存在,我不想更改它,如果不希望创建,这是我发现的最好方法:

IF OBJECT_ID('ValidateRequestPost') IS NULL
BEGIN
    EXEC ('CREATE PROCEDURE ValidateRequestPost 
    @RequestNo VARCHAR(30),
    @ErrorStates VARCHAR(255) OUTPUT
AS
BEGIN
    SELECT @ErrorStates = @ErrorStates
END')
END

2
我没有提供拒绝投票的权利,但是,我想说它被否决了,因为此解决方案引入了新的复杂性,即在存储过程的主体内转义了引号字符。
donperk '16

0

下面的代码将检查存储过程是否已经存在。

如果存在,它将改变;如果不存在,它将为您创建一个新的存储过程:

//syntax for Create and Alter Proc 
DECLARE @Create NVARCHAR(200) = 'Create PROCEDURE sp_cp_test'; 
DECLARE @Alter NVARCHAR(200) ='Alter PROCEDURE sp_cp_test'; 
//Actual Procedure 
DECLARE @Proc NVARCHAR(200)= ' AS BEGIN select ''sh'' END'; 
//Checking For Sp
IF EXISTS (SELECT * 
           FROM   sysobjects 
           WHERE  id = Object_id('[dbo].[sp_cp_test]') 
                  AND Objectproperty(id, 'IsProcedure') = 1 
                  AND xtype = 'p' 
                  AND NAME = 'sp_cp_test') 
  BEGIN 
      SET @Proc=@Alter + @Proc 

      EXEC (@proc) 
  END 
ELSE 
  BEGIN 
      SET @Proc=@Create + @Proc 

      EXEC (@proc) 
  END 

go 

0

更好的选择可能是使用Red-Gate SQL Compare或SQL Examiner之类的工具来自动比较差异并生成迁移脚本。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.