Cómo detectar si ya existe un procedimiento almacenado

Respuestas:

160

Si DROP y CREATE el procedimiento, perderá la configuración de seguridad. Esto podría molestar a su DBA o romper su aplicación por completo.

Lo que hago es crear un procedimiento almacenado trivial si aún no existe. Después de eso, puede ALTERAR el procedimiento almacenado a su gusto.

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

De esta manera, la configuración de seguridad, los comentarios y otros meta deta sobrevivirán a la implementación.

Andomar
fuente
2
Al menos si lo suelta, sabe que debe volver a agregar los permisos. Si ejecutó este sql, no sabría si el sproc tenía los permisos correctos o no, ya que no sabría si lo creó o lo modificó.
Liazy
@Liazy, la solución simple es agregar código en el if object_id('YourSp') is null BEGIN ... ENDpara agregar los permisos adecuados después de crear el procedimiento almacenado.
Salse
44
creo que la otra respuesta es un poco más completa, ya que solo extrae la identificación del objeto para los procedimientos almacenados. no es común tener el mismo nombre para diferentes tipos, pero podría suceder
workabyte
149

La forma más limpia es probar su existencia, descartarla si existe y luego recrearla. No puede incrustar una declaración "create proc" dentro de una declaración IF. Esto debería funcionar bien:

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

CREATE PROC MySproc
AS
BEGIN
    ...
END
Aaron Alton
fuente
1
Esto funcionará, pero elimina cualquier cambio de seguridad aplicado al procedimiento almacenado.
Andomar 02 de
18
Los cambios de seguridad también deberían ser parte de los scripts. De esa manera, se documentará adecuadamente. Este es el enfoque correcto.
Ender Wiggin
@EnderWiggin Excepto si la implementación de seguridad no se conoce en tiempo de diseño ... ¿Qué sucede si el desarrollador no sabe qué usuarios necesitan derechos de ejecución?
Adriaan Davel
2
@AdriaanDavel l para eso están los DBA, y hacer que los DBA hablen con los desarrolladores se llama gestión. Si los desarrolladores y los DBA no pueden trabajar juntos, hay un problema con la empresa. Además, los sistemas implementados adecuadamente no dependen del privilegio del usuario para tocar una base de datos, para eso están las cuentas de servicio, y la seguridad del nivel de servicio debería ser aplicable en toda la base de datos, de esta manera los DBA no tienen que gastar tiempo y dinero en ajustar la seguridad Sprocs individuales.
Shaun Wilson
2
No habría desarrolladores dejando caer / recreando sprocs que pertenecían a un producto comercial. Ahora que lo pienso, tampoco tendría DBA haciendo eso. Sin embargo, veo a lo que te refieres, es decir, "qué pasa si los DBA necesitan ajustar la seguridad en un sproc posterior a la implementación de un producto comercial". Reitero que los sistemas implementados adecuadamente no dependen de los privilegios del usuario y que la seguridad de nivel de servicio debe aplicarse en toda la base de datos. He trabajado con DBA que se instalarán en un sistema de demostración / scratch y luego compararán un esquema para garantizar que una actualización sea segura, en mi opinión, esto es lo que están contratados para hacer.
Shaun Wilson
31

Si solo se trata de procedimientos almacenados, lo más fácil es probablemente abandonar el proceso y luego volver a crearlo. Puede generar todo el código para hacerlo utilizando el asistente Generar secuencias de comandos en 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...
JasonS
fuente
20

Desde SQL Server 2016 CTP3usted puede usar nuevas declaraciones DIE en lugar de grandes IFenvoltorios

Sintaxis:

DROP {PROC | PROCEDIMIENTO} [SI EXISTE] {[nombre_esquema. ] procedimiento} [, ... n]

Consulta:

DROP PROCEDURE IF EXISTS usp_name

Más información aquí.

P ரதீப்
fuente
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

donde xxxesta el nombre del proceso

Luke Schafer
fuente
4

Además de lo que ya se ha dicho, también me gusta agregar un enfoque diferente y abogar por el uso de una estrategia de implementación de script diferencial. En lugar de crear una secuencia de comandos con estado que siempre verifique el estado actual y actúe en función de ese estado, implemente a través de una serie de secuencias de comandos sin estado que se actualicen desde versiones conocidas . He usado esta estrategia y vale mucho la pena ya que mis scripts de implementación ahora están libres de 'IF'.

Remus Rusanu
fuente
¡Interesante! En los cinco años transcurridos desde que publicó esta respuesta, ¿ha habido más desarrollos en los métodos de control de versiones de su base de datos?
Thomas L Holaday
4

Puede escribir una consulta de la siguiente manera:

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

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

Para ser más específico sobre la sintaxis anterior:
OBJECT_ID es un número de identificación único para un objeto dentro de la base de datos, SQL Server lo utiliza internamente. Dado que estamos pasando ProcedureName seguido de su tipo de objeto P, que le dice al SQL Server que debe encontrar el objeto llamado ProcedureName, que es de tipo procedimiento, es decir, P

Esta consulta encontrará el procedimiento y, si está disponible, lo descartará y creará uno nuevo.

Para obtener información detallada sobre OBJECT_ID y los tipos de objetos, visite: SYS.Objects

shary.sharath
fuente
3
IF OBJECT_ID('SPNAME') IS NULL
     -- Does Not Exists
ELSE
     -- Exists
Hemanshu Bhojak
fuente
0

Tengo un proceso almacenado que permite al cliente extender la validación, si existe no quiero cambiarlo, si no es así, quiero crearlo, la mejor manera que he encontrado:

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
Adriaan Davel
fuente
2
No proporcioné el voto negativo, pero, supongo, diría que fue votado negativamente porque esta solución introduce nuevas complicaciones con caracteres de comillas que escapan dentro del cuerpo del procedimiento almacenado.
donperk
0

El siguiente código verificará si el procedimiento almacenado ya existe o no.

Si existe, se alterará, si no existe, creará un nuevo procedimiento almacenado para usted:

//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 
shiva kumar kella
fuente
0

Una mejor opción podría ser usar una herramienta como Red-Gate SQL Compare o SQL Examiner para comparar automáticamente las diferencias y generar un script de migración.

Kane
fuente