Una procedura memorizzata può fare riferimento al database in cui è memorizzata?


8

Supponiamo di avere una procedura memorizzata che è duplicata, con alcune modifiche, in diversi database. E voglio fare riferimento al database in cui è memorizzata la procedura memorizzata, anche se viene eseguita in un altro database.

Esiste un modo per recuperare il percorso completo (..) o altrimenti recuperare il database in cui è memorizzata la procedura memorizzata, anziché il database corrente?


Non sapevo che il proc si eseguisse nel contesto del database in cui vive e voglio assicurarmi che eseguirlo mentre si trova in un altro database non influirebbe sul database in cui ti trovavi.
Jim Clark,

Risposte:


13

Voglio fare riferimento al database in cui è memorizzata la procedura memorizzata, anche se viene eseguita [da] un altro database.

Utilizzare solo nomi di una o due parti nella procedura memorizzata e farà riferimento agli oggetti nel database contenente la procedura memorizzata. In particolare,

Per SQL statico in una procedura memorizzata:

  • I nomi degli oggetti non qualificati si risolveranno in relazione allo schema contenente la procedura memorizzata.

  • I nomi in due parti verranno risolti in relazione al database contenente la procedura memorizzata.

Per SQL dinamico in una procedura memorizzata:

  • I nomi degli oggetti non qualificati si risolveranno in relazione allo schema predefinito dell'identità dell'utente che esegue la procedura memorizzata (per impostazione predefinita, il chiamante).

  • I nomi in due parti verranno risolti in relazione al database contenente la procedura memorizzata.

La funzione db_name () restituirà il nome del database contenente la procedura memorizzata in entrambi i casi.


4

Ecco un breve esempio che ho messo insieme mostrando le funzioni comuni utilizzate per avvicinarsi a ciò che stai cercando.

/** Create a procedure in master to demonstrate
    DB_NAME()
    OBJECT_SCHEMA_NAME()
    OBJECT_NAME()
    @@PROCID
**/
USE [master]
GO

CREATE OR ALTER PROCEDURE dbo.uspTestMe
AS
BEGIN

    PRINT 'Database: ' + DB_NAME()
    PRINT 'Schema Name: ' + OBJECT_SCHEMA_NAME(@@PROCID)
    PRINT 'Procedure Name: ' + OBJECT_NAME(@@PROCID)

END

GO

/** CHANGE Context to TempDB
    Execute procedure in master
    **/
USE [tempdb]
GO

EXEC master.dbo.uspTestMe 

GO

/** Cleanup in master **/
USE [master]
GO

DROP PROCEDURE IF EXISTS dbo.uspTestMe 

0

Aggiungendo all'ottima risposta di David Browne :

Voglio fare riferimento al database in cui è memorizzata la procedura memorizzata, anche se viene eseguita in un altro database.

Sei fortunato perché questo è il modo in cui le procedure memorizzate regolari / permanenti, non di sistema, funzionano già in questo modo e in realtà devi fare di tutto per far funzionare gli oggetti nel database corrente. Questo è il modo in cui funzionano anche le funzioni, è solo che con le procedure memorizzate, hai delle opzioni - contrassegnandole come "procedure memorizzate dal sistema" o creando procedure memorizzate temporanee - che non hai con le funzioni / viste / trigger / ecc.

Poiché le funzioni integrate si comportano in modo leggermente diverso rispetto all'SQL statico nelle stored procedure temporanee, il seguente esempio utilizza una tabella non temporanea per fare riferimento sia in UDF che Inline-TVF. È vero, il seguente esempio in realtà non testa le stored procedure temporanee, ma il motivo per cui ho usato la tabella non temporanea è perché poiché abbiamo un'istanza di comportamento diverso, dobbiamo assicurarci che tale comportamento non si verifichi qui. Nel seguente esempio, se uno dei due tipi di funzione fosse a conoscenza del database "corrente", il riferimento alla tabella non temporanea causerebbe un errore.

IMPOSTARE

USE [tempdb];

CREATE IF NOT EXISTS TABLE dbo.InTempDB (Col1 INT);
INSERT INTO dbo.InTempDB ([Col1]) VALUES (999);

GO
CREATE 
OR ALTER -- comment out if using SQL Server < 2017
FUNCTION dbo.GetDbNameUDF()
RETURNS SYSNAME
AS
BEGIN
  DECLARE @DoNothing INT;
  SELECT @DoNothing = [Col1] FROM dbo.InTempDB;

  RETURN DB_NAME();
END;

GO
CREATE
OR ALTER -- comment out if using SQL Server < 2017
FUNCTION dbo.GetDbNameITVF()
RETURNS TABLE
AS
RETURN
  SELECT DB_NAME() AS [DbName],
         tmp.[Col1]
  FROM   dbo.InTempDB tmp;

GO

TEST

USE [model];

SELECT DB_NAME() AS [CurrentDB],
       tempdb.dbo.GetDbNameUDF() AS [DbNameFromUDF];
-- CurrentDB    DbNameFromUDF
-- model        tempdb


SELECT DB_NAME() AS [CurrentDB],
       *
FROM   tempdb.dbo.GetDbNameITVF();
-- CurrentDB    DbName    Col1
-- model        tempdb    999


/* -- clean-up
DROP TABLE dbo.InTempDB;
DROP FUNCTION dbo.GetDbNameUDF;
DROP FUNCTION dbo.GetDbNameITVF;
*/
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.