データベースにスクリプトで新しい関数を作成したい。スクリプトコードは次のとおりです。
IF Exists(Select * From sys.sysobjects A Where A.name =N'fn_myfunc' and xtype=N'FN') return;
CREATE FUNCTION fn_myfunc ()
returns varchar(10)
AS Begin
...
End
しかし、上記のスクリプトを実行すると、SQL Serverはエラーを返します。
'CREATE FUNCTION' must be the first statement in a query batch.
2017年1月更新-SQL Server 2016以降/ Azure SQLデータベース
SQL Server 2016およびAzure SQL Databaseの現在のバージョンでは、関数、プロシージャ、テーブル、データベースなどの構文が次のようになりました( DROP IF EXISTS
):
DROP FUNCTION IF EXISTS dbo.fn_myfunc;
また、SQL Server 2016 Service Pack 1は、モジュール(関数、プロシージャ、トリガー、ビュー)にさらに優れた機能を追加します。つまり、権限または依存関係を失うことはありません( CREATE OR ALTER
):
CREATE OR ALTER FUNCTION dbo.fn_myfunc ...
これらの構文の機能強化はどちらも、ソース管理やデプロイメントなどに使用されるはるかに単純なスクリプトにつながる可能性があります。
ただし、使用している場合...
古いバージョン
これをManagement Studioからスクリプト化する場合、SQL Serverが行うことを実行する必要があります。
IF NOT EXISTS (SELECT 1 FROM sys.objects WHERE type = 'FN' AND name = 'fn_myfunc')
BEGIN
DECLARE @sql NVARCHAR(MAX);
SET @sql = N'CREATE FUNCTION ...';
EXEC sp_executesql @sql;
END
またはあなたは言うことができます:
BEGIN TRY
DROP FUNCTION dbo.fn_myfunc;
END TRY
BEGIN CATCH
PRINT 'Function did not exist.';
END CATCH
GO
CREATE FUNCTION...
または、次のように言うこともできます。
DROP FUNCTION dbo.fn_myfunc;
GO
CREATE FUNCTION...
(関数がまだ存在しない場合、ここでエラーメッセージが表示されますが、スクリプトは次のGOから続行されるため、ドロップが機能したかどうかにかかわらず、関数は(再)作成されます。)
関数を削除して再作成すると、権限と依存関係の情報も失われることに注意してください。
オブジェクトがdatabase
に存在するかどうかを確認し、存在しない場合は作成するオプションがあります。
IF OBJECT_ID('new_function', 'FN') IS NULL
BEGIN
EXEC('CREATE FUNCTION new_function() RETURNS INT AS BEGIN RETURN 1 END');
END;
go
ALTER FUNCTION new_function() RETURNS INT AS
BEGIN
...
エラーはかなり自明です。それを修正する方法はいくつかあります。
GO
擬似キーワードとDROP
/CREATE
オブジェクトを使用して、Management Studioでスクリプトを異なるバッチに分離します。(キーワードそれ自体はManagement Studioオプションで変更できますが、これは事実上の設定であるため、そのままにすることをお勧めします)。
スクリプト(またはスクリプトの選択された部分)を実行すると、Management Studioはスクリプトの各チャンクをGO
s間で分離し、その部分を個別のバッチとしてSQL Serverに順次送信します。
動的SQLを使用して、別のバッチ内から別のバッチを送信します。
これは、スクリプトが外部機能に依存して正しく実行されないため、推奨される方法です。たとえば、アプリケーションにデータベース更新プログラムがある場合、一般的に言えば、アプリケーションはスクリプトファイルをロードし、ターゲットサーバーで実行します。 Management Studioが行うようにバッチを分離するロジックを追加する必要があります(注:危険を伴う)、またはentireスクリプトは単一のバッチとして正常に実行できます。
別の回答で述べたように、このメソッド(またはCREATE
/DROP
などの他の組み合わせ)を使用してテスト/ CREATE
を実行できます。オブジェクトが存在しない場合は、スタブオブジェクトを作成し、ALTER <object>
を使用して実際に作成または変更を行います。この方法では、アクセス許可や拡張プロパティなどの依存関係が削除されることはなく、単一のステートメントでCREATE
/ALTER
を実行するためにエラーが発生しやすいロジックをコピーして貼り付ける必要もありません。
これが、スカラー関数の作成または変更に使用するテンプレートです。読者がこれを他のタイプのオブジェクト(ストアドプロシージャ、トリガーなど)に適応させる演習として残しておきます。
IF NOT EXISTS(SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[<schema>].[<function name>]') AND type IN ('FN', 'FS'))
EXEC sp_executesql N'CREATE FUNCTION [<schema name>].[<function name>] (@a int) RETURNS int AS BEGIN /* Stub */ RETURN @a END'
EXEC sp_executesql N'
ALTER FUNCTION [<schema name>].[<function name>]
/* ... */
'