web-dev-qa-db-ja.com

ストアドプロシージャがまだ存在しない場合は作成する

ストアドプロシージャのリストが存在するかどうかを確認します。これをすべて1つのスクリプトで1つずつ実行してほしい。これまでのところ、私はこの形式を持っています:

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

等々。ただし、次のエラーが表示されます。

キーワード「手順」の近くの構文が正しくありません。

私がやっていることが正しく動作しないのはなぜですか?

19
Sean Smyth

CREATE PROCEDUREは、バッチの最初のステートメントでなければなりません。私は通常このようなことをします:

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 

(Grantステートメントを忘れないでください。Procを再作成すると失われます)

ストアドプロシージャを展開するときに考慮すべきもう1つのことは、ドロップが成功し、作成が失敗する可能性があることです。問題が発生した場合は、常にロールバックを使用してSQLスクリプトを記述します。最後にコミット/ロールバックコードを誤って削除しないように注意してください。削除しないと、DBAが気管でクレーンキックする可能性があります:)

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
27
Code Magician

私が最近使っているイディオムの1つは、非常に気に入っていることです。

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

基本的に、プロシージャが存在しない場合はスタブを作成し、スタブ(作成されたばかりの場合)または既存のプロシージャを変更します。これの良いところは、既存のプロシージャを削除せず、すべてのアクセス許可も削除しないことです。また、アプリケーションが存在しない短い瞬間にそれを必要とするアプリケーションで問題を引き起こす可能性があります。

[編集2018-02-09]-SQL 2016 SP1では、create procedureおよびdrop procedureは、この種のことを支援する構文糖を取得しました。具体的には、これを行うことができます。

create or alter dbo.yourProc as
go

drop procedure if exists dbo.yourProc;

どちらも、意図したステートメントでべき等性を提供します(つまり、複数回実行し、目的の状態にすることができます)。これは私が今やる方法です(あなたがそれをサポートするSQL Serverのバージョンを使用していると仮定して)。

21
Ben Thul

受け入れられた答えがあることは知っていますが、答えは元の質問が求めるものを正確に扱っていません。つまり、存在しない場合はプロシージャを作成します。以下は常に機能し、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
13
Ron

ALTERを使用したいので、権限を失うことはありません。構文エラーがある場合でも、古いバージョンは引き続き存在します。

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

SQL Server 2016を使用している場合に備えて、procが存在するかどうかを確認し、それを削除して再作成する短いバージョンがあります

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>

ソース: https://blogs.msdn.Microsoft.com/sqlserverstorageengine/2015/11/03/drop-if-exists-new-thing-in-sql-server-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;
1
Ajay Dagade