如何在无参数情况下获取存储过程的原始调用数据库
如何在存储过程中获取调用方的原始数据库(无需传入参数)
我正在开发一个存储过程,希望获取它的原始调用来源——也就是调用该存储过程时所在的数据库,并且尽可能不通过参数实现这个需求。
我试过带默认参数的存储方案,但没法把db_name()设为默认参数,不然这就是最理想的解决办法。我还了解过将函数作为默认参数值的方案,但不确定能不能用这个实现需求。
目前我是通过参数实现的功能,但觉得不够理想,现有代码如下:
select @@SERVERNAME use master go create or alter procedure whereami @origin sysname = null as begin print @origin select [inside the procedure] = @origin end go use [database one] select db_name() declare @a sysname = db_name() use [database two] select db_name() exec master.dbo.whereami @origin = @a

无需参数的解决方案
方案1:利用sys.dm_exec_requests直接获取
这是最可靠的方式,sys.dm_exec_requests中的database_id字段记录了当前请求执行时的数据库上下文,也就是调用存储过程时所在的数据库:
use master go create or alter procedure whereami as begin declare @calling_db sysname select @calling_db = DB_NAME(database_id) from sys.dm_exec_requests where session_id = @@SPID and request_id = 0 print @calling_db select [inside the procedure] = @calling_db end go
方案2:结合会话视图解析调用上下文
如果需要处理会话中切换数据库的场景,可以结合sys.dm_exec_input_buffer解析调用语句中的USE命令,同时用sys.dm_exec_sessions的original_db_name作为 fallback:
use master go create or alter procedure whereami as begin declare @session_id int = @@SPID declare @sql_text nvarchar(max) declare @calling_db sysname -- 获取当前会话的输入SQL文本 select @sql_text = event_info from sys.dm_exec_input_buffer(@session_id, null) -- 检查是否有USE语句切换数据库 if CHARINDEX('USE ', @sql_text) > 0 begin -- 提取USE后的数据库名称 set @calling_db = SUBSTRING( @sql_text, CHARINDEX('USE ', @sql_text) + 4, CHARINDEX(CHAR(10), @sql_text, CHARINDEX('USE ', @sql_text)) - (CHARINDEX('USE ', @sql_text) + 4) ) -- 去掉可能存在的方括号 set @calling_db = REPLACE(REPLACE(@calling_db, '[', ''), ']', '') end else begin -- 没有USE语句时,取会话初始连接的数据库 select @calling_db = original_db_name from sys.dm_exec_sessions where session_id = @session_id end print @calling_db select [inside the procedure] = @calling_db end go
内容的提问来源于stack exchange,提问作者Marcello Miorelli
相关产品推荐
相关产品推荐

