Substitute Column name in dynamic queries - sql

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

Related

How to SELECT INTO <a calculated table name>? [duplicate]

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)

Passing a variable out of a SQL query

Is it possible to pass a variable out of a SQL query?
I am building up the initial query using a variable. I have added a simplified subset of my query below.
Thanks
declare #query Nvarchar(max)
declare #ColumnName Nvarchar(max)
set #ColumnName = 'MyColumn'
SET #query = 'Select ' + #ColumnName + ' from [MyTable] WHERE [MyCondition]'
EXECUTE sp_executesql #query
Can I return this result as a variable to pass to another query?
Yes. You use an output parameter:
declare #query Nvarchar(max);
declare #ColumnName Nvarchar(max);
declare #outval <type>; -- whatever type
set #ColumnName = 'MyColumn'
set #query = 'Select #outval =' + #ColumnName + ' from [MyTable] where [MyCondition]';
execut sp_executesql #query,
N'#outval <type> output',
#outval = #outval output;
Store the results in table variable and then convert it into XML.
Declare #xml XML
declare #query Nvarchar(max)
declare #ColumnName Nvarchar(max)
set #ColumnName = 'MyColumn'
declare #Table as TABLE(
MyColumn varchar(Max)-- Your Column datatype
)
SET #query = 'Select ' + #ColumnName + ' from [MyTable] WHERE [MyCondition]'
INSERT INTO #Table
EXECUTE sp_executesql #query
select #xml=MyColumn from #Table for XML PATH('')
How you want to pass returned result to other query?
What i can think of create a function return a table and call that function on other query:
CREATE FUNCTION test (#id int)
RETURNS #testTable TABLE(id int)
AS
begin
insert into #testTable select id from #your_table where id = #id
return
end
This will return a table you can check using :
select * from test(2); --will give you a table
If you want to use in a query:
`select * from #second_table where id in (select * from test2(#id parameter))` --- will filter query by id returned by function.

SQL add a variable to a query

How do I create variables that are specified once and then used in queries later in a script? These variables may be used multiple times in a query, and in multiple queries in a script. I use #x as such a variable in the examples below.
What I want to do is something like:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + #x + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Which returns the error mentioned above. I would like it to achieve the equivalent of:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''test'' as [TestCase]
From mytable'
Exec (#Query)
-- Returns e.g.
-- Name TestCase
-- Alice Test
-- Bob Test
I also note that the following doesn't work and returns the same error as the first:
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ' + 'test' + ' as [TestCase]
From mytable'
Exec (#Query)
-- returns "Invalid column name 'test'"
Based on the error and since I'm not trying to use the #x as a column name, but just as a variable, I assume I'm using an invalid implementation of a variable.
Since you're not trying to use a variable as a column name, you do not need to use dynamic SQL at all. (Which is a Good Thing(TM) since dynamic SQL should only be used with a great deal of caution due to it being a great attack surface.)
A simple:
declare #x nvarchar(40)
set #x = 'test'
select [Name], #x as TestCase
from mytable
will do.
That being said, if you have a use case for dynamic SQL (again the particular query in question here does not but perhaps an ad-hoc query is being passed in to the procedure), the thing to do would be to pass your variable as a parameter to the query via sp_executesql. This is akin to creating a stored procedure with parameters:
declare #x nvarchar(40)
declare #query nvarchar(1000)
set #x = 'test'
set #query = 'select [Name], #x as TestCase from mytable'
exec sp_executesql #query, N'#x nvarchar(1000)', #x
You were missing quotes. Thats it. Try below code.
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name]
, ''' + #x + ''' as [TestCase]
From mytable'
Exec (#Query)
Declare #Query nvarchar(1000)
Declare #x nvarchar(40)
Set #x = 'test'
Set #Query = 'Select [Name],'++''''+#x+''''+ ' as [TestCase]
From mytable'
print #query
Output:
Select [Name],'test' as [TestCase]
From mytable

Get column value from string column name sql

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

Dynamically Create Update SQL In Stored Procedure

I try to create a stored procedure to update a table record whose sql statement is dynamically created. I wrote some codes but am stoped in to run this query dynamically, How can i run this query or is there a better solution for this problem.
How this SP work?=> I send the columns names,values and datatype of the record that need update to SP like below
<e columnName=''PaymentStatus'' value=''99'' type=''nvarchar''/>
<e columnName=''HotelProvider'' value=''GAT2'' type=''nvarchar''/>
Then travel the nodes and create an Update statement, but can't execute it :))
I am giving a part of SP to understand the question better.
DECLARE #UpdateXml xml = '
<xml>
<e columnName=''PaymentStatus'' value=''99'' type=''nvarchar''/>
<e columnName=''HotelProvider'' value=''GAT2'' type=''nvarchar''/>
</xml>';
DROP TABLE ##UpdateFields
SELECT
t.c.value('#columnName', 'varchar(max)') AS ColumnName,
t.c.value('#value', 'varchar(max)') AS Value,
t.c.value('#property', 'varchar(max)') AS PropertyOf,
t.c.value('#type', 'varchar(max)') AS ColumnType
INTO ##UpdateFields
from #UpdateXml.nodes('/xml/e') as t(c)
DECLARE #SQL nvarchar(MAX) = 'UPDATE HotelBooking ';
DECLARE #SQLUpdatePart nvarchar(MAX);
SET #SQLUpdatePart = 'SET ';
SELECT #SQLUpdatePart= #SQLUpdatePart+ColumnName +'='+'#QP_'+ColumnName+',' FROM ##UpdateFields WHERE PropertyOf IS NULL;
DECLARE #SQLWherePart nvarchar(MAX);
SET #SQLWherePart = ' WHERE Id=2';
DECLARE #ParmDefinition nvarchar(MAX)='';
SELECT #ParmDefinition = #ParmDefinition+'#QP_'+ColumnName+' '+ColumnType+',' FROM ##UpdateFields;
SELECT #ParmDefinition
SELECT #SQL + #SQLUpdatePart + #SQLWHerePart;
Last two select statements results are:
#QP_PaymentStatus nvarchar,#QP_HotelProvider nvarchar,#QP_TransactionId uniqueidentifier,#QP_UpdatedDate datetime
and
UPDATE HotelBooking SET PaymentStatus=#QP_PaymentStatus,HotelProvider=#QP_HotelProvider,UpdatedDate=#QP_UpdatedDate,TransactionId=#QP_TransactionId WHERE Id=2
Now How can I give the #QP parameters to sp_executesql() method dynamically?
You can do it by wrapping sp_executesql call in another exec:
declare #updateStr nvarchar(1000)
-- #updateStr = N'select * from ATable where ID = #p1'
set #updateStr = N'N''select * from ATable where ID = #p1'''
declare #paramStr nvarchar(100)
-- #paramStr = N'#p1 int'
set #paramStr = N'N''#p1 int'''
declare #actualParameters nvarchar(100)
set #actualParameters = N'#p1 = 10'
-- Concatenate parts of query into a variable
declare #sql nvarchar(max)
set #sql = N'sp_executesql ' + #updateStr + ',' + #paramStr + ', ' + #actualParameters
-- And voila!
exec (#sql)