ストアドプロシージャのリストが存在するかどうかを確認します。これをすべて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
等々。ただし、次のエラーが表示されます。
キーワード「手順」の近くの構文が正しくありません。
私がやっていることが正しく動作しないのはなぜですか?
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
私が最近使っているイディオムの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のバージョンを使用していると仮定して)。
受け入れられた答えがあることは知っていますが、答えは元の質問が求めるものを正確に扱っていません。つまり、存在しない場合はプロシージャを作成します。以下は常に機能し、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
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
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
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>
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;