奇妙な質問?...多分、でも私は必要があります。 :)
あらゆるデータベースで普遍的に使用したいストアード・プロシージャーがあります。ストアドプロシージャはいくつかの動的SQLを生成し、このSQLをデータベースで実行します。このSQLは、このプロシージャのパラメーターの1つとして渡されます。
しかし、データベースパラメータをオプションにし、データベース名が渡されない場合は、プロシージャ自体の呼び出し元と同じデータベース内で動的SQLを実行します。 (この手順は、データベース全体で実行でき、手順自体が存在する同じデータベース内では実行できないことに注意してください。)
[database].sys.sp_executesql
コマンドを動的に作成することにより、特定のデータベースで動的SQLを実行するように簡単に指示できます。
USE your_database;
GO
CREATE PROCEDURE dbo.DatabaseNameOptional
@db sysname = NULL
AS
BEGIN
SET NOCOUNT ON;
DECLARE @sql nvarchar(max) = N'SELECT DB_NAME(); /* other stuff */'
DECLARE @exec nvarchar(770) = COALESCE(@db, DB_NAME())
+ N'.sys.sp_executesql';
-- alternatively, just leave DB_NAME() out of it:
--DECLARE @exec nvarchar(770) = COALESCE(@db, N'')
-- + N'sys.sp_executesql';
EXEC @exec @sql;
END
GO
やってみよう:
USE your_database;
GO
EXEC dbo.DatabaseNameOptional;
GO -- output = your_database
EXEC dbo.DatabaseNameOptional @db = N'master';
GO -- output = master
USE tempdb;
GO
EXEC your_database.dbo.DatabaseNameOptional;
GO -- output = your_database
EXEC your_database.dbo.DatabaseNameOptional @db = N'master';
GO -- output = master
ただし、プロシージャの実行コンテキストでは、いいえ、呼び出しがどこから発生したかを判断する方法(またはそのコンテキストで実行する方法)はないと思います。これが、システムでマークされた手順をマスターで使用する利点です。これが必要な機能である場合、「オブジェクトをマスターに置く」のが「必要なものを取得しない」よりも厄介かどうかを判断する必要があります。
Masterでプロシージャを作成するのは好きではありませんが、masterデータベースにプロシージャを配置し、_sp_dynamicproc
_のようなSP_プレフィックスを追加すると、自分のユーザーデータベース内からそれを呼び出して正しいdb_name()
パラメータ。
例
_USE master
GO
CREATE PROCEDURE dbo.sp_dynamicproc
(@dbname nvarchar(255) = NULL)
as
BEGIN
DECLARE @SQL NVARCHAR(MAX)
IF @dbname IS NULL
BEGIN
SET @dbname = (SELECT db_name());
END
SELECT db_name()
SET @SQL = 'SELECT * FROM '+QUOTENAME(@dbname)+'.INFORMATION_SCHEMA.COLUMNS ;';
EXEC(@SQL);
END
_
プロシージャの呼び出し
_USE test
GO
exec dbo.sp_dynamicproc;
_
結果
データベースUtils
にプロシージャMyUtil
があり、次のようになっているとします。
_USE MyDatabase
GO
EXEC Utils.dbo.MyUtil
GO
_
次に、元の質問に従って、_Utils.dbo.MyUtil
_がMyDatabase
内ではなくUtils
内でユーティリティ操作を実行するようにします。
これを正確に行う直接的な方法はないようです。 _sys.sysprocesses
_内でDB_NAME()
、_sys.dm_exec_sessions
_または_Utils.dbo.MyUtil
_にアクセスすると、_Utils.dbo.MyUtil
_の呼び出し元に関係なく、常に現在のデータベースがUtils
として識別されます。一方、syslogins
と_sys.sql_logins
_は、現在のデータベースではなく、ログインデータベースを返します(例:_USE xyz
_で選択したもの)。
問題は、_Utils.dbo.MyUtil
_が機能しないことではなく、自動的に機能しないことですwhere機能します(つまり、それがどこから呼び出されたかを知ることはできません)。
1つのオプション(master
の変更が含まれるため、まだ理想的ではありません。これは、@ RandiVertongenおよび@ DaniloBragaによるビルドに追加され、回答に追加されます)は、薄いラッパープロシージャを提供することですmaster
データベース内:
_USE master
GO
CREATE PROCEDURE sp_MyUtil
{...other params}
AS
BEGIN
SET NOCOUNT ON;
DECLARE @default_db_name sysname = DB_NAME()
EXEC Utils.dbo.MyUtil {...other params,} @default_db_name = @default_db_name
END
GO
USE Utils
GO
ALTER PROCEDURE MyUtil
{...other params,}
@default_db_name sysname = null
AS
BEGIN
SET NOCOUNT ON;
{...do stuff which uses @default_db_name to identify the calling DB, this is set correctly and passed automatically when sp_MyUtil is used}
END
GO
_
いいえ、電話できません:
_USE MyDatabase
GO
EXEC sp_MyUtil
GO
_
これは、_Utils.dbo.MyUtil
_を実行することになりますが、MyDatabase
で作業を行うために十分な情報が利用可能になりました。
(セキュリティ上の理由から)master
データベースへの変更を運用サーバーにインストールしないことを強くお勧めします。これらのmaster
プロシージャは、ユーザーがlessと入力できるようにするための便利なものにすぎないため、必要に応じて、Utils
ラッパープロシージャなしでmaster
データベースを本番サーバーにいつでもインストールできます。
なぜ 独自のSQL Serverシステムストアドプロシージャを作成する ?
動的SQLを使用するよりも優れたソリューションです。