web-dev-qa-db-fra.com

Comment vérifier si une procédure stockée existe avant de la créer

J'ai un script SQL qui doit être exécuté à chaque fois qu'un client exécute la fonctionnalité "gestion de base de données". Le script inclut la création de procédures stockées sur la base de données client. Certains de ces clients peuvent déjà avoir la procédure stockée lors de l'exécution du script, et d'autres non. J'ai besoin que les procédures stockées manquantes soient ajoutées à la base de données du client, mais peu importe combien j'essaie de modifier la syntaxe T-SQL

CREATE/ALTER PROCEDURE 'doit être la première instruction d'un lot de requêtes

J'ai lu cette chute avant de créer des œuvres, mais je n'aime pas le faire de cette façon.

IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'MyProc')
DROP PROCEDURE MyProc
GO

CREATE PROCEDURE MyProc
...

Comment puis-je ajouter un contrôle pour l'existence d'une procédure stockée et le créer s'il n'existe pas, mais le modifier s'il existe?

228
The Shaper

Vous pouvez exécuter du code de procédure partout où vous pouvez exécuter une requête.

Il suffit de tout copier après AS:

BEGIN
    DECLARE @myvar INT
    SELECT  *
    FROM    mytable
    WHERE   @myvar ...
END

Ce code fait exactement la même chose qu'un processus stocké ferait, mais n'est pas stocké du côté base de données.

Cela ressemble beaucoup à ce qu'on appelle la procédure anonyme dans PL/SQL.

Mettre à jour:

Le titre de votre question est un peu déroutant.

Si vous n'avez besoin de créer une procédure que si elle n'existe pas, votre code suffit.

Voici ce que SSMS génère dans le script de création:

IF EXISTS ( SELECT  *
            FROM    sys.objects
            WHERE   object_id = OBJECT_ID(N'myproc')
                    AND type IN ( N'P', N'PC' ) ) 
DROP …
CREATE …

Mettre à jour:

Exemple de procédure à suivre pour inclure le schéma:

IF EXISTS ( SELECT * 
            FROM   sysobjects 
            WHERE  id = object_id(N'[dbo].[MyProc]') 
                   and OBJECTPROPERTY(id, N'IsProcedure') = 1 )
BEGIN
    DROP PROCEDURE [dbo].[MyProc]
END

Dans l'exemple ci-dessus, dbo est le schéma.

Mettre à jour:

Dans SQL Server 2016+, vous pouvez simplement faire

CREATE OR ALTER PROCEDURE dbo.MyProc

154
Quassnoi

Je réalise que cela a déjà été marqué comme réponse, mais nous le faisions comme ceci:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND OBJECT_ID = OBJECT_ID('dbo.MyProc'))
   exec('CREATE PROCEDURE [dbo].[MyProc] AS BEGIN SET NOCOUNT ON; END')
GO

ALTER PROCEDURE [dbo].[MyProc] 
AS
  ....

Juste pour éviter de laisser tomber la procédure.

408
Geoff

