Use "the USE [Database]" statement dynamically inside a SQL stored procedure - sql-server

I've created a stored procedure where I want to pass the #DB through a USE command. I know I can define dynamically the correct path for the table with the name of the DB (e.g. ... '+ #DB +' .dbo.tAnalysisResult' ) but I have several inner joins with many tables on the same database so I'd like to define the DB only once at the beginning.
Any help will be highly appreciated. Below my query which currently doesn't work:
USE [DB_Research]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].sp_test1 #DB VARCHAR(300), #OUTCOME INT OUTPUT
AS
SET NOCOUNT ON
EXECUTE ('USE' + #DB)
BEGIN TRY
SELECT #OUTCOME = (select SUM(ResultSID) from tAnalysisResult)
END TRY BEGIN CATCH
-- If error encountered, display it
SELECT #OUTCOME = '0, line: ' + CAST(ERROR_LINE() AS VARCHAR(MAX)) + ', msg:' + ERROR_MESSAGE()
END CATCH
SET NOCOUNT OFF
-- Execute the stored procedure
declare #OUTCOME INT
exec sp_test1 'Loss_DB', #OUTCOME OUTPUT
Print(#OUTCOME)

Select * from dbname..schemaname.tablename

Related

Unable to execute SQL Server stored procedure with variables (could not find stored procedure)

I was unable to find the solution for the issue and unable to execute a stored procedure. Am I missing anything in the stored procedure?
Main aim is to run multiple tables inserts into different tables (different metadata).
This is my stored procedure:
CREATE OR ALTER PROCEDURE newsample
AS
BEGIN
DECLARE #sqlquery varchar(max);
SET #sqlquery = 'insert into dbo.table1 select 2 as newcol;
insert into dbo.table2 select 2 as newcol;
insert into dbo.table3 select 2 as newcol;
insert into dbo.table4 select 2 as newcol;';
EXEC #sqlquery
END
EXEC dbo.newsample
Error:
Msg 2812, Level 16, State 62, Procedure dbo.newsample, Line 6 [Batch Start Line 9]
Could not find stored procedure 'insert into dbo.table1 select 2 as newcol'.
Appreciate your help.
Thank you
To execute arbitrary dynamic sql, you have to use exec(), not exec.
exec('select 0'); exec(#myDynamicSql);
If you use exec arg, then arg is a stored procedure or function, or the name of a stored procedure or function. Yep, it can be a function. And these can either be the literal names, or strings with the value of the name. All of the following works:
create procedure dbo.p as begin set nocount on; end;
go
create function dbo.funcwithoutargs() returns int as begin return 2; end
go
create function dbo.funcwithargs(#i int) returns int as begin return #i; end
go
declare #i int = 0, #module sysname;
exec dbo.p;
exec #i = dbo.funcwithoutargs;
exec #i = dbo.funcwithargs #i;
set #Module = 'dbo.p';
exec #module;
set #module = 'dbo.funcwithoutargs';
exec #i = #module;
The line
EXEC #sqlquery
Should be
EXEC sp_executesql #stmt = #sqlquery

Global temporary table scope behaves differently inside a stored procedure

The following code executes successfully, unless I add create procedure dbo.proc_name ... as to it:
use db_name
go
declare #sp_date date;
select #sp_date = getdate();
if object_id('tempdb..##global_tmp_tbl') is not null drop table ##global_tmp_tbl;
begin transaction
set xact_abort on
declare #query varchar(250), #exec_stmnt varchar(500);
set #query = 'exec remote_db.dbo.remote_sp' + ' ''''' + cast(#sp_date as varchar(10)) + ''''' ';
set #query = '''' + #query + '''';
set #exec_stmnt = 'select * into ##global_tmp_tbl from openquery(LS_RMT,' + #query + ')';
exec (#exec_stmnt);
commit transaction
go
if object_id('tempdb..#local_tmp_tbl') is not null drop table #local_tmp_tbl;
select * into #local_tmp_tbl from ##global_tmp_tbl;
Here LS_RMT is a linked server, and remote_sp is a stored procedure on the database remote_db on that linked server.
When I try to put this code into a stored procedure, SQL Server complains that ##global_tmp_tbl is an invalid name when trying to read from it after executing the stored procedure on the linked server which loads it.
I'm guessing that the scope of the global temporary table changes once within the context of a stored procedure, but I can't find any documentation on why that might be the case so I'm not sure.
Is this a scope issue, or is it actually possible to use the global temporary table within a stored procedure after it has been created inside a transaction that loads it from an openquery statement and I am just doing it wrong?
Although I am not entirely sure why the code above works when outside the context of a stored procedure, I did determine that embedding all references to the global temporary table within the committed transaction allowed the stored procedure to work. So something like the following:
use db_name
go
create procedure dbo.proc_name
#sp_date date = NULL
as
if isnull(#sp_date,'') = ''
begin
select #sp_date = getdate();
end
if object_id('tempdb..##global_tmp_tbl') is not null drop table ##global_tmp_tbl;
begin transaction
set xact_abort on
declare #query varchar(250), #exec_stmnt varchar(500);
set #query = 'exec remote_db.dbo.remote_sp' + ' ''''' + cast(#sp_date as varchar(10)) + ''''' ';
set #query = '''' + #query + '''';
set #exec_stmnt = 'select * into ##global_tmp_tbl from openquery(LS_RMT,' + #query + ')';
exec (#exec_stmnt);
if object_id('tempdb..#local_tmp_tbl') is not null drop table #local_tmp_tbl;
select * into #local_tmp_tbl from ##global_tmp_tbl;
commit transaction
go

cursor not adding data, adding only when executing separately

I have stored procedure & cursor loop which I am using to add data in main table issue is I am adding data from csv file to temp table and from temp table to main table
alter PROCEDURE [dbo].[CreateHub]
#HubName varchar(100)
AS
INSERT INTO dbo.HUB1
(HUB_NAME)
SELECT #HubName
WHERE (NOT EXISTS
(SELECT ID_HUB, HUB_NAME
FROM dbo.HUB1
WHERE (HUB1.hub_name = #HubName)))
SELECT ID_HUB AS newHubId
FROM dbo.HUB1
WHERE (hub1.hub_name = #HubName)
GO
Once this is done, there is another code which is doing bulk insert from csv file and running cursor loop for adding data in main table
bulk insert [dbo].[HUB_temp]
from 'C:\POPAD-DAT\HUB1.csv'
with (fieldterminator = ',', rowterminator = '\n')
go
DECLARE #sSQL AS nVARCHAR(100)
DECLARE #ItemsFromCSV AS nvarchar(200)
DECLARE sql_cursor_hub CURSOR
FOR SELECT HUB_NAME FROM HUB_temp
OPEN sql_cursor_hub
FETCH NEXT FROM sql_cursor_hub
INTO #ItemsFromCSV -- Multiple variables for multiple CSV columns will be required
WHILE ##FETCH_STATUS = 0
BEGIN
set #sSQL = 'EXEC [dbo].[CreateHub] ' + #ItemsFromCSV -- AND OTHER Parameters
print #sSQl
EXECUTE sp_executesql #sSQL
FETCH NEXT FROM sql_cursor_hub
END
CLOSE sql_cursor_hub;
DEALLOCATE sql_cursor_hub;
Running cursor is not adding data its showing like same id and showing different u=hubname but not inserting data
While if I am running separately executing SP it is adding like this
EXEC [dbo].[CreateHub] 'SGGSP30'
EXEC [dbo].[CreateHub] 'USGSP20'
can you please help where exactly iam going wrong
You forgot to do INTO in the second fetch
WHILE ##FETCH_STATUS = 0
BEGIN
set #sSQL = 'EXEC [dbo].[CreateHub] ' + #ItemsFromCSV -- AND OTHER Parameters
print #sSQl
EXECUTE sp_executesql #sSQL
-- This is changed
FETCH NEXT FROM sql_cursor_hub INTO #ItemsFromCSV
END
You should also take care of your parameter declarations, #ItemsFromCSV is varchar(200) but the stored proc parameter is only varchar(100) and #sSQL is only 100 in size but you add #ItemsFromCSV to it.

Pass current dbName and execute procedure

See this...
SELECT *
INTO #WL_Klijenti
FROM OPENROWSET ('SQLOLEDB','Server=(local);TRUSTED_CONNECTION=YES;','SET
FMTONLY OFF; SET NOCOUNT ON; EXEC
WBANKA_KBBL2.dbo.sp_kbbl_WachLista_Priprema ''2017.09.30'', ''2017.09.30'',
0')
AS tbl
The part : EXEC WBANKA_KBBL2 should be replaced with the current db used, so that the user does not have to specify it manualy.
I had an idea of a procedure with an output parameter which will return current database and store it in a variable and this was my try:
SP Looks like this:
CREATE procedure dbo.getCurrentDB
(
#dbName varchar(30) OUTPUT
)
AS
BEGIN
set #dbName = (select db_name())
--select #dbName
END
go
How can I pass my current db used to the procedure call, instead of specifying it manually?
EDIT:
When I run it like this I receive A SELECT statement that assigns a value to a variable must not be combined with data-retrieval operations
declare #dbName varchar(30)
exec getCurrentDB #dbName output
DECLARE #ORS varchar(MAX);
SELECT #ORS = 'Server=(local);TRUSTED_CONNECTION=YES;','SET
FMTONLY OFF; SET NOCOUNT ON; exec
select ' + QUOTENAME([name] + '.dbo.sp_kbbl_WachLista_Priprema
''2017.09.30'', ''2017.09.30'',
0')
FROM sys.databases
WHERE [name] = #dbName
SELECT *
INTO #WL_Klijenti
FROM OPENROWSET ('SQLOLEDB',#ORS)
AS tbl;

SQL - define a variable that points to a stored procedure

I have several queries that drop the proc if it exists, recreate it, and set permissions on it, similar to this:
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
if exists (select *
from dbo.sysobjects
where id = object_id(N'[dbo].[spMyStoredProcedureName]')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure [dbo].[spMyStoredProcedureName]
GO
CREATE PROCEDURE [dbo].[spMyStoredProcedureName]
AS
/* more proc stuff */
GRANT EXECUTE ON [dbo].[spMyStoredProcedureName]
TO Some_User_Group
My question is: is there some way to define a variable for [dbo].[spMyStoredProcedureName] so that I can declare it once and refer to the variable? I need to use the variable two ways - once as a string in the select statement and the rest of the time as a reference to the stored proc I'm creating/dropping.
I'm assuming your goal is to replace your "several scripts" with just one script that can be used by changing the value of the variable that holds the name of the stored procedure.
If so you could try a dynamic approach:
Declare #spMyStoredProcedureName nvarchar(255);
--either use a cursor or whatever means to populate the variable.
--for this example I will simply set it
SET #spMyStoredProcedureName = '[dbo].[spMyStoredProcedureName]';
DECLARE #sql nvarchar(max);
SET #sql='
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_NULLS ON
GO
if exists (select *
from dbo.sysobjects
where id = object_id(N''#spMyStoredProcedureName'')
and OBJECTPROPERTY(id, N'IsProcedure') = 1)
drop procedure #spMyStoredProcedureName
GO
CREATE PROCEDURE #spMyStoredProcedureName
AS
/* more proc stuff */
GRANT EXECUTE ON #spMyStoredProcedureName
TO Some_User_Group
';
SET #sql = REPLACE(#sql, '#spMyStoredProcedureName', #spMyStoredProcedureName)
EXECUTE(#sql)
Note that you'll need to escape all the single quotes in your stored proc code when doing this. Also I'm not so sure you can use the GO command in dynamic sql. If not, you'd need to do two separate dynamic statements per stored proc.
Use dynamic sql for your intended ddl statement. A sample implementation below.
-- Declare variable to store the procedure name
Declare #proc varchar(100) = 'myProc';
-- Construct the ddl statement
DECLARE #script nvarChar(MAX);
SET #script =
'
if exists (select *
from dbo.sysobjects
where id = object_id(N'''+ #proc + ''')
and OBJECTPROPERTY(id, N''IsProcedure'') = 1)
drop procedure ' + #proc + ';
GO
CREATE PROCEDURE ' + #proc + '
AS
print ''Hello World!'';
/* more proc stuff */
GO
GRANT EXECUTE ON ' + #proc + '
TO Some_User_Group;
'
SET #script = 'EXEC (''' + REPLACE(REPLACE(#script, '''', ''''''),
'GO', '''); EXEC(''') + ''');'
-- Run the dynamic ddl
EXEC (#script);
-- Test
exec myproc;

Resources