Une procédure stockée peut-elle référencer la base de données dans laquelle elle est stockée?

8

Supposons que j'ai une procédure stockée qui est dupliquée, avec quelques modifications, dans plusieurs bases de données. Et je veux faire référence à la base de données dans laquelle la procédure stockée est stockée, même si elle est exécutée dans une autre base de données.

Existe-t-il un moyen de récupérer le chemin d'accès complet (..) ou de récupérer la base de données dans laquelle la procédure stockée est stockée, plutôt que la base de données actuelle?

Jim Clark
la source
Je ne savais pas que le proc s'exécute dans le contexte de la base de données où il se trouve et je veux m'assurer que son exécution dans une autre base de données n'affectera pas la base de données dans laquelle vous vous trouviez.
Jim Clark

Réponses:

13

Je veux faire référence à la base de données dans laquelle la procédure stockée est stockée, même si elle est exécutée [à partir] d'une autre base de données.

Utilisez simplement des noms en une ou deux parties dans la procédure stockée, et elle référencera les objets dans la base de données contenant la procédure stockée. En particulier,

Pour SQL statique dans une procédure stockée:

  • Les noms d'objet non qualifiés seront résolus par rapport au schéma contenant la procédure stockée.

  • Les noms en deux parties seront résolus par rapport à la base de données contenant la procédure stockée.

Pour SQL dynamique dans une procédure stockée:

  • Les noms d'objet non qualifiés seront résolus par rapport au schéma par défaut de l'identité de l'utilisateur exécutant la procédure stockée (par défaut, l'appelant).

  • Les noms en deux parties seront résolus par rapport à la base de données contenant la procédure stockée.

La fonction db_name () renverra le nom de la base de données contenant la procédure stockée dans les deux cas.

David Browne - Microsoft
la source
4

Voici un exemple rapide que j'ai rassemblé montrant les fonctions courantes utilisées pour se rapprocher de ce que vous recherchez.

/** 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
la source
0

Ajoutant à l'excellente réponse de David Browne :

Je veux référencer la base de données dans laquelle la procédure stockée est stockée, même si elle est exécutée dans une autre base de données.

Vous avez de la chance, car c'est ainsi que les procédures stockées régulières / permanentes non système fonctionnent déjà de cette façon, et vous devez en fait faire tout votre possible pour que les objets fonctionnent dans la base de données actuelle. C'est ainsi que fonctionnent les fonctions, c'est juste qu'avec les procédures stockées, vous avez des options - les marquer comme "procédures stockées système" ou créer des procédures stockées temporaires - que vous n'avez pas avec les fonctions / vues / déclencheurs / etc.

Étant donné que les fonctions intégrées se comportent légèrement différemment du SQL statique dans les procédures stockées temporaires, l'exemple suivant utilise une table non temporaire pour référencer à la fois un UDF et Inline-TVF. Certes, l'exemple suivant ne teste pas réellement les procédures stockées temporaires, mais la raison pour laquelle j'ai utilisé la table non temporaire est parce que comme nous avons une instance de comportement différent, nous devons nous assurer que ce comportement ne se produit pas ici. Dans l'exemple suivant, si l'un ou l'autre type de fonction connaissait la base de données "actuelle", la référence à la table non temporaire provoquerait une erreur.

INSTALLER

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

TESTER

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
la source