2013-04-12 1 views
5

Ho un numero di database diversi su un singolo SQL Server 2008 R2. Per amor di argomenti, chiamiamoli DB_A, DB_B e DB_C. Mi è stato chiesto di sviluppare come stored proc che vivrà su DB_A. Questo processo memorizzato verrà utilizzato per eliminare e creare indici e anche per memorizzare ulteriori informazioni sull'indice in una tabella su DB_A. Quando questo proc memorizzato viene richiamato da DB_C o DB_C, sarà in grado di rilasciare e creare indici sul database chiamante, ma memorizzare le informazioni aggiuntive sull'indice nella tabella su DB_A.Come restituire il nome del database remoto che chiama un proc memorizzato in un altro database?

Ecco cosa mi piacerebbe fare: vorrei che il proc memorizzato fosse in grado di ottenere il nome del database di chiamata SENZA dover richiedere il nome del database come parametro.

Ecco un semplice esempio:

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 

Quando eseguo la stored procedure in DB_A ...

EXEC sp_WhatDatabaseAmICallingFrom 

... ritorna: "banca dati chiamando: DB_A"

Quando eseguo la stored procedure in DB_B ...

USE DB_B 
GO 

EXEC DB_A.dbo.sp_WhatDatabaseAmICallingFrom 

... restituisce: "database chiamante: DB_A".

Dopo aver letto le varie funzioni dei metadati di SQL Server, questo è esattamente ciò che dovrebbe fare. Ma quello che vorrei è di cambiare il codice in modo da impostare @calling_db sul nome del database chiamante, in modo che il mio esempio memorizzato proc possa stampare: "database chiamante: DB_B".

Sfortunatamente, non riesco a trovare alcuna funzione di metadati che possa farlo. Qualche idea su come questo può essere fatto?

+0

Domanda molto interessante.Per curiosità, esiste un motivo per cui non si desidera che il processo che chiama lo sproc fornisca il parametro dbname come parametro (oltre a dover supportare un parametro e fornirlo)? Un pensiero se non esiste un modo diretto per farlo sarebbe rendere il parametro opzionale @CallingDB NVARCHAR (128) = NULL e verificare se il valore è nullo. In tal caso, per impostazione predefinita utilizzare DB_NAME(). Naturalmente, questo significa che l'invocazione da altri database dovrebbe fornire il nome ... –

+0

L'unico vero motivo per cui non voglio usare un parametro è che penso ci debba essere un modo per farlo, e odio camminare lontano da una sfida come questa senza trovare una soluzione. –

+0

FYI, la stessa domanda è stata [posta sul sito DBA] (http://dba.stackexchange.com/questions/30310/db-id-context-from-farther-up-call-stack), anche se non ha Ho avuto risposta. I suggerimenti fatti erano di usare eventi estesi, SQL CLR o mantenere il proprio stack di chiamate usando ['CONTEXT_INFO'] (http://msdn.microsoft.com/en-us/library/ms187768.aspx). – Pondlife

risposta

4

Per rendere SP eseguito nel contesto della connessione corrente è necessario creare il proprio SP su master database e trasformarlo in un oggetto di sistema.

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 

controllare come funziona:

USE [DB_A] 
GO 

EXEC sp_WhatDatabaseAmICallingFrom 
GO 
3

so che questa discussione è piuttosto vecchio, ma ho trovato qualcosa che almeno mi ha aiutato.

Se si utilizza DB_A e sta chiamando una stored procedure in DB_B come:

USE DB_A 
EXEC db_b.dbo.sproc 

L'unico modo che ho trovato per ottenere l'id "banca dati chiamata" è quello di eseguire una selezione contro sys.dm_tran_locks all'interno la stored procedure. request_session_id dovrebbe essere il tuo spid, resource_type dovrebbe essere DATABASE e request_owner_type dovrebbe essere SHARED_TRANSACTION_WORKSPACE. Tale blocco condiviso esiste sempre su un database per ogni sessione connessa. La query sarebbe qualcosa di simile:

SELECT resource_database_id FROM sys.dm_tran_locks WHERE request_session_id = @@SPID and resource_type = 'DATABASE' and request_owner_type = 'SHARED_TRANSACTION_WORKSPACE' 

Anche se questo richiede che l'utente esegue di avere almeno autorizzazioni di visualizzazione server di stato sul server. Nel mio caso non era un problema però ..