【问题标题】:How to detect if a stored procedure already exists如何检测存储过程是否已存在
【发布时间】:2010-10-30 14:08:59
【问题描述】:

我必须编写一个部署脚本,它可以在存储过程存在或不存在时工作。即如果它存在,那么我需要更改它,否则创建它。

如何在 sql 中做到这一点。

我使用的是 SQL Server 2005

【问题讨论】:

标签: sql sql-server-2005 stored-procedures


【解决方案1】:
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 是过程名称

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:
      IF OBJECT_ID('SPNAME') IS NULL
           -- Does Not Exists
      ELSE
           -- Exists
      

      【讨论】:

        【解决方案4】:

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

        IF OBJECT_ID('MySproc', 'P') IS NOT NULL
        DROP PROC MySproc
        GO
        
        CREATE PROC MySproc
        AS
        BEGIN
            ...
        END
        

        【讨论】:

        • 这将起作用,但它会删除应用于存储过程的任何安全更改。
        • 安全更改也应该是脚本的一部分。这样,它将被正确记录。这是正确的方法。
        • @EnderWiggin 除非在设计时不知道安全实现...如果开发人员不知道哪些用户需要执行权限怎么办?
        • @AdriaanDavel l 这就是 DBA 的职责,让 DBA 与开发人员交谈称为管理。如果开发人员和 DBA 不能一起工作,那么公司就有问题。此外,正确实施的系统不依赖于用户权限来访问数据库,这就是服务帐户的用途,并且服务级别的安全性应该适用于整个数据库,这样 DBA 就不必花费时间和金钱来调整安全性单个存储过程。
        • 我不会让开发人员丢弃/重新创建属于商业产品的存储过程。想想看,我也不会让 DBA 这样做。不过,我明白您的意思,即“如果 DBA 需要在商业产品的 sproc 部署后调整安全性怎么办”。我将重申,正确实施的系统不依赖于用户权限,并且服务级别的安全性应该在数据库范围内应用。我与 DBA 合作过,他们将安装到演示/临时系统,然后进行模式比较以确保升级是安全的,IMO 这就是他们受雇做的事情。
        【解决方案5】:

        如果您只处理存储过程,最简单的做法是删除 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...
        

        【讨论】:

          【解决方案6】:

          如果您 DROP 和 CREATE 过程,您将失去安全设置。这可能会惹恼您的 DBA 或完全破坏您的应用程序。

          我要做的是创建一个微不足道的存储过程,如果它还不存在的话。之后,您可以根据自己的喜好更改存储过程。

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

          这样,安全设置、cmets 和其他元数据将在部署后继续存在。

          【讨论】:

          • 至少如果你放弃它,你知道你必须重新添加权限。如果您运行此 sql,您将不知道存储过程是否具有正确的权限,因为您不知道您是否创建了它或更改了它。
          • @Liazy 的简单解决方案是在if object_id('YourSp') is null BEGIN ... END 中添加代码以在创建存储过程后添加适当的权限。
          • 认为另一个答案更完整一些,因为它只提取存储过程的对象 ID。不同类型使用相同名称并不常见,但可能会发生
          【解决方案7】:

          除了已经说过的内容之外,我还想添加一种不同的方法,并提倡使用差异化脚本部署策略。 Instead of making a stateful script that always checks the current state and acts based on that state, deploy via a series of stateless scripts that upgrade from well known versions。我已经使用了这个策略,并且它带来了巨大的回报,因为我的部署脚本现在都是“IF”免费的。

          【讨论】:

          • 有趣!自您发布此答案以来的五年中,您的数据库版本控制方法是否有进一步的发展?
          【解决方案8】:

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

          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
          

          【讨论】:

          • 我没有提供否决票,但我猜测,我会说它被否决了,因为该解决方案引入了新的复杂性,即在存储过程的主体中转义引号字符.
          【解决方案9】:

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

          语法:

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

          查询:

          DROP PROCEDURE IF EXISTS usp_name
          

          更多信息here

          【讨论】:

            【解决方案10】:

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

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

            //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 
            

            【讨论】:

              【解决方案11】:

              您可以编写如下查询:

              IF OBJECT_ID('ProcedureName','P') IS NOT NULL
                  DROP PROC ProcedureName
              GO
              
              CREATE PROCEDURE [dbo].[ProcedureName]
              ...your query here....
              

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

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

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

              【讨论】:

                猜你喜欢
                • 2011-08-08
                • 1970-01-01
                • 1970-01-01
                • 2021-11-11
                • 2012-10-01
                • 1970-01-01
                • 2022-08-21
                • 2016-11-06
                • 2017-08-24
                相关资源
                最近更新 更多