web-dev-qa-db-ja.com

最後のSQLステートメントのデータベースコンテキストを見つける方法は?

以下のコードから、最後のコマンドが実行されたデータベースの名前を確認したいと思います。

この場合、私はmy_other_databaseを探しています。

彼はこれを見つける方法はありますか?この情報のために私が見なければならないDMVはありますか?

また、更新が動的SQLでラップされている場合、それを追跡することは可能でしょうか?

use my_database
go

begin tran t1

UPDATE my_other_database.REF.applicationReference
SET uploadPaperReferences = 0
WHERE REFERENCEID IN (
69361,
69690,
69354,
69358,
69362,
69732,
69863,
70187
)

commit tran t1

私は何を達成しようとしていますか?最後に、以下の例のように、サーバーの名前と使用しているデータベースの名前を出力します。 enter image description here

ただし、以下の例では、技術的にはデータベースcola内にいましたが、ステートメントはapcore.upl.applicationDocumentであり、apcoreは別のデータベースです。

apcoreの代わりにcolaを印刷する方法はありますか?

SET NOCOUNT OFF
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

BEGIN TRAN T1

PRINT ''
PRINT 'AFTER BEGIN TRAN'
PRINT ''
PRINT '@@TRANCOUNT: '  + CAST(@@TRANCOUNT AS VARCHAR)
PRINT '@@SERVERNAME: ' + CAST(@@SERVERNAME AS VARCHAR) + CHAR(10) + 'Databasename: ' + DB_NAME()
PRINT ''


DECLARE @row INT

USE COLA
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

            update t
            set documentstateid = 5
             from apcore.upl.applicationDocument t
            where applicationid in (
                                    319761
                                    ,320455
                                    ,333433
                                    ,351642
                                    ,371539
                                    ,372508
                                    )

             and documentStateId not in (1,5)

SELECT @row = @@ROWCOUNT

PRINT ''
PRINT 'AFTER RUNNING THE UPDATE(s)'
PRINT ''
PRINT 'The number of rows updated:' + SPACE(1) + CAST(@row as varchar)
PRINT '@@TRANCOUNT: '  + CAST(@@TRANCOUNT AS VARCHAR)
PRINT 'Server Name is:' + space(1) +  @@SERVERNAME + CHAR(10) + 'Databasename: ' + DB_NAME()


COMMIT TRAN T1

PRINT ''
PRINT 'AFTER COMMIT'
PRINT ''
PRINT '@@TRANCOUNT: '  + CAST(@@TRANCOUNT AS VARCHAR)
PRINT 'Server Name is:' + space(1) +  @@SERVERNAME + CHAR(10) + 'Databasename: ' + DB_NAME()
3

アドホッククエリは、ログインしたか、ほとんどの場合USEステートメントを介して最近変更されたデータベースで実行されます。

ストアドプロシージャまたは関数内で実行されているクエリは、それらが含まれているモジュールが存在するデータベースで実行されます。

例えば:

_USE [tempdb];
-- DROP PROCEDURE dbo.CurrentDatabaseTest;
GO
CREATE PROCEDURE dbo.CurrentDatabaseTest
AS
SET NOCOUNT ON;

SELECT db.[database_id], db.[name]
FROM sys.dm_exec_sessions es
INNER JOIN sys.databases db
        ON db.[database_id] = es.[database_id]
WHERE es.[session_id] = @@SPID;
GO

USE [model];

SELECT db.[database_id], db.[name]
FROM sys.dm_exec_sessions es
INNER JOIN sys.databases db
        ON db.[database_id] = es.[database_id]
WHERE es.[session_id] = @@SPID;

EXEC tempdb.dbo.CurrentDatabaseTest;
GO
_

上記を実行すると、以下が返されます。

_database_id    name
3              model


database_id    name
2              tempdb
_

次のクエリからデータベースIDを取得できる場合がありますが、常にそうとは限りません。

_SELECT txt.*
FROM   sys.dm_exec_connections con
OUTER APPLY  sys.dm_exec_sql_text(con.[most_recent_sql_handle]) txt
--WHERE  con.[session_id] = @@SPID;
_

documentation は、返されたdbidフィールドの値に関して次のように述べています。

アドホックおよび準備されたSQLステートメントの場合、ステートメントがコンパイルされたデータベースのID。

ただし、私のテストでは、最後のステートメントがアドホックだった場合はNULLのように見えることが示されています。

ああ、でも私は次のようなメモを見ました。

dbidは、アドホッククエリのsql_handleから決定できません。アドホッククエリのdbidを決定するには、代わりにplan_handleを使用します。

残念ながら、_plan_handle_または_sys.dm_exec_connections_から_sys.dm_exec_sessions_を取得することはできません。 _sys.dm_exec_requests_から取得できますが、行はセッションがクエリを実行しているときにのみ存在します。クエリが終了すると、その行はそのDMVに含まれなくなります。また、そのDMVを使用して現在のセッションの値を取得する場合、クエリはデータベースを見つけるために実行しているクエリになるため、常に現在のデータベースになります。この場合は、 _database_id_から_sys.dm_exec_sessions_を選択するか、組み込みのDB_NAME()およびDB_ID()関数を使用します(パラメーターを渡さないでください)。


UPDATE質問の追加情報への対応

[i]以下の例では、技術的にはデータベースcola内にいましたが、ステートメントは_apcore.upl.applicationDocument_であり、apcoreは別のデータベースです。

はい、これらは2つの異なるデータベースですが、ここで何が起こっているのか誤解していると思います。そのステートメントは単一のオブジェクトを参照していました。ただし、マルチオブジェクトクエリについて考えてみます。

_        update t
        set documentstateid = 5
         from apcore.upl.applicationDocument t
           INNER JOIN other_db.dbo.some_table st
                   ON st.column = t.column
        where applicationid in (...
_

現在、2つのデータベースが参照されていますが、どちらも使用していません。

そのテーブルにトリガーがある場合、クエリでOUTPUT句が使用されている場合、またはスナップショットアイソレーションが有効になっている場合は、tempdbも含まれます。

実際に存在する唯一のコンテキストは、現在使用しているDBです。

また、モジュール(ストアドプロシージャ、トリガー、関数、およびビュー)に関しては、コンテキストは、それらがどこから呼び出されたかに関係なく、それらが存在するDBです。

ただし、モジュールには2つの例外があります。

  1. masterに存在し、「システムストアドプロシージャ」としてマークされているストアドプロシージャには、実行されている場所のコンテキストがあります。
  2. 一時的なストアドプロシージャは、クエリが作成されたDB(_CREATE PROCEDURE_の時点での現在のDB、必ずしもtempdbではない)でクエリが実行されるという奇妙なケースですが、システム関数(例: DB_NAME()DB_ID()など)はcurrentDBを取得します。
2
Solomon Rutzky

このスクリプトのコンテキストはmy_database。クエリが別のデータベースのオブジェクトを参照しているだけです。 1つのクエリで複数のデータベースのオブジェクトを使用するシナリオを考えてみます。どのデータベースを返したいですか?

何を達成しようとしていますか?

2
Dan Guzman