I'm struggling with a dynamic query in tSQL to be used with Excel ODBC.
SQL Server 2016 via ODBC Driver 11 for SQL Server
I found this article but it only uses the table name stored in a parameter, I'd need the actual table to be within parameter: Simple dynamic TSQL query syntax
declare #t table(value1 int, value2 nvarchar(1024))
insert #t SELECT 1 as value1, 'test' as value2
declare #where nvarchar(max)
declare #query nvarchar(max)
declare #sql nvarchar(max)
set #where = ' WHERE value1 = 1'
set #query = 'Select * from #t'
set #sql = #query + #where
EXEC(#sql)
This results in the error message Must declare the table variable "#t"
Unfortunately I can't use temporary tables as the connector doesn't support temp tables.
My original query is far more complex and contains 6 different parameters all being injected at different points into the query and 2 table-parameters that hold temp results
Thanks in advance
You just need to declare your table as part of your query. The table is declared and recognized in that scope:
declare #t table(value1 int, value2 nvarchar(1024))
insert #t select 1 as value1, 'test' as value2
declare #where nvarchar(max)
declare #query nvarchar(max)
declare #sql nvarchar(max)
set #where = ' where value1 = 1'
set #query = 'declare #t table(value1 int, value2 nvarchar(1024))
insert #t select 1 as value1, ''test'' as value2
select * from #t'
set #sql = #query + #where
exec(#sql)
Result:
Related
I am querying a linked server:
DECLARE #result nvarchar(max);
SET #Sql = N'
SELECT *
FROM OPENQUERY(DATABASE_' + UPPER(#Environment) + ', ''
Complex Query against the linked server...
'');'
EXECUTE sp_executesql #sql, #result OUTPUT
Before inserting the results into the correct table I have to filter some rows of the results. I can't filter them in the original query because the results must be matched against values in the target table.
Something like:
INSERT INTO targetTable
SELECT * FROM #result AS r
WHERE r.Col1 NOT IN (SELECT Col1 FROM targetTable)
AND r.Col2 NOT IN (SELECT Col2 FROM targetTable)
I can't use the #results variable to query from because it's no table.
How can I do this?
Create a table variable or temporary table. Insert the records from your openquery. Here is an example with a table variable.
declare #tableVar as table (
field1 varchar(10)
, field2 int
etc
);
declare #sql as nvarchar(max);
set #sql = '
SELECT value1, value2, etc
FROM OPENQUERY(DATABASE_' + UPPER(#Environment) + ', ''
Complex Query against the linked server...
'');
insert into #tableVar
EXECUTE sp_executesql #sql
';
Solved my problem with a hint form here
Code:
DECLARE #linkedServer varchar(50) = 'linkedServerName';
DECLARE #Sql NVARCHAR(MAX);
SET #Sql = N'
INSERT INTO [DatabaseName].[Schema].[Table]
SELECT
t1.Column1
FROM OPENQUERY(' + #linkedServer + ',
''
complex query here
) AS t1
WHERE t1.Column1 NOT IN (SELECT Column1 FROM [DatabaseName].[Schema].[Table])
;
';
EXECUTE sp_executesql #sql;
Works like a charm.
Kind Regards
I have a procedure , in which i am receiving a parameter column name and creating the dynamic query by substituting column name.
when i am directly running this dynamic query its working fine.
declare #a datetime,
#b varchar(50) ='CREATED_DATE',--column name
#query varchar(500);
select #a= CONVERT(datetime,LAST_RUN_PROC,121) from TEST_TABLE_MASTER
exec( 'select '+#b+' from TEST1 where '+#b+' = '+''''+#a+'''' )
But when i am storing query in a variable and then executing,its showing error.
Below code showing error
declare #a datetime,
#b varchar(50) ='CREATED_DATE',--column name
#query varchar(500);
select #a= CONVERT(datetime,LAST_RUN_PROC,121) from TEST_TABLE_MASTER
SET #query= 'select '+#b+' from TEST1 where '+#b+' = '+''''+#a+'''' --this line showing error Conversion failed when converting date and/or time from character string.
exec (#query)
I got stuck here.please help
Concatenating SQL string is not the best idea, because of multiple '''' needed. It is error-prone and hard to debug.
Use correct types (table name, column name) - SYSNAME, query -NVARCHAR(MAX).
You can use REPLACE placeholder to fill values or pass them as parameter to EXEC dbo.sp_executesql.
Always quote table/column names.
SELECT #a= CONVERT(datetime, LAST_RUN_PROC,121) FROM TEST_TABLE_MASTER; will set #a last read value from table, you should add TOP 1 and ORDER BY.
Code:
DECLARE #a DATETIME,
#b SYSNAME ='CREATED_DATE',
#query NVARCHAR(MAX);
SELECT #a= CONVERT(datetime, LAST_RUN_PROC,121) FROM TEST_TABLE_MASTER;
SET #query =
N'SELECT <col_name>
FROM TEST1
WHERE <col_name> = ''<col_value>'';';
SET #query = REPLACE(#query, '<col_name>', QUOTENAME(#b));
SET #query = REPLACE(#query, '<col_value>', #a);
--SELECT #query;
EXEC [dbo].[sp_executesql]
#query;
SqlFiddleDemo
Recommended version with parameter passing and dbo.sp_executesql instead of EXEC:
DECLARE #a DATETIME,
#b SYSNAME ='CREATED_DATE',
#query NVARCHAR(MAX);
SELECT #a= LAST_RUN_PROC FROM TEST_TABLE_MASTER;
SET #query =
N'SELECT <col_name>
FROM TEST1
WHERE <col_name> = #a;';
SET #query = REPLACE(#query, '<col_name>', QUOTENAME(#b));
EXEC [dbo].[sp_executesql]
#query
,N'#a DATETIME'
,#a;
SqlFiddleDemo2
Warning:
Using Dynamic-SQL is great resposibility. If you don't understand it, don't use Dynamic-SQL at all.
EDIT:
I've managed to run your example, but I strongly recommend to use one of the solution above:
SET #query= 'select '+#b+' from TEST1 where '+#b+' = '+''''+CONVERT(varchar(19),#a, 121)+''''
SqlFiddleDemo3
Is this possible to get multiple columns value when we have column name as string
Like if i have a table Test and i have columns FirstName , LastName , Address .
Now what i want to get value of all three columns but i want to make this dynamic so that i just pass string column name i get values for that columns
Example
Select
(select column_name from metadata )
from source table
Pass the column names as parameters
DECLARE #COLS NVARCHAR(MAX)
DECLARE #TABLE NVARCHAR(MAX)
SET #COLS = 'COL1,COL2'
SET #TABLE = 'TABLENAME'
Now execute the query
DECLARE #QRY NVARCHAR(MAX)
SET #QRY = 'SELECT (SELECT '+#COLS+' FROM '+#TABLE+') FROM sourcetable'
EXEC SP_EXECUTESQL #QRY
You can build the query in code dynamically. However it needs to be robust so that it does not gets prone to SQL injection. Something like this:
string commandString = "select {0} from SomeTable";
SqlCommand command = new SqlCommand();
command.CommandText = string.Format(commandString, "selected column names");
command.EndExecuteReader();
In SQL:
declare #query nvarchar(500)
set #query = replace('select 0 from author','0','column names from some parameter')
execute sp_executesql #query
Update 2: Does this do what you need?
declare #query nvarchar(500)
DECLARE #columnNames varchar(1000)
set #columnNames = ''
SELECT #columnNames = #columnNames + column_name + ',' FROM metadata
set #query = replace('select 0 from source_table','0',SUBSTRING(#columnNames,0,LEN(#columnNames)-1))
execute sp_executesql #query
I have a problem when I would like to transfer the value of a variable to another variable.
declare #column varchar(255);
set #column = 'cheesecake';
declare #tmp varchar(255);
set #tmp = (select #column from TEST where id = 1);
But in this case #tmp won't have the value of the table, but the name of the #column variable. I tried it with dynamic sql, but I got a syntax error.
declare #column varchar(255);
set #column = 'cheesecake';
declare #tmp varchar(255);
set #tmp = exec('select ' + #column + ' from TEST where id = 1');
How can I solve that the #tmp variable would contain the value of the query?
EXEC executes in a different context, therefore the variables cannot be shared without hassle. You specify an output parameter to the statement using sp_executesql
DECLARE
#language nvarchar(255),
#translation nvarchar(255),
#statement nvarchar(255)
SET #language = N'norwegian'
SET #statement = 'select #translation='+#language+' from Translations where id = 1'
EXEC sp_executesql
#statement,
N'#translation nvarchar(255) OUTPUT',
#translation OUTPUT
SELECT #translation
SQLFiddle
AFAIK, it is not possible to directly assign to a variable using `exec. A workaround to your issue would be to create a table variable to store the results of the dynamic query, and then set the value of the second variable using the table variable, like so:
declare #column varchar(255);
set #column = 'cheesecake';
declare #tmp varchar(255);
declare #query nvarchar(255) = N'select ' + #column + N' from TEST where id = 1'
declare #tbl table(tmp varchar(255)) --Intermediate Table variable
insert into #tbl --Insert dynamic query results here
exec sp_executesql #query
select top 1 #tmp = tmp from #tbl --Assign value here
select #tmp
EDIT: I stand corrected. This answer shows how you can assign from dynamic SQL result to a variable by making use of OUTPUT parameters within the dynamic query.
I am using a dynamic sql i.e.
DECLARE #searchstring VARCHAR(500)
DECLARE #str VARCHAR(MAX)
SELECT #str = 'SELECT * FROM Table1 WHERE ' + #searchstring
EXECUTE #str
What I need is I want to select one column value from above dynamic sql to pass in a different SP
Let's say I need ID column value and pass it to another sp named GetAnotherData #Ids. How can I do that?
well you can go with Alexander Fedorenko example, but if you don't want to create any temp tables, you can use output xml parameter to pass your ids:
declare #stmt nvarchar(max), #Data xml, #searchstring nvarchar(max)
select #stmt = '
select #Data = (
select id
from Table1
where ' + #searchstring + '
for xml raw(''Data'')
)
'
exec sp_executesql
#stmt = #stmt,
#params = N'#Data xml output',
#Data = #Data output
select
T.C.value('#id', 'int') as id
from #Data.nodes('Data') as T(C)
sql fiddle demo
The following example creates a user-defined table type that has one Id column. Further the INSERT #RetIds EXEC(#STR) statement fills the parameter list, and then passes the values to a stored procedure
CREATE TYPE RetIds AS TABLE
(
Id int
)
DECLARE #searchstring varchar(500) = 'AND SearchCol = 1'
DECLARE #str varchar(max)
SELECT #str ='SELECT Id FROM dbo.test6 WHERE 1 = 1 ' + #searchstring
DECLARE #RetIds AS RetIds
INSERT #RetIds
EXEC(#str)
EXEC dbo.ExecIds #RetIds
See demo on SQLFiddle