web-dev-qa-db-ja.com

ストアドプロシージャが実行中にそのストアドプロシージャ内で実行されるデータベースの名前を取得する方法

奇妙な質問?...多分、でも私は必要があります。 :)

あらゆるデータベースで普遍的に使用したいストアード・プロシージャーがあります。ストアドプロシージャはいくつかの動的SQLを生成し、このSQLをデータベースで実行します。このSQLは、このプロシージャのパラメーターの1つとして渡されます。

しかし、データベースパラメータをオプションにし、データベース名が渡されない場合は、プロシージャ自体の呼び出し元と同じデータベース内で動的SQLを実行します。 (この手順は、データベース全体で実行でき、手順自体が存在する同じデータベース内では実行できないことに注意してください。)

3
J.D.

[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

ただし、プロシージャの実行コンテキストでは、いいえ、呼び出しがどこから発生したかを判断する方法(またはそのコンテキストで実行する方法)はないと思います。これが、システムでマークされた手順をマスターで使用する利点です。これが必要な機能である場合、「オブジェクトをマスターに置く」のが「必要なものを取得しない」よりも厄介かどうかを判断する必要があります。

6
Aaron Bertrand

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;
_

結果

enter image description here

4
Randi Vertongen

データベース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データベースを本番サーバーにいつでもインストールできます。

0
MikeBeaton

なぜ 独自のSQL Serverシステムストアドプロシージャを作成する

動的SQLを使用するよりも優れたソリューションです。

0
Danilo Braga