I want to use the output from a query as Dynamic SQL - sql-server

My Dynamic SQL queries have been placed inside a table. I want to read these from the table (in SQL server), do a parameter substitution, then execute the dynamic query.
i.e. Column GetFieldServerSQL contains the following:
SELECT top 1 Tenancy.LeadName
FROM Tenancy
RIGHT OUTER JOIN Property ON Tenancy.KeyProperty = Property.KeyProperty
WHERE (Tenancy.EndDate IS NULL) and Property.KeyProperty = #PropertyID
This is what I have tried:
declare #sql nvarchar(1000)
declare #sql2 nvarchar(1000)
declare #res nvarchar(1000)
declare #result nvarchar(1000)
set #sql = 'SELECT [GetFieldServerSQL]
FROM [SVSCentral].[dbo].[SVSSurvey_ExternalField] where ID=5'
exec #res = sys.sp_executesql #sql
print #res
This returns my query in the Results window, but I want it as a variable. #res only contains a 0 (for success)
Once I have it as a variable, I want to do a substitution. Something like:
set #sql2 = REPLACE(#result,'#propertyID','1003443')
(supposing #result is where my results is stored)
And then execute it:
exec (#sql2)

Instead of doing this:
exec #res = sys.sp_executesql #sql
You need to insert the results into a table, then select from that table, like this:
DECLARE #resTable TABLE (res nvarchar(1000))
INSERT INTO #resTable (res)
exec (#sql)
SELECT #res=res from #resTable
print #res

Related

How to execute Dynamically created query in sql server

I have written a stored procedure Where I have written a query to get userid. There is a separate database for every userid. So I am trying to run a select query based on this userid obtained from my previous select query in a loop.
And I am trying to assign the columns in this select query to variables declared and use them further. But I am not understanding how to assign these to variables as I am getting errors
USE DATABASE1
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [User].[update_client_details]
AS
DECLARE
#clientdata CURSOR,
#clientid INT,
#SQL VARCHAR(2000),
#uid INT
#isactive INT,
#createdDate Date
BEGIN
SET #clientdata = CURSOR FOR
SELECT clientuserid FROM User.queen_client
OPEN #clientdata
FETCH NEXT
FROM #clientdata INTO #clientid
WHILE ##FETCH_STATUS = 0
BEGIN
SET #SQL = N'SELECT #uid=userid, #isactive=isactive, #createdDate=createddate FROM ['+CAST(#clientid AS NVARCHAR(20))+'].User.queen_user';
EXEC (#SQL)
IF(#isactive = 1)
BEGIN
//do someting//
END
END
CLOSE #clientdata
DEALLOCATE #clientdata
END
if the execute the store procedure it is getting executed and not stopping. If I force stop the execution then I am getting the error as "must declare the scalar variable "uid""
Query Which I tried
EXEC sys.sp_executesql N'SELECT #uid=userid, #isactive=isactive, #createdDate=createddate FROM ' +QUOTENAME(#clientid)+'.QueenBase.queen_user', N'#clienid int, #uid int OUTPUT, #createDate date OUTPUT';
Variables only persist and exist within the scope that they are declared in. Therefore both the following batches will fail:
DECLARE #I int = 1;
EXEC (N'SELECT #i;');
GO
EXEC (N'DECLARE #I int = 1;');
SELECT #i;
When using dynamic SQL, don't use EXEC(#SQL);, use sp_executesql. Then you can parametrise the statement. For example:
DECLARE #I int = 1;
EXEC sys.sp_executesql N'SELECT #i;', N'#i int', #i;
This returns 1. If you need to return a value to the outer SQL, as a parameter, you need to use OUTPUT parameters:
DECLARE #I int = 10;
DECLARE #O int;
EXEC sys.sp_executesql N'SELECT #O = #I / 2;', N'#I int, #O int OUTPUT', #I, #O OUTPUT;
SELECT #O;
This assigns the value 5 to the variable #O (which is then selected).
Also, don't use N'...[' + #SomeVariable + N'] ...' to inject dynamic values, it's not injection safe. Use QUOTENAME: N'...' + QUOTENAME(#SomeVariable) + N'...'
Additional note. The fact that you need to do something like N'FROM ['+CAST(#clientid AS NVARCHAR(20))+'].User.queen_user' suggests a severe design flaw, but that's a different topic.
If you do fancy additional reading, I cover a lot of considerations you need to take into account in my article Dos and Don'ts of Dynamic SQL.
For your attempt, it's not working as you use an expression for the first parameter (not a literal or variable) and then don't pass any of the parameters you define:
DECLARE #SQL nvarchar(MAX) = N'SELECT #uid=userid, #isactive=isactive, #createdDate=createddate FROM ' +QUOTENAME(#clientid)+'.QueenBase.queen_user;';
EXEC sys.sp_executesql #SQL, N'#isactive int OUTPUT, #uid int OUTPUT, #createDate date OUTPUT', #isactive OUTPUT, #uid OUTPUT, #createDate OUTPUT;

How to store the result of exec in a variable

How can I store the result of exec in a variable? The output is JSON.
My SQL query is complex and dynamically generated, so I have to set a variable and execute it.
create PROCEDURE dbo.RetrievePerfCounterData #jsonOutput NVARCHAR(MAX) OUTPUT
AS
BEGIN
declare #sql NVARCHAR(MAX)
SET #sql = ' SELECT TOP (1) getdate() AS ''dateTime'' ,suser_sname()AS ''user'' FOR JSON PATH '
exec (#sql)
END
Here's my attempt at storing the data in a variable:
DECLARE #json AS NVARCHAR(MAX)
EXEC dbo.RetrievePerfCounterData #jsonOutput = #json OUTPUT
DECLARE #myVar VARCHAR(MAX)
DECLARE #SQL NVARCHAR(MAX)
IF OBJECT_ID('tempdb..#t1') IS NOT NULL DROP TABLE #t1
CREATE TABLE #t1 (col1 INT, col2 INT)
INSERT INTO #t1
SELECT 1, 1
UNION
SELECT 1, 2
SET #SQL = 'SET #myVar = (SELECT * FROM #t1 AS T FOR JSON AUTO);'
EXEC sp_executesql #SQL, N'#myVar VARCHAR(MAX) OUT', #myVar OUT
SELECT #myVar
You need to use a subquery:
SET #json = (SELECT TOP (1) getdate() AS [dateTime],suser_sname()AS [user] FOR JSON PATH);

SQL server stored procedure insert with dynamic exec

Am unable to insert record when given all the column names in insert
Below is the SP
ALTER PROCEDURE [dbo].[test]
#tab_name nvarchar(50),
#tab_id int,
#tab_n nvarchar(50),
#tab_q int
as
Begin
declare #sql as nvarchar(50);
declare #counts as int;
select #sql='select #cnt=count(*) from '+#tab_name+' where id='+cast(#tab_id as varchar)+';'
exec sp_executesql #sql,N'#cnt int output', #cnt=#counts output
select #counts as counts
if #counts=1
begin
declare #sql1 as nvarchar(50);
select #sql1='update '+#tab_name+' set quantity='+cast(#tab_q as varchar)+' where id='+cast(#tab_id as varchar)+';'
exec sp_executesql #sql1
end
else
begin
declare #sql2 as nvarchar(50);
set #sql2='insert into '+#tab_name+' (id,name,quantity) values ('+CAST(#tab_id as varchar)+','''+#tab_n+''''
set #sql2+=','+CAST(#tab_q as varchar)+');'
select #sql2
exec sp_executesql #sql2
end
End
"
command: exec dbo.test #tab_name='inventory',#tab_id=4,#tab_n='chiku',#tab_q=123
record gets inserted when column names are removed but does not work with column names during insert.
Please help.
Thanks
It is better to use A nvarchar(max) for dynamic queries with parameters.
Because u never know how long the string can be. unless you know the max lenght of the string.
A dba also told me to use N' as prefix before the string to denote Unicode string literals.
Increase #sql variables size like below:
declare #sql as nvarchar(max);
....
declare #sql1 as nvarchar(max);
...
declare #sql2 as nvarchar(max);

Select data from another database in storedprocedure

I try to select data from a table of another database in my storedprocedure and the name of the other database is given by parameter. I get an error message:
'Invalid object name [#DbName].dbo.Setup'.
CREATE PROCEDURE [dbo].[spUndeliverableOrders]
#DbName sysname
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Sortfield nvarchar(50)
SET #Sortfield = (SELECT COALESCE(Text, 'ToDoListeDatum') AS SortField FROM [#DbName].dbo.Setup WHERE label like 'ComboBoxSetupBatchReihenfolge')
END
GO
Can someone help me to solve this problem?
Like #ThomasSchremser said:
DECLARE #sqlquery varchar(1000)
SET #sqlquery = '(SELECT COALESCE(Text, ''ToDoListeDatum'') AS SortField FROM ['+#DbName+'].dbo.Setup WHERE label like ''ComboBoxSetupBatchReihenfolge'')'
It is upto you to decide weither you what to populate a table/variable with the results.
Either use:
insert into #table(column) exec #sqlquery...
or
sp_executesql #sqlquery...
You need to use dynamic query as below
CREATE PROCEDURE [dbo].[spUndeliverableOrders]
#DbName sysname
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #Str varchar(max)
CREATE TABLE #Result(Res VARCHAR(MAX))
SET #Str = 'insert into #Result SELECT TOP 1 COALESCE(Text, ''ToDoListeDatum'') AS SortField FROM ['+#DbName+'].dbo.Setup WHERE label like ''ComboBoxSetupBatchReihenfolge'''
exec(#str)
select Res from #Result
END
Modified per your script:
DECLARE #Str varchar(max)
CREATE TABLE #Result(Res VARCHAR(MAX))
SET #Str = ' SELECT TOP 1 COALESCE(Text, ''ToDoListeDatum'') AS SortField FROM ['+#DbName+'].dbo.Setup WHERE label like ''ComboBoxSetupBatchReihenfolge'''
insert into #Result
EXEC(#Str)

How to use variable as table name in select into statement?

I have a problem with treating table name as variable as I need to put the results to different table each month automatically (without using any advanced procedures to make this query dynamic). Can somebody help me to modify this code and make it work?
declare #exp_dte as date;
set #exp_dte='2015-12-31';
print (#exp_dte);
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
print (#tab_mth);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
print (#tab_name);
IF OBJECT_ID (N'#tab_name', N'U') IS NOT NULL
begin
drop table #tab_name
end
select distinct
*
into #tab_name
from table_x
You have to use dynamic SQL to set name at runtime:
DECLARE #exp_dte DATE = '2015-12-31';
DECLARE #tab_name SYSNAME = '[dbo].' + QUOTENAME('BIK_' + FORMAT(#exp_dte, 'yyyyMM'));
IF OBJECT_ID (#tab_name, N'U') IS NOT NULL
BEGIN
EXEC('DROP TABLE' + #tab_name);
END
DECLARE #sql NVARCHAR(MAX) = N'SELECT DISTINCT *
INTO #tab_name
FROM table_x';
SET #sql = REPLACE(#sql, '#tab_name', #tab_name);
EXEC [dbo].[sp_executesql] #sql;
LiveDemo
Remarks:
Try to be more conscise
You could use FORMAT to get yyyyMM (SQL Server 2012+)
Always QUOTENAME generated identifiers to avoid SQL Injection attacks
I strongly recommend to read The Curse and Blessings of Dynamic SQL especially CREATE TABLE #tbl.
use dynamic sql ,you cant user table names as variables
declare #exp_dte as date;
set #exp_dte='2015-12-31';
declare #tab_mth as nvarchar(max);
set #tab_mth=year(#exp_dte)*100+month(#exp_dte);
declare #tab_name as nvarchar(max)
set #tab_name='mis_anl.dbo.BIK_' + #tab_mth
declare #sql1 nvarchar(max)
set #sql1='drop table '+#tab_name;
IF exists(select 1 from information_schema.tables where table_name=#tab_name)
begin
exec(#sql1);
end
declare #sql nvarchar(max)
set #sql='
select distinct
*
into '+#tab_name+'
from table_x'
exec (#sql)

Resources