¿Puede un procedimiento almacenado hacer referencia a la base de datos en la que está almacenado?

8

Supongamos que tengo un procedimiento almacenado que está duplicado, con algunas modificaciones, en varias bases de datos. Y quiero hacer referencia a la base de datos en la que se almacena el procedimiento almacenado, incluso si se ejecuta en otra base de datos.

¿Hay alguna manera de recuperar la ruta completa (..) o recuperar la base de datos en la que se almacena el procedimiento almacenado, en lugar de la base de datos actual?

Jim Clark
fuente
No sabía que el proceso se ejecuta en el contexto de la base de datos donde vive y quiero asegurarme de que ejecutarlo mientras está en otra base de datos no afectaría la base de datos en la que estaba.
Jim Clark

Respuestas:

13

Quiero hacer referencia a la base de datos en la que se almacena el procedimiento almacenado, incluso si se ejecuta [desde] otra base de datos.

Simplemente use nombres de una o dos partes en el procedimiento almacenado, y hará referencia a objetos en la base de datos que contiene el procedimiento almacenado. En particular,

Para SQL estático en un procedimiento almacenado:

  • Los nombres de objetos no calificados se resolverán en relación con el esquema que contiene el procedimiento almacenado.

  • Los nombres de dos partes se resolverán en relación con la base de datos que contiene el procedimiento almacenado.

Para SQL dinámico en un procedimiento almacenado:

  • Los nombres de objetos no calificados se resolverán en relación con el esquema predeterminado de la identidad del usuario que ejecuta el procedimiento almacenado (de forma predeterminada, la persona que llama).

  • Los nombres de dos partes se resolverán en relación con la base de datos que contiene el procedimiento almacenado.

La función db_name () devolverá el nombre de la base de datos que contiene el procedimiento almacenado en ambos casos.

David Browne - Microsoft
fuente
4

Aquí hay un ejemplo rápido que reuní mostrando funciones comunes utilizadas para acercarse a lo que está buscando.

/** 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 
Jonathan Fite
fuente
0

Agregando a la excelente respuesta de David Browne :

Quiero hacer referencia a la base de datos en la que se almacena el procedimiento almacenado, incluso si se ejecuta en otra base de datos.

Estás de suerte porque así es como los procedimientos regulares / permanentes, no almacenados en el sistema, ya funcionan de esta manera, y en realidad debes hacer todo lo posible para que los objetos funcionen en la base de datos actual. Así es como funcionan las funciones también, es solo que con los procedimientos almacenados, tiene opciones, marcándolas como "procedimientos almacenados del sistema" o creando procedimientos almacenados temporales, que no tiene con funciones / vistas / disparadores / etc.

Debido a que las funciones integradas se comportan de manera ligeramente diferente que el SQL estático en los procedimientos almacenados temporales, el siguiente ejemplo usa una tabla no temporal para hacer referencia tanto en UDF como en Inline-TVF. Es cierto que el siguiente ejemplo en realidad no prueba los procedimientos almacenados temporales, pero la razón por la que utilicé la tabla no temporal es porque, dado que tenemos una instancia de comportamiento diferente, debemos asegurarnos de que tal comportamiento no ocurra aquí. En el siguiente ejemplo, si cualquier tipo de función conocía la base de datos "actual", entonces la referencia a la tabla no temporal causaría un error.

PREPARAR

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

PRUEBA

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;
*/
Solomon Rutzky
fuente