2

Weird question?...maybe, but I have a need. :)

I have a stored procedure that I want to use universally in any database. The stored procedure generates some dynamic SQL and then executes that SQL in a database that is passed in as one of the parameters in this procedure.

BUT I want to make the database parameter optional and when no database name is passed in, I want the dynamic SQL to execute within the same database that the procedure itself was called from. (Please keep in mind this procedure could be executed across databases and not within the same database that the procedure itself lives in.)

  • Do you need dynamic SQL? Is something stopping you from doing like: IF @dbname IS NULL then @dbname = (SELECT dbname()) or you mean the calling procedure itself? – Jacob H Mar 14 at 18:03
  • 1
    @JacobH that unfortunately does not work when calling a stored proc from a different database, as it returns the dbname where the stored proc resides in. – Randi Vertongen Mar 14 at 18:43
  • Right, I want when the procedure executes, a way for the procedure to be able to determine which database the query that executed it was executed from. For example if my procedure lives in database A, and I execute it from database B, then I want the procedure that lives in database A to be able to determine the query that executed it came from database B. – J.D. Mar 14 at 19:14
5

You can easily tell the dynamic SQL execute in a specific database by dynamically building a [database].sys.sp_executesql command:

USE your_database;
GO

CREATE PROCEDURE dbo.DatabaseNameOptional
    @db sysname = NULL
AS
BEGIN
  SET NOCOUNT ON;

  DECLARE @sql nvarchar(max) = N'SELECT DB_NAME(); /* other stuff */'

  DECLARE @exec nvarchar(770) = COALESCE(@db, DB_NAME())
    + N'.sys.sp_executesql';

  -- alternatively, just leave DB_NAME() out of it:

  --DECLARE @exec nvarchar(770) = COALESCE(@db, N'')
  --  + N'sys.sp_executesql';

  EXEC @exec @sql;
END
GO

Try it out:

USE your_database;
GO

EXEC dbo.DatabaseNameOptional;
GO  -- output = your_database

EXEC dbo.DatabaseNameOptional @db = N'master';
GO  -- output = master

USE tempdb;
GO

EXEC your_database.dbo.DatabaseNameOptional;
GO  -- output = your_database

EXEC your_database.dbo.DatabaseNameOptional @db = N'master';
GO  -- output = master

In the execution context of the procedure, though, no, I don't think there's any way to determine where the call originated from (or to run in that context). That's the benefit of using a system-marked procedure in master - if that's the functionality you want, you need to decide if "putting objects in master" is ickier than "not getting what I want."

  • Thanks! I'm good on building / executing the dynamic SQL end, but I'm sad there isn't a better way to determine the database which the stored procedure query was executed from. Perhaps it would be pretty janky, but what about going by one of the tables or DMVs that cache query execution stats? (I guess you would need to know the user who executed it too to not mix up concurrent executions.) – J.D. Mar 14 at 21:41
2

I don't like creating procedures in master, but if you put your procedure in the master database and add the SP_ prefix like sp_dynamicproc, you could call it from inside your own user database and get the correct db_name() parameter.

Source

An example

USE master  
GO
CREATE PROCEDURE dbo.sp_dynamicproc
(@dbname nvarchar(255) = NULL)
as
BEGIN

DECLARE @SQL NVARCHAR(MAX)

IF @dbname IS NULL 
BEGIN
SET @dbname = (SELECT db_name());
END
SELECT db_name()
SET @SQL = 'SELECT * FROM '+QUOTENAME(@dbname)+'.INFORMATION_SCHEMA.COLUMNS ;';
EXEC(@SQL);

END

Calling the proc

USE test
GO
exec dbo.sp_dynamicproc;

Result

enter image description here

  • Cool, this is helpful, +1 for that. But I'm with ya, I'd prefer to not create objects in the master database, and I have a dedicated database this procedure lives in with other similar types of functions. – J.D. Mar 14 at 19:17
  • I am not sure what the role of master is, here? db_name() returns the current database name (use test) anyway? – eckes Mar 15 at 0:38
  • @eckes Yes but the procedure is only defined in master, we can call it from our any user db without specifying any other database name. If we created the same proc in say test2, we cannot call it from test without specifying exec test2.dbo.sp_dynamicproc, where db_name() would return test2` – Randi Vertongen Mar 15 at 7:42
0

Why don't you create your own SQL Server System Stored Procedures?

It's a better solution than using dynamic SQL.

  • Dynamic SQL will be occurring regardless, because I need to change my SQL statements that are executed based on the parameters inputted into the procedure. I gave you the +1 though because your answer is similarly helpful as @Randi's but I'd prefer to not create objects in the master database. – J.D. Mar 14 at 19:20
  • 1
    Why is dynamic SQL bad? It's like a lot of things - it can be dangerous in certain scenarios, if you choose to use it without any research, but it shouldn't be written off just as a matter of course. It can accomplish a lot of really powerful things that you wouldn't be able to do otherwise. – Aaron Bertrand Mar 14 at 21:21
  • Agreed, but I'm not saying dynamic SQL is bad. It's really powerful and I do like it actually. I use it in my favor to improve performance in difference situations, and to do whatever I need to customize some routines. When I first suggested, it seemed that it would be a "static stored procedure" or something like that. Using System Stored procedures he would be able to run something like: EXEC DB1.dbo.SP_whatever , EXEC DB2.dbo.SP_whatever. It would be pretty easy to know from which database it comes from. – Dan Mar 14 at 21:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.