Sql-Server

如何找到最後一條sql語句的數據庫上下文?

  • January 10, 2019

我想從下面的程式碼中找出執行最後一個命令的數據庫的名稱是什麼。

在這種情況下,我正在尋找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

我想完成什麼?在下面的範例中,最後我列印出伺服器的名稱和我所在的數據庫的名稱: 在此處輸入圖像描述

但在下面的範例中,雖然我在技術上是在數據庫內部cola,但聲明是apcore.upl.applicationDocumentapcore是另一個數據庫。

有沒有辦法列印出來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()

即席查詢在已登錄或最近更改為通過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;

文件指出,關於返回dbid欄位的值:

對於即席和準備好的 SQL 語句,編譯語句的數據庫的 ID。

但是,我的測試表明,NULL如果最後一個語句是臨時的。

啊,但我剛看到一張紙條,上面寫著:

dbid無法從sql_handle確定即席查詢。要確定臨時查詢的dbid ,請改用plan_handle

不幸的是,您無法plan_handlesys.dm_exec_connections或中獲得 a sys.dm_exec_sessions。您可以從 獲取它sys.dm_exec_requests,但只有在會話執行查詢時才會出現行。查詢結束後,該行不再在該 DMV 中。如果您使用該 DMV 來獲取目前會話的值,那麼它將始終是您目前所在的數據庫,因為查詢將是您正在執行以查找數據庫的查詢,在這種情況下,您不妨只是選擇或database_id使用sys.dm_exec_sessions內置DB_NAME()DB_ID()函式(不為它們傳遞任何參數)。


更新解決問題中的附加資訊

$$ i $$在下面的範例中,雖然我在技術上是在數據庫內部cola,但語句是apcore.upl.applicationDocumentapcore是另一個數據庫。

是的,這是兩個不同的數據庫,但我認為你誤解了這裡發生的事情。該語句引用了一個對象。但是考慮一個多對象查詢:

       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 (...

現在有兩個數據庫被引用,你都不在其中。

如果該表上有觸發器,或者查詢使用了該OUTPUT子句,或者您啟用了快照隔離,那麼tempdb也涉及到。

唯一實際存在的上下文是您目前所在的數據庫。

就模組(儲存過程、觸發器、函式和視圖)而言,上下文是它們所在的數據庫,無論它們是從哪裡呼叫的。

但是,模組有兩個例外:

  1. 駐留在master並標記為“系統儲存過程”的儲存過程具有執行它們的位置的上下文。
  2. 臨時儲存過程是一種奇怪的情況,因為它們中的查詢在創建它們的 DB 中執行(CREATE PROCEDURE不一定是 時的目前 DB tempdb),但係統函式(例如DB_NAME(),DB_ID()等)獲取目前DB。

引用自:https://dba.stackexchange.com/questions/202509