Solución:
CREATE PROCEDURE
debe ser la primera declaración del lote. Normalmente hago algo como esto:
IF EXISTS (
SELECT type_desc, type
FROM sys.procedures WITH(NOLOCK)
WHERE NAME = 'myProc'
AND type="P"
)
DROP PROCEDURE dbo.myProc
GO
CREATE PROC dbo.myProc
AS
....
GO
GRANT EXECUTE ON dbo.myProc TO MyUser
(no olvides las declaraciones de concesión, ya que se perderán si vuelves a crear tu proceso)
Otra cosa a tener en cuenta al implementar procedimientos almacenados es que una caída puede tener éxito y una creación fallar. Siempre escribo mis scripts SQL con una reversión en caso de un problema. Solo asegúrese de no eliminar accidentalmente el código de confirmación / retroceso al final, de lo contrario su DBA podría patearlo en la tráquea 🙂
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 = 'myProc'
AND type="P"
)
COMMIT TRAN
ELSE
ROLLBACK TRAN
-- END DO NOT REMOVE THIS CODE
Un modismo que he estado usando últimamente y que me gusta bastante es:
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
Básicamente, está creando un código auxiliar si el procedimiento no existe y luego modificando el código auxiliar (si se acaba de crear) o el procedimiento preexistente. Lo bueno de esto es que no elimina un procedimiento preexistente que también elimina todos los permisos. También puede causar problemas con cualquier aplicación que lo desee en ese breve instante en el que no existe.
[Edit 2018-02-09] – En SQL 2016 SP1, create procedure
y drop procedure
Tengo un poco de azúcar sintáctico que ayuda con este tipo de cosas. Específicamente, ahora puede hacer esto:
create or alter dbo.yourProc as
go
drop procedure if exists dbo.yourProc;
Ambos proporcionan idempotencia en la declaración prevista (es decir, puede ejecutarlo varias veces y el estado deseado). Así es como lo haría ahora (suponiendo que esté en una versión de SQL Server que lo admita).
Sé que hay una respuesta aceptada, pero la respuesta no aborda exactamente lo que pide la pregunta original, que es CREAR el procedimiento si no existe. Lo siguiente siempre funciona y tiene la ventaja de no requerir procedimientos de eliminación, lo que puede ser problemático si se usa la autenticación 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