Um procedimento armazenado pode fazer referência ao banco de dados em que está armazenado?

8

Suponha que eu tenha um procedimento armazenado duplicado, com algumas modificações, em vários bancos de dados. E eu quero fazer referência ao banco de dados no qual o procedimento armazenado está armazenado, mesmo que seja executado em outro banco de dados.

Existe uma maneira de recuperar o caminho completo (..) ou recuperar o banco de dados no qual o procedimento armazenado está armazenado, em vez do banco de dados atual?

Jim Clark
fonte
Eu não sabia que os executa proc no contexto do banco de dados onde vive e eu quero ter certeza de que executá-lo em enquanto em outro banco de dados não afetaria a base de dados que estavam no.
Jim Clark

Respostas:

13

Quero referenciar o banco de dados no qual o procedimento armazenado está armazenado, mesmo se for executado [de] outro banco de dados.

Basta usar nomes de uma ou duas partes no procedimento armazenado, e ele fará referência a objetos no banco de dados que contém o procedimento armazenado. Em particular,

Para SQL estático em um procedimento armazenado:

  • Os nomes de objetos não qualificados serão resolvidos em relação ao esquema que contém o procedimento armazenado.

  • Os nomes de duas partes serão resolvidos em relação ao banco de dados que contém o procedimento armazenado.

Para SQL dinâmico em um procedimento armazenado:

  • Os nomes de objetos não qualificados serão resolvidos em relação ao esquema padrão da identidade do usuário executando o procedimento armazenado (por padrão, o chamador).

  • Os nomes de duas partes serão resolvidos em relação ao banco de dados que contém o procedimento armazenado.

A função db_name () retornará o nome do banco de dados que contém o procedimento armazenado nos dois casos.

David Browne - Microsoft
fonte
4

Aqui está um exemplo rápido que eu reuni mostrando funções comuns usadas para se aproximar do que você está procurando.

/** 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
fonte
0

Adicionando a excelente resposta de David Browne :

Quero referenciar o banco de dados no qual o procedimento armazenado está armazenado, mesmo que seja executado em outro banco de dados.

Você está com sorte, porque é assim que os procedimentos armazenados regulares / permanentes, que não são do sistema, já funcionam dessa maneira e você realmente precisa se esforçar para fazer com que os objetos operem no banco de dados atual. É assim que as funções também funcionam: apenas com procedimentos armazenados, você tem opções - marcando-as como "procedimentos armazenados do sistema" ou criando procedimentos armazenados temporários - que você não possui com funções / visualizações / gatilhos / etc.

Como as funções internas se comportam de maneira ligeiramente diferente do SQL estático nos procedimentos armazenados temporários, o exemplo a seguir usa uma tabela não temporária para fazer referência em UDF e Inline-TVF. É verdade que o exemplo a seguir na verdade não testa procedimentos armazenados temporários, mas o motivo pelo qual usei a tabela não temporária é porque, como temos uma instância de comportamento diferente, precisamos garantir que esse comportamento não ocorra aqui. No exemplo a seguir, se qualquer um dos tipos de função estivesse ciente do banco de dados "atual", a referência à tabela não temporária causaria um erro.

CONFIGURAÇÃO

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

TESTE

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
fonte