Si vous recherchez le moyen le plus simple de vérifier l'existence d'un objet de base de données avant de le supprimer, voici un moyen (l'exemple utilise un SPROC, tout comme votre exemple ci-dessus mais peut être modifié pour les tables, les index, etc.):

IF (OBJECT_ID('MyProcedure') IS NOT NULL)
  DROP PROCEDURE MyProcedure
GO

Ceci est rapide et élégant, mais vous devez vous assurer que vous avez des noms d’objet uniques pour tous les types d’objets, car cela n’en tient pas compte.

J'espère que ça aide!

111
MrChips

Je sais que vous souhaitez "modifier une procédure si elle existe et ne la supprimer que si elle n'existe pas", mais je pense qu'il est plus simple de simplement supprimer la procédure, puis de la recréer. Voici comment supprimer la procédure uniquement si elle existe déjà:

IF OBJECT_ID('MyProcedure', 'P') IS NOT NULL
    DROP PROCEDURE MyProcedure
GO

Le deuxième paramètre indique à OBJECT_ID de ne rechercher que les objets avec object_type = 'P', qui sont des procédures stockées:

AF = fonction d'agrégation (CLR)

C = contrainte de vérification

D = DEFAULT (contrainte ou autonome)

F = contrainte de clé étrangère

FN = fonction scalaire SQL

FS = fonction scalaire d'assemblage (CLR)

FT = fonction table de valeur d'assemblage (CLR)

IF = fonction de table inline SQL

IT = table interne

P = Procédure stockée SQL

PC = Assembly (CLR) procédure stockée

PG = guide de plan

PK = contrainte PRIMARY KEY

R = règle (ancien style, autonome)

RF = procédure de filtrage de réplication

S = table de base du système

SN = synonyme

SO = objet séquence

TF = fonction de table SQL

Vous pouvez obtenir la liste complète des options via:

SELECT name 
FROM master..spt_values
WHERE type = 'O9T'
25
Michael Currie

À partir de SQL SERVER 2016, vous pouvez utiliser le nouveau DROP PROCEDURE IF EXISTS.
DROP { PROC | PROCEDURE } [ IF EXISTS ] { [ schema_name. ] procedure } [ ,...n ]

Référence: https://msdn.Microsoft.com/en-us/library/ms174969.aspx

17
Hybris95

Je sais que c'est un très vieux message, mais puisque cela apparaît dans les premiers résultats de la recherche, nous avons donc ajouté la dernière mise à jour pour ceux qui utilisent SQL Server 2016 SP1

create or alter procedure procTest
as
begin
 print (1)
end;
go

Cela crée une procédure stockée si elle n’existe pas déjà, mais la modifie si elle existe.

Référence

12
gkb

J'ai eu la même erreur. Je sais que ce fil est déjà pratiquement mort mais je souhaite définir une autre option en plus de "procédure anonyme".

Je l'ai résolu comme ça:

  1. Vérifiez si la procédure stockée existe:

    IF NOT EXISTS (SELECT * FROM sysobjects WHERE name='my_procedure') BEGIN
        print 'exists'  -- or watever you want
    END ELSE BEGIN
        print 'doesn''texists'   -- or watever you want
    END
    
  2. Cependant, le "CREATE/ALTER PROCEDURE' must be the first statement in a query batch" est toujours là. Je l'ai résolu comme ça:

    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE -- view procedure function or anything you want ...
    
  3. Je me retrouve avec ce code:

    IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = OBJECT_ID('my_procedure'))
    BEGIN
        DROP PROCEDURE my_procedure
    END
    
    SET ANSI_NULLS ON
    GO
    SET QUOTED_IDENTIFIER ON
    GO
    
    CREATE PROCEDURE [dbo].my_procedure ...
    
7
Oaxas

Voici une méthode et un raisonnement derrière l’utiliser de cette façon. Ce n'est pas aussi joli d'éditer le proc stocké mais il y a des avantages et des inconvénients ...

UPDATE: Vous pouvez également envelopper tout cet appel dans une TRANSACTION. Inclure plusieurs procédures stockées dans une seule transaction pouvant toutes être validées ou annulées. Un autre avantage du wrapping dans une transaction est que la procédure stockée existe toujours pour les autres connexions SQL tant qu'elles n'utilisent pas le niveau d'isolement de la transaction READ UNCOMMITTED!

1) Pour éviter les modifications comme une décision de processus. Nos processus sont à toujours SI EXISTE DROP ALORS CRÉER. Si vous procédez de la même manière en supposant que le nouveau PROC est le proc souhaité, la restauration des modifications est un peu plus difficile, car vous auriez un IF EXISTS ALTER ELSE CREATE.

2) Vous devez mettre CREATE/ALTER en tant que premier appel d'un lot afin de ne pas encapsuler une séquence de mises à jour de procédures dans une transaction en dehors du SQL dynamique. En gros, si vous souhaitez exécuter une pile complète de mises à jour de procédures ou les restaurer toutes sans restaurer une sauvegarde de base de données, vous pouvez tout faire en un seul lot.

IF NOT EXISTS (select ss.name as SchemaName, sp.name as StoredProc 
    from sys.procedures sp
    join sys.schemas ss on sp.schema_id = ss.schema_id
    where ss.name = 'dbo' and sp.name = 'MyStoredProc')
BEGIN
    DECLARE @sql NVARCHAR(MAX)

    -- Not so aesthetically pleasing part. The actual proc definition is stored
    -- in our variable and then executed.
    SELECT @sql = 'CREATE PROCEDURE [dbo].[MyStoredProc]
(
@MyParam int
)
AS
SELECT @MyParam'
    EXEC sp_executesql @sql
END
5
Shiv

À partir de Sql Server 2008, vous pouvez utiliser "INFORMATION_SCHEMA.ROUTINES"

IF EXISTS (SELECT 1 FROM INFORMATION_SCHEMA.ROUTINES 
  WHERE ROUTINE_NAME = 'MySP'
        AND ROUTINE_TYPE = 'PROCEDURE') 
4
Romil Kumar Jain

Je n'ai apparemment pas la réputation requise pour voter ou commenter, mais je voulais juste dire que la réponse de Geoff en utilisant EXEC (sp_executesql pourrait être meilleure) est certainement la voie à suivre. Si vous abandonnez puis recréez la procédure stockée, le travail est fini, mais il existe un moment où la procédure stockée n’existe pas du tout, et cela peut être très grave, surtout si cela se produit courir à plusieurs reprises. J'avais toutes sortes de problèmes avec mon application car un thread d'arrière-plan exécutait IF EXISTS DROP ... CREATE en même temps qu'un autre thread essayait d'utiliser la procédure stockée.

3
James

Voici le script que j'utilise. Avec cela, j'évite de perdre et de recréer inutilement les procs stockés.

IF NOT EXISTS (
    SELECT *
    FROM sys.objects
    WHERE object_id = OBJECT_ID(N'[dbo].[uspMyProcedure]')
    )
BEGIN
  EXEC sp_executesql N'CREATE PROCEDURE [dbo].[uspMyProcedure] AS select 1'
END
GO

ALTER PROCEDURE [dbo].[uspMyProcedure] 
    @variable1 INTEGER  
AS
BEGIN
   -- Stored procedure logic
END
3
myroslav

** Le moyen le plus simple de supprimer et de recréer un processus stocké dans T-Sql est **

Use DatabaseName
go
If Object_Id('schema.storedprocname') is not null
begin
   drop procedure schema.storedprocname
end
go

create procedure schema.storedprocname
as

begin
end
3
Rennish Joseph

Vérifier si la procédure stockée existe

IF EXISTS (SELECT * FROM sys.objects 
            WHERE object_id = OBJECT_ID
             (N'[Schema].[Procedure_Name]') AND type IN (N'P', N'PC'))
BEGIN
       DROP PROCEDURE [Schema].[Procedure_Name]
       Print('Proceudre dropped => [Schema].[Procedure_Name]')
END

Cochez SI existe pour le déclencheur, Fonction également en cliquant sur le lien ci-dessous http://www.gurujipoint.com 2017/05/check-if-exist-for-trigger-function-and.html

2
Jatin Phulera

DROP IF EXISTS Est une nouvelle fonctionnalité de SQL Server 2016

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

DROP  PROCEDURE IF EXISTS dbo.[procname]
2
JayJay

pourquoi tu ne vas pas comme ça 

    IF EXISTS(SELECT * FROM sys.procedures WHERE NAME LIKE 'uspBlackListGetAll')
    BEGIN
         DROP PROCEDURE uspBlackListGetAll
    END
    GO

    CREATE Procedure uspBlackListGetAll

..........

1
dnxit

Je me demande! Pourquoi je n'écris pas toute la requête comme

GO
create procedure [dbo].[spAddNewClass] @ClassName varchar(20),@ClassFee int
as
begin
insert into tblClass values (@ClassName,@ClassFee)
end

GO
create procedure [dbo].[spAddNewSection] @SectionName varchar(20),@ClassID       int
as
begin
insert into tblSection values(@SectionName,@ClassID)
end

Go
create procedure test
as
begin 
select * from tblstudent
end

je sais déjà que les deux premières procédures existent déjà. SQL exécutera la requête donnera l'erreur des deux premières procédures mais créera la dernière procédure. à tous mes clients! 

0

En plus de la réponse de @ Geoff j'ai créé un outil simple qui génère un fichier SQL contenant des instructions pour les procédures stockées, les vues, les fonctions et les déclencheurs.

Voir MyDbUtils @ CodePlex .  enter image description here

0
Stef Heyenrath