如何返回在另一个数据库中调用存储过程的远程数据库名称?

时间:2013-04-12 16:17:27

标签: sql sql-server stored-procedures

我在单个SQL Server 2008 R2上有许多不同的数据库。为了论证,让我们称它们为DB_A,DB_B和DB_C。我被要求开发为存储过程,它将存在于DB_A上。此存储过程将用于删除和创建索引,并在DB_A上的表中存储有关索引的一些额外信息。当从DB_C或DB_C调用此存储过程时,它将能够在调用数据库上删除并创建索引,但在DB_A上的表中存储有关索引的额外信息。

这就是我想要做的事情:我希望存储过程能够获取调用数据库的名称,而不必请求数据库名称作为参数。

这是一个简单的例子:

USE [DB_A]

CREATE PROC sp_WhatDatabaseAmICallingFrom
AS 
BEGIN
      DECLARE @calling_db NVARCHAR(128)
      SET @calling_db = DB_NAME()
      PRINT 'calling database: ' + @calling_db
END

当我在DB_A ...

中执行存储过程时
EXEC sp_WhatDatabaseAmICallingFrom

...它返回:“调用数据库:DB_A

当我在DB_B中执行存储过程...

USE DB_B
GO

EXEC DB_A.dbo.sp_WhatDatabaseAmICallingFrom

...它返回:“调用数据库:DB_A ”。

在阅读了各种SQL Server元数据函数之后,这正是它应该做的。但我想要的是更改代码,以便将@calling_db设置为调用数据库的名称,以便我的示例存储过程将打印:“调用数据库:DB_B ”。

不幸的是,我找不到任何能够做到这一点的元数据功能。关于如何做到这一点的任何想法?

3 个答案:

答案 0 :(得分:4)

要在当前连接的上下文中运行SP,您需要在master数据库上创建SP并使其成为系统对象。

USE MASTER 
GO 

CREATE PROC sp_WhatDatabaseAmICallingFrom
AS 
BEGIN
      DECLARE @calling_db NVARCHAR(128)
      SET @calling_db = DB_NAME()
      PRINT 'calling database: ' + @calling_db
END
GO

EXEC sp_ms_marksystemobject 'sp_WhatDatabaseAmICallingFrom'
GO

检查它的工作原理:

USE [DB_A]
GO

EXEC sp_WhatDatabaseAmICallingFrom
GO

答案 1 :(得分:3)

我知道这个帖子很老了,但我发现了一些至少帮助我的东西。

如果您正在使用DB_A并在DB_B中调用存储过程,如:

<android.support.v7.widget.CardView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginLeft="15dp"
        android:clipChildren="false">
    <ImageView
           android:layout_marginLeft="-10dp"
           android:background="@drawable/some_picture"
           android:layout_width="50dp"
           android:layout_height="50dp"/>
</android.support.v7.widget.CardView>

我找到获取“调用数据库”id的唯一方法是在存储过程内对sys.dm_tran_locks运行select。 request_session_id应该是你的spid,resource_type应该是DATABASE,request_owner_type应该是SHARED_TRANSACTION_WORKSPACE。对于每个连接的会话,这种共享锁始终存在于数据库中。查询将类似于:

USE DB_A
EXEC db_b.dbo.sproc

虽然这要求执行用户至少拥有服务器上的VIEW SERVER STATE权限。在我的情况下,这不是一个问题..

答案 2 :(得分:0)

基于Mike的答案,这是在Sql2012中有效的解决方案的示例。

您必须在以具有足够权限(“查看服务器状态”)的用户身份登录时创建功能,但是使用该功能的用户仅需要权限才能执行该功能本身。

USE [DB_A];
GO

CREATE FUNCTION dbo.GetCallingDbCatName()
RETURNS nvarchar(128) 
WITH EXECUTE AS SELF
AS
BEGIN
    DECLARE @result nvarchar(128);
    SELECT TOP 1 @result = DB_NAME(resource_database_id) 
        FROM sys.dm_tran_locks 
        WHERE request_session_id = @@SPID 
            AND resource_type = 'DATABASE' 
            AND request_owner_type = 'SHARED_TRANSACTION_WORKSPACE' 
        ORDER BY IIF(resource_database_id != DB_ID(), 0, 1);
    RETURN @result;
END
GO

USE [DB_A];
SELECT DB_A.dbo.GetCallingDbCatName(); --"DB_A"
USE [DB_B];
SELECT DB_A.dbo.GetCallingDbCatName(); --"DB_B"
USE [DB_C];
SELECT DB_A.dbo.GetCallingDbCatName(); --"DB_C"

从那里,您应该能够构建所需的实际功能,而无需污染 master dbcat。