web-dev-qa-db-fra.com

Création d'une procédure stockée si elle n'existe pas déjà

Je veux vérifier s'il existe une liste de procédures stockées. Je veux que tout cela soit fait en 1 script, un par un. Jusqu'ici j'ai ce format:

USE [myDatabase]
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_1')
BEGIN
CREATE PROCEDURE sp_1
AS
.................
END
GO

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_2')
BEGIN
CREATE PROCEDURE sp_2
AS
.................
END
GO

etc. Cependant, j'obtiens l'erreur suivante: 

Syntaxe incorrecte près du mot clé 'Procédure'.

Pourquoi ce que je fais ne fonctionne pas correctement?

11
Sean Smyth

CREATE PROCEDURE doit être la première instruction du lot. Je fais habituellement quelque chose comme ça:

IF EXISTS (
        SELECT type_desc, type
        FROM sys.procedures WITH(NOLOCK)
        WHERE NAME = 'procname'
            AND type = 'P'
      )
     DROP PROCEDURE dbo.procname
GO

CREATE PROC dbo.procname

AS
....

    GO
    GRANT EXECUTE ON dbo.MyProc TO MyUser 

(N'oubliez pas les déclarations de subvention car elles seront perdues si vous recréez votre proc) 

Un autre élément à prendre en compte lors du déploiement de procédures stockées est qu'une suppression peut réussir et que la création échoue. J'écris toujours mes scripts SQL avec une restauration en cas de problème. Assurez-vous simplement de ne pas supprimer accidentellement le code de validation/annulation à la fin, sinon votre administrateur de base de données pourrait vous donner un coup de pied dans la trachée :) 

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 = 'DatasetDeleteCleanup'
           AND type = 'P'
     )
COMMIT TRAN
ELSE
ROLLBACK TRAN
-- END DO NOT REMOVE THIS CODE
23
Code Magician

Un idiome que j'utilise depuis peu et que j'aime beaucoup est:

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

Essentiellement, vous créez un stub si la procédure n'existe pas, puis vous modifiez le stub (s'il vient d'être créé) ou la procédure préexistante. La bonne chose à ce propos est que vous ne supprimez pas une procédure préexistante qui supprime également toutes les autorisations. Vous pouvez également causer des problèmes à toute application qui le souhaite en un instant si elle n’existe pas.

[Edit 2018-02-09] - Dans SQL 2016 SP1, create procedure et drop procedure ont obtenu un sucre syntaxique qui facilite ce genre de choses. Plus précisément, vous pouvez maintenant faire ceci:

create or alter dbo.yourProc as
go

drop procedure if exists dbo.yourProc;

Les deux fournissent idempotency dans l’instruction prévue (c’est-à-dire que vous pouvez l’exécuter plusieurs fois et dans l’état souhaité). Voici comment je le ferais maintenant (en supposant que vous utilisez une version de SQL Server qui le prend en charge).

18
Ben Thul

Je sais qu'il y a une réponse acceptée, mais la réponse ne dit pas exactement ce que la question initiale pose, à savoir CREER la procédure si elle n'existe pas. Ce qui suit fonctionne toujours et présente l’avantage de ne pas nécessiter de procédures d’abandon, ce qui peut poser problème si on utilise l’authentification 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
7
Ron

J'aime utiliser ALTER pour ne pas perdre les permissions et si vous avez une erreur de syntaxe, l'ancienne version existe toujours:

BEGIN TRY
    --if procedure does not exist, create a simple version that the ALTER will replace.  if it does exist, the BEGIN CATCH will eliminate any error message or batch stoppage
    EXEC ('CREATE PROCEDURE AAAAAAAA AS DECLARE @A varchar(100); SET @A=ISNULL(OBJECT_NAME(@@PROCID), ''unknown'')+'' was not created!''; RAISERROR(@A,16,1);return 9999')
END TRY BEGIN CATCH END CATCH
GO

ALTER PROCEDURE AAAAAAAA 
(
     @ParamsHere varchar(10)
)
AS
PRINT 'HERE IN '+(OBJECT_NAME(@@PROCID))
GO
2
KM.
USE [myDatabase]
GO

IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'sp_1')
BEGIN
  DROP PROCEDURE sp_1
END
GO   --<-- Add a Batch Separator here



CREATE PROCEDURE sp_1
AS
.................
END
GO
2
M.Ali

Juste au cas où vous utiliseriez SQL Server 2016, il existe une version plus courte pour vérifier si le proc existe, puis déposez-le et recréez-le. 

USE [DATABASENAME]
GO
DROP PROCEDURE IF EXISTS <proc name>
GO
CREATE PROCEDURE <proc name>
AS
-- your script here
END
GO
GRANT EXECUTE ON <proc name> TO <username>

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

1
Niladri
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[spGetRailItems]') AND type in (N'P', N'PC'))
BEGIN 
execute ('
CREATE PROCEDURE [dbo].[spGetRailItems]  
AS  
BEGIN  

Declare @isLiftedBagsEnable bit=1;  
select @isLiftedBagsEnable=cast(DataValu as bit) from setups where scope =''Rail Setting'' and dataName = ''isLiftedBagsEnable'';

IF @isLiftedBagsEnable=1
BEGIN
    IF EXISTS (SELECT * FROM ITEMCONFIG)
    BEGIN
        SELECT [Item],[Desc] FROM ProcData WHERE Item IN (SELECT Item FROM ItemConfig) ORDER BY [Desc]
    END
    ELSE
    BEGIN
        SELECT [Item],[Desc] FROM ProcData ORDER BY [Desc]
    END
END
ELSE
BEGIN
    SELECT [Item],[Desc] FROM ProcData ORDER BY [Desc]
END

END

')
END

exec spGetRailItems;
0
Ajay Dagade