Kann eine gespeicherte Prozedur auf die Datenbank verweisen, in der sie gespeichert ist?

8

Angenommen, ich habe eine gespeicherte Prozedur, die mit einigen Änderungen in mehreren Datenbanken dupliziert wird. Und ich möchte auf die Datenbank verweisen, in der die gespeicherte Prozedur gespeichert ist, auch wenn sie in einer anderen Datenbank ausgeführt wird.

Gibt es eine Möglichkeit, den vollständigen Pfad (..) abzurufen oder auf andere Weise die Datenbank abzurufen, in der die gespeicherte Prozedur gespeichert ist, und nicht die aktuelle Datenbank?

Jim Clark
quelle
Ich wusste nicht, dass der Prozess in dem Datenbankkontext ausgeführt wird, in dem er sich befindet, und ich möchte sicherstellen, dass das Ausführen in einer anderen Datenbank keine Auswirkungen auf die Datenbank hat, in der Sie sich befinden.
Jim Clark

Antworten:

13

Ich möchte auf die Datenbank verweisen, in der die gespeicherte Prozedur gespeichert ist, auch wenn sie [aus] einer anderen Datenbank ausgeführt wird.

Verwenden Sie einfach einteilige oder zweiteilige Namen in der gespeicherten Prozedur, und es wird auf Objekte in der Datenbank verwiesen, die die gespeicherte Prozedur enthalten. Bestimmtes,

Für statisches SQL in einer gespeicherten Prozedur:

  • Nicht qualifizierte Objektnamen werden relativ zu dem Schema aufgelöst, das die gespeicherte Prozedur enthält.

  • Zweiteilige Namen werden relativ zur Datenbank aufgelöst, die die gespeicherte Prozedur enthält.

Für dynamisches SQL in einer gespeicherten Prozedur:

  • Nicht qualifizierte Objektnamen werden relativ zum Standardschema der Benutzeridentität aufgelöst, auf der die gespeicherte Prozedur ausgeführt wird (standardmäßig der Aufrufer).

  • Zweiteilige Namen werden relativ zur Datenbank aufgelöst, die die gespeicherte Prozedur enthält.

Die Funktion db_name () gibt in beiden Fällen den Namen der Datenbank zurück, die die gespeicherte Prozedur enthält.

David Browne - Microsoft
quelle
4

Hier ist ein kurzes Beispiel, das ich zusammengestellt habe und das allgemeine Funktionen zeigt, mit denen Sie sich dem nähern, wonach Sie suchen.

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

Zu David Brownes hervorragender Antwort hinzufügen :

Ich möchte auf die Datenbank verweisen, in der die gespeicherte Prozedur gespeichert ist, auch wenn sie in einer anderen Datenbank ausgeführt wird.

Sie haben Glück, denn so funktionieren reguläre / permanente, nicht vom System gespeicherte Prozeduren bereits auf diese Weise, und Sie müssen sich wirklich alle Mühe geben, damit Objekte in der aktuellen Datenbank funktionieren. So funktionieren auch Funktionen. Bei gespeicherten Prozeduren haben Sie nur Optionen - sie als "gespeicherte Systemprozeduren" markieren oder temporär gespeicherte Prozeduren erstellen -, die Sie bei Funktionen / Ansichten / Triggern / etc. nicht haben.

Da sich integrierte Funktionen in temporär gespeicherten Prozeduren geringfügig anders verhalten als statisches SQL, wird im folgenden Beispiel eine nicht temporäre Tabelle verwendet, um sowohl in einer UDF als auch in einer Inline-TVF zu referenzieren. Das folgende Beispiel testet zwar keine temporär gespeicherten Prozeduren, aber der Grund, warum ich die nicht temporäre Tabelle verwendet habe, ist, dass wir sicherstellen müssen, dass ein solches Verhalten hier nicht auftritt, da wir eine Instanz mit unterschiedlichem Verhalten haben. Wenn im folgenden Beispiel einer der Funktionstypen die "aktuelle" Datenbank kennt, würde der Verweis auf die nicht temporäre Tabelle einen Fehler verursachen.

INSTALLIEREN

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

PRÜFUNG

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
quelle