Returning Variables from Linked Servers - sql-server

I need to write a stored procedure which will return the value of a parameter, acquired from a Linked Server.
I have tried declaring the variable both inside and outside of the dynamic sql but it fails with a must declare variable error.
declare #srvr nvarchar(100)
declare #dbn nvarchar(50)
set #srvr = 'ServerName'
set #dbn = 'DatabaseName'
Declare #sql nvarchar(max)
set #sql = 'declare #param nvarchar(50) set #param = (Select X from [' + #srvr + '].[' + #dbn + '].[TableName])'
exec (#sql)
print #param
This will form the framework for multiple procedures which reside in a central database, these procedures will be called when restoring other databases into the environment forming part of 'prep script' of sorts
Any ideas please?
Thanks very much

You need to declare the variable twice. Once for the inner context, once for the outer context. They need not use the same names inside and out:
declare #srvr nvarchar(100)
declare #dbn nvarchar(50)
set #srvr = N'ServerName'
set #dbn = N'DatabaseName'
Declare #sql nvarchar(max)
declare #parms nvarchar(max)
set #sql = N'set #param = (Select X from [' + #srvr + '].[' + #dbn + '].[TableName])'
set #parms = N'#param nvarchar(50) output'
declare #param2 nvarchar(50)
exec sp_executesql #sql,#parms,#param = #param2 output
print #param2

Related

Writing dynamic SQL in SQL Server 2016 throwing error

This is my stored procedure in SQL Server 2016:
CREATE PROCEDURE [USA_PHILIPS].[usp_stock]
#VCM INT,
#ID VARCHAR,
#SCHEMA_NAME VARCHAR(50)
AS
BEGIN
SET NOCOUNT ON;
DROP TABLE IF EXISTS [USA_PHILIPS].[stock]
SELECT STOCKNUMBER,STOCKBOOKS
INTO [USA_PHILIPS].[stock]
FROM [USA_PHILIPS].[DMARTSTOCK]
WHERE VCM = #VCM
AND ID = #ID
END
How can I pass schema name as a parameter #SCHEMA_NAME?
And execute these statements as dynamic SQL:
DROP TABLE IF EXISTS [USA_PHILIPS].[stock]
Please help.
I would personally do it this way, injecting the value directing into the dynamic query. I also fix some of your data types:
CREATE PROCEDURE [USA_PHILIPS].[usp_stock] #VCM int,
#ID varchar(25), --Always define your varchar lengths
#SCHEMA_NAME sysname --Correct data type for object names
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL nvarchar(MAX),
#CRLF nchar(2) = NCHAR(13) + NCHAR(10)
SET #SQL = N'DROP TABLE IF EXISTS ' + QUOTENAME(#SCHEMA_NAME) + N'.[stock];' + #CRLF + #CRLF +
N'SELECT STOCKNUMBER,STOCKBOOKS' + #CRLF +
N'INTO ' + QUOTEMANE(#SCHEMA_NAME) + N'.[stock]' + #CRLF +
N'FROM [USA_PHILIPS].[DMARTSTOCK]' + #CRLF +
N'WHERE VCM=#VCM' + #CRLF +
N' AND ID = #ID;';
EXEC sys.sp_executesql #SQL, N'#VCM int, #ID varchar(25)', #VCM, #ID;
END;
All the code needs to be dynamic if an identifier is dynamic -- and you have to munge query strings:
CREATE PROCEDURE [USA_PHILIPS].[usp_stock] (
#VCM INT,
#ID VARCHAR(255),
#SCHEMA_NAME VARCHAR(50)
) AS
BEGIN
DECLARE #sql = NVARCHAR(MAX);
SET #sql = 'DROP TABLE IF EXISTS [SCHEMA].[stock]';
SET #sql = REPLACE(#sql, '[SCHEMA]', QUOTENAME(#SCHEMA_NAME));
EXEC sp_executeSQL #sql;
SET #sql = '
SELECT STOCKNUMBER, STOCKBOOKS
Into [SCHEMA].[stock]
from [USA_PHILIPS].[DMARTSTOCK]
WHERE VCM=#VCM AND ID = #ID';
SET #sql = REPLACE(#sql, '[SCHEMA]', QUOTENAME(#SCHEMA_NAME));
EXEC sp_executesql #sql,
N'#vcm INT, #id VARCHAR(255)',
#vcm=#vcm, #id=#id;
END;
Note some important changes to the query:
#ID has a length as an argument. This is important because the default varies by context and it might (well probably isn't) long enough for what you want.
I assume that you want the same table referenced in the DELETE as the INTO.
Pass the constant values as parameters.

Execute dynamic query that executes another stored procedure

I have a query like this:
DECLARE #TaskId UNIQUEIDENTIFIER
DECLARE #TaskName VARCHAR(255) = 'MasterSet'
DECLARE #sql NVARCHAR(MAX)
DECLARE #StartingDateTask DATETIME2 = (SELECT TOP 1 [Date]
FROM [TaskStatusAudit]
WHERE [TaskId] = 'A1FDFC16-904D-4560-B19D-5E7D4FEB1C2B'
AND [TaskStatusName] = 'IN-PROGRESS')
DECLARE #EndingDateTask DATETIME2 = (SELECT TOP 1 [Date]
FROM [TaskStatusAudit]
WHERE [TaskId] = 'A1FDFC16-904D-4560-B19D-5E7D4FEB1C2B'
AND [TaskStatusName] = 'COMPLETED')
SET #sql = N'SELECT dbo.TotalMinuteRange(#StartingDateTask,#EndingDateTask) as ' + quotename(#TaskName) + N''
EXEC sp_executesql #sql
Problem is when I execute it I get this error:
Must declare the scalar variable "#StartingDateTask".
Any ideas why I getting that if I declare my variable correctly? Regards
When executing sp_executesql you need to declare and pass the variables to sp_executesql something like..
SET #sql = N'SELECT dbo.TotalMinuteRange(#StartingDateTask,#EndingDateTask) as '
+ quotename(#TaskName) + N''
exec sp_executesql #sql
, N'#StartingDateTask DATETIME2 , #EndingDateTask DATETIME2'
, #StartingDateTask
, #EndingDateTask
Second parameter is the variable declaration parameter followed by the actual variables separately.
You can also do like taking a parameters variable and assign it.
declare #params nvarchar(100)
set #params='#StartingDateTask DATETIME2,#EndingDateTask DATETIME2'
SET #sql = N'SELECT dbo.TotalMinuteRange(#StartingDateTask,#EndingDateTask) as '
+ quotename(#TaskName) + N''
exec sp_executesql #sql
, #params
, #StartingDateTask
, #EndingDateTask

SQL server 2012 - return variable value from a dynamic script

I'm trying to run a dynamic script to then return the variable so I can pass in to the rest of my script. I've a couple of ways with the help of Google, but I think I still haven't got the syntax correct, therefore getting error or null value returned.
Can someone please advise where I've gone wrong.
For example:
To return the value for variable #table_name
ASIA is the database and this is set as variable which is appended to the table name that is retrieved from the table and T5148 is the id from the table to turn the table name as is so a variable. I have set this a variables as this script sits when other scripts which loops
Thank you
declare #table_name nvarchar(50)
declare #database nvarchar(50)
declare #id nvarchar(50)
declare #sql nvarchar(max)
set #database = 'ASIA'
set #id = 'T5178'
set #sql = N'SELECT #table_name = ''#database''+table_name
FROM ''#database''+tables (NOLOCK)
WHERE id = ''#id'''
exec sp_executesql #sql, N'#table_name nvarchar(50) output', #table_name output
select #TRAN_TABLE
If I am not wrong, this is what you need :
DECLARE #table_name NVARCHAR(50)
DECLARE #database NVARCHAR(50)
DECLARE #id NVARCHAR(50)
DECLARE #sql NVARCHAR(MAX)
SET #database = 'ASIA'
SET #id = 'T5178'
SET #sql = N'SELECT #table_name = table_name
FROM ' + #database+'.dbo.tables (NOLOCK)
WHERE id = #id'
EXEC SP_EXECUTESQL #sql, N'#id nvarchar(50),#table_name nvarchar(50) output',
#id = #id, #table_name = #table_name OUTPUT
SET #table_name = #database + #table_name
Note : change dbo as you schema name.

Stored procedure with table name as parameter amongst others

I have tried to update a stored procedure which worked fine without the need to use sp_executesql. I now want to have the table name as a parameter as I have a number of tables with the same structure and don't want to create new stored procedures for each of them.
The problem I have is that this version seems to require all the parameters, while the previous one accepted any number of parameters. For instance, if I remove all the WHERE parameters and just have the #TableName parameter it works fine. I;ve tried looking for an example, but I cannot find anything like this. All the examples of parsing the table name have only that parameter.
CREATE PROCEDURE cafgTenantNamesTEST2
#TableName sysname,
#Square nvarchar(100) = null,
#Location nvarchar(100) = null,
#Name nvarchar(100) = null,
#NormalizedName nvarchar(100) = null,
#SharedLand int = 0,
#FieldNumber int = 0,
#Description nvarchar(255) = null,
#Dwelling nvarchar(100) = null
AS
BEGIN
DECLARE #sql AS NVARCHAR(MAX)
SET #sql = 'SELECT * FROM [' + #TableName + ']' +
'WHERE ([Square] LIKE ''' + #Square + ''' OR ''' + #Square + ''' IS NULL)' +
'AND ([Location] = ''' + #Location + ''' OR ''' + #Location + ''' IS NULL)' +
...
...
--PRINT #sql
EXEC sp_executesql #sql
END
Suggestions please.
Suggestion 1:
Use QUOTENAME() to handle proper escaping of the table name.
Suggestion 2: You are inserting the value of the parameter into #sql. Don't do that. Instead you should use pameterized the sql.
Suggestion 3: Eliminate the OR logic by conditionally building the query's WHERE clause.
CREATE PROCEDURE cafgTenantNamesTEST2
#TableName sysname,
#Square nvarchar(100) = null,
#Location nvarchar(100) = null,
#Name nvarchar(100) = null,
#NormalizedName nvarchar(100) = null,
#SharedLand int = 0,
#FieldNumber int = 0,
#Description nvarchar(255) = null,
#Dwelling nvarchar(100) = null
AS
BEGIN
DECLARE #sql AS NVARCHAR(MAX)
SET #sql = N'SELECT * FROM ' + QUOTENAME(#TableName ) +
' WHERE 1=1 '
IF #Square IS NOT NULL
SET #sql = #sql + ' AND ([Square] LIKE #Square )' -- still patameterized
IF #Location IS NOT NULL
SET #sql = #sql + N' AND ([Location] = #Loc )'
...
...
--PRINT #sql
EXEC sp_executesql #sql, N'#Square nvarchar(100), #Loc nvarchar(100)...', #square=#square, #loc=#location -- the param names can be the same or different, sp_executesql has it's own scope.
END
Sp_executesql can execute parameterized sql in addition to plain sql. It is the underlying system stored procedure that is used by client libraries to execute parameterized code. For example, System.Data.SqlClient.SqlCommand will call sp_executesql if you have added any parameters. It is atypical in that it accepts a variable number of parameters. The msdn docs on sp_executesql provide some good information, but isn't clear. Capturing activity in SQL profiler is the easiest way to see sp_executesql in action.

Can I specify a database name dynamically in a trigger?

I need to get data from a table in a database who's database name will be determined as a variable during a trigger. I then, knowing this variable need to get a seqno from a table in the determined database for a item which was also determined as a variable during a trigger.
I am trying this route as I assume I need to build the SQL statement before I set it to a variable.
This is not working and I need to know the best way on how I can do this:
DECLARE #SU_SEQNO INTEGER, #SU_NAME VARCHAR(50), #SU_OWNER VARCHAR(15), #SUD_SEQNO INTEGER, #SQL NVARCHAR(500)
SET #SU_OWNER = 'XXX'
SET #SU_NAME = '1ABC234'
SET #SQL ='SELECT #SUD_SEQNO=SEQNO FROM ' + (#SU_OWNER) + '.SU_MAIN
WHERE UNITNAME= ' + #SU_NAME
SET #SUD_SEQNO = (EXECUTE (#SQL))
Thanks alot for any help with this
From: Get result from dynamic SQL in stored procedure
SET #SQL = N'SELECT DISTINCT #FiscalYear = FiscalYear FROM ' + #DataSource;
EXEC sp_executesql #SQL, N'#FiscalYear INT OUTPUT', #FiscalYear OUTPUT;
PRINT #FiscalYear;
I'd re-engineer to use the sp_executesql method as shown above. That should do the trick.
I have amended the code, and it works
declare #su_owner varchar(15) = 'DBTEST'
declare #SU_SEQNO INTEGER=1, #SUD_SEQNO INTEGER=0, #SQL NVARCHAR(500)
DECLARE #ParmDefinition NVARCHAR(500), #SU_NAME_INPUT VARCHAR(50)='SU123'
SET #SU_NAME_INPUT = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SU_NAME = (SELECT UNITNAME FROM SU_MAIN WHERE SEQNO=#SU_SEQNO)
SET #SQL = N'SELECT #sud_seqnoOUT=MAX(SEQNO) FROM ' + quotename(#su_owner) + '.[dbo].[SU_MAIN] WHERE UNITNAME]=#SU_NAME_INPUT' ;
SET #ParmDefinition = N'#SU_NAME_INPUT VARCHAR(50),#sud_seqnoOUT INT OUTPUT'
EXEC sp_executesql #SQL,#ParmDefinition,#SU_NAME_INPUT = #SU_NAME,
#sud_seqnoOUT = #SUD_SEQNO OUTPUT

Resources