複数のデータベースで、いくつかの変更を加えて複製されたストアード・プロシージャーがあるとします。また、別のデータベースで実行されている場合でも、ストアドプロシージャが格納されているデータベースを参照したいと思います。
現在のデータベースではなく、フルパス(..)を取得する方法、またはストアドプロシージャが格納されているデータベースを取得する方法はありますか?
複数のデータベースで、いくつかの変更を加えて複製されたストアード・プロシージャーがあるとします。また、別のデータベースで実行されている場合でも、ストアドプロシージャが格納されているデータベースを参照したいと思います。
現在のデータベースではなく、フルパス(..)を取得する方法、またはストアドプロシージャが格納されているデータベースを取得する方法はありますか?
回答:
別のデータベースから実行されたとしても、ストアドプロシージャが格納されているデータベースを参照したい。
ストアドプロシージャで1部構成または2部構成の名前を使用するだけで、ストアドプロシージャを含むデータベース内のオブジェクトを参照します。特に、
ストアドプロシージャの静的SQLの場合:
修飾されていないオブジェクト名は、ストアドプロシージャを含むスキーマに関連して解決されます。
2部構成の名前は、ストアード・プロシージャーを含むデータベースに関連して解決されます。
ストアドプロシージャの動的SQLの場合:
修飾されていないオブジェクト名は、ストアドプロシージャを実行しているユーザーIDのデフォルトスキーマ(デフォルトでは、呼び出し元)を基準に解決されます。
2部構成の名前は、ストアード・プロシージャーを含むデータベースに関連して解決されます。
db_name()関数は、どちらの場合も、ストアドプロシージャを含むデータベースの名前を返します。
ここに、あなたが探しているものに近づくために使用される一般的な関数を示す簡単な例を示します。
/** Create a procedure in master to demonstrate
DB_NAME()
OBJECT_SCHEMA_NAME()
OBJECT_NAME()
@@PROCID
**/
USE [master]
GO
CREATE OR ALTER PROCEDURE dbo.uspTestMe
AS
BEGIN
PRINT 'Database: ' + DB_NAME()
PRINT 'Schema Name: ' + OBJECT_SCHEMA_NAME(@@PROCID)
PRINT 'Procedure Name: ' + OBJECT_NAME(@@PROCID)
END
GO
/** CHANGE Context to TempDB
Execute procedure in master
**/
USE [tempdb]
GO
EXEC master.dbo.uspTestMe
GO
/** Cleanup in master **/
USE [master]
GO
DROP PROCEDURE IF EXISTS dbo.uspTestMe
別のデータベースで実行されている場合でも、ストアドプロシージャが格納されているデータベースを参照したい。
これは、通常の/永続的な非システムストアドプロシージャが既にこのように機能しており、実際にオブジェクトを現在のDBで動作させるために邪魔になる必要があるため、幸運です。これが関数の機能です。ストアドプロシージャでは、「システムストアドプロシージャ」としてマークしたり、一時的なストアドプロシージャを作成したりするオプションがあります。これは、関数、ビュー、トリガーなどにはありません。
組み込み関数は一時ストアドプロシージャの静的SQLとは少し異なる動作をするため、次の例では、非一時テーブルを使用してUDFとInline-TVFの両方で参照しています。確かに、次の例では一時ストアドプロシージャを実際にテストしていませんが、非一時テーブルを使用したのは、異なる動作のインスタンスが1つあるため、そのような動作がここで発生しないようにする必要があるためです。次の例では、いずれかのタイプの関数が「現在の」データベースを認識している場合、非一時テーブルへの参照がエラーの原因になります。
セットアップ
USE [tempdb];
CREATE IF NOT EXISTS TABLE dbo.InTempDB (Col1 INT);
INSERT INTO dbo.InTempDB ([Col1]) VALUES (999);
GO
CREATE
OR ALTER -- comment out if using SQL Server < 2017
FUNCTION dbo.GetDbNameUDF()
RETURNS SYSNAME
AS
BEGIN
DECLARE @DoNothing INT;
SELECT @DoNothing = [Col1] FROM dbo.InTempDB;
RETURN DB_NAME();
END;
GO
CREATE
OR ALTER -- comment out if using SQL Server < 2017
FUNCTION dbo.GetDbNameITVF()
RETURNS TABLE
AS
RETURN
SELECT DB_NAME() AS [DbName],
tmp.[Col1]
FROM dbo.InTempDB tmp;
GO
テスト
USE [model];
SELECT DB_NAME() AS [CurrentDB],
tempdb.dbo.GetDbNameUDF() AS [DbNameFromUDF];
-- CurrentDB DbNameFromUDF
-- model tempdb
SELECT DB_NAME() AS [CurrentDB],
*
FROM tempdb.dbo.GetDbNameITVF();
-- CurrentDB DbName Col1
-- model tempdb 999
/* -- clean-up
DROP TABLE dbo.InTempDB;
DROP FUNCTION dbo.GetDbNameUDF;
DROP FUNCTION dbo.GetDbNameITVF;
*/