I'm attempting to learn to use dynamic SQL to automate what would otherwise require a lot of typing. However, this would include putting variables directly into table names (not as the whole table name).
When running the below query directly in SSMS, I get the output "Command(s) completed successfully"... but I'd rather get the query output. Where am I going wrong?
DECLARE #sql NVARCHAR(MAX)
DECLARE #cat NVARCHAR(25)
DECLARE #type NVARCHAR(25)
SET #sql = '
SELECT EntityID, ''#cat'' AS c, Subcategory'+#type+'
FROM WCO..Entity'+#cat+' a
JOIN WCO..Entity'+#cat+'Subcategory b ON a.Entity'+#cat+'ID = b.Entity'+#cat+'ID
JOIN WCO..'+#cat+'Subcategory c ON b.'+#cat+'SubcategoryID = c.'+#cat+'SubcategoryID
WHERE
EntityID IN Ent_ID IN (728456,762360)
'
EXECUTE sp_executesql #sql, N'#cat NVARCHAR(25), #type NVARCHAR(25)', 'AdverseMedia', 'Label'
When you're constructing #sql you're concatenating #cat and #type into the string, however, they're uninitialized. As a result, your #sql variable is null when you go to execute (try using print #sql right before the sp_executesql). You're looking for more like (note the initializations in the declarations):
DECLARE #sql NVARCHAR(MAX)
DECLARE #cat NVARCHAR(25) = 'AdverseMedia'
DECLARE #type NVARCHAR(25) = 'Label'
SET #sql = '
SELECT EntityID, '''+#cat+''' AS c, Subcategory'+#type+'
FROM WCO..Entity'+#cat+' a
JOIN WCO..Entity'+#cat+'Subcategory b ON a.Entity'+#cat+'ID = b.Entity'+#cat+'ID
JOIN WCO..'+#cat+'Subcategory c ON b.'+#cat+'SubcategoryID = c.'+#cat+'SubcategoryID
WHERE
EntityID IN Ent_ID IN (728456,762360)
'
PRINT #sql
EXECUTE sp_executesql #sql
Related
I declared a variable #Obj and assign a complete table name 'ODS..Account' to it.
DECLARE #Obj VARCHAR(255)
Then I used it in a query immediately after FROM Clause. I perceive it is just a string, unable to act as a table object. So how can I fix the code to get it works? Cheers
INSERT Control.dbo.Consistency_Check
(Table_Name
,Schema_Name
,Id
,Incremental_DateTime_Column
)
SELECT
#Tab
,'ODS'
,Id
,SystemModstamp
FROM
#Obj )
You can use a local variable as a scalar value, not as a function. To do this, you need dynamic SQL:
declare #sql varchar(max);
select #sql = '
INSERT Control.dbo.Consistency_Check(Table_Name, Schema_Name, Id, Incremental_DateTime_Column)
SELECT ''#Tab'', 'ODS', Id, SystemModstamp
FROM #Tab
';
select #sql = replace(#sql, '#tab', #tab);
exec sp_executesql #sql;
Slightly different way of doing it with dynamic SQL:
DECLARE #Obj VARCHAR(255) = 'dbo.table'
DECLARE #SQL NVARCHAR(MAX) = ''
SET #SQL = #SQL +
'INSERT Control.dbo.Consistency_Check
(Table_Name
,Schema_Name
,Id
,Incremental_DateTime_Column
)
SELECT
#Tab
,''ODS''
,Id
,SystemModstamp
FROM
' + #Obj + ''
EXEC (#SQL)
You cannot. You probably want to use dynamic query. i.e. workout the SQL query string into a variable and exec using sp_executesql.
You may use the same variable name in the dynamic SQL but I changed it to #p_Tab for the example.
DECLARE #Tab int = 3
DECLARE #SQLString nvarchar(500)
DECLARE #ParmDefinition nvarchar(500) = N'#p_Tab int';
Declare #TableName nvarchar(100) = 'ODS..Account'
/* Build the SQL string dynamicly.*/
SET #SQLString = N'INSERT Control.dbo.Consistency_Check
(Table_Name
,Schema_Name
,Id
,Incremental_DateTime_Column
)
SELECT
#p_Tab
,''ODS''
,Id
,SystemModstamp
FROM
'+ #TableName
EXECUTE sp_executesql #SQLString, #ParmDefinition,
#p_Tab = #Tab
Further reference: https://msdn.microsoft.com/en-us/library/ms188001.aspx
I am creating a stored procedure with a cursor and I need to store the quantity of a column into a variable.
SQL says that it cannot convert nvarchar into int
I have tried to use CONVERT, CAST and EXEC but couldn't make it work.
How can I solve this ?
DECLARE #FieldName nvarchar(255);
DECLARE #RequestCode Nvarchar(50);
DECLARE #ReqSQLQuantity nvarchar(max);
DECLARE #Quantity int;
Select #ReqSQLQuantity = concat('select count(*) From (select distinct [', #FieldName , '] from [report_' , #RequestCode , ']) as number')
Set #Quantity = (#ReqSQLQuantity)
Select #Quantity
Another a bit safer option would be to use sp_executesql stored procedure something like this....
DECLARE #FieldName nvarchar(255);
DECLARE #RequestCode Nvarchar(50);
DECLARE #ReqSQLQuantity nvarchar(max);
DECLARE #Quantity int, #tableName SYSNAME;
SET #tableName = N'report_' + #RequestCode
Select #ReqSQLQuantity = N' select #Quantity = count(*) '
+ N' From (select distinct ' + QUOTENAME(#FieldName)
+ N' from ' + QUOTENAME(#tableName) + N' ) as number'
Exec sp_executesql #ReqSQLQuantity
,N'#Quantity INT OUTPUT'
,#Quantity OUTPUT
Select #Quantity
Set #Quantite = (#ReqSQLQuantite)
This is not an evaluation, is an implicit conversion. From NVARCHAR to INT, and you are trying to convert a SQL query text into an INT, hence the error.
Also, you are assuming that results are the same as return values and can be assigned to variables. This is incorrect, SQL execution results are sent to the client. To capture a result, you must use a SELECT assign: SELECT #value =.... Trying to run #variable = EXEC(...) is not the same thing. Think at SELECT results the same way as a print in an app: a print sends some text to the console. If you run some pseudo-code like x = print('foo') then 'foo' was sent to the console, and x contains the value returned by print (whatever that is). Same with this pseudo-SQL, #x = EXEC('SELECT foo') will send foo to the client, and #x will some numeric value which is the value returned by EXEC (in a correct example one would have to use explicit RETURN statement to set it).
Overall, the code as posted has absolutely no need for capturing the value and returning it, it can simply execute the dynamic SQL and let the result be returned to client:
SET #sql = concat(N'SELECT count(*) FROM (SELECT ... FROM ...)');
exec sp_executesql #sql;
I have a language table and I want to select aliases from that table according to the specified language.
ALTER PROCEDURE sp_executesql
(#parameter1 NVARCHAR(MAX)
,#parameter2 NVARCHAR(MAX)
,#code NVARCHAR(MAX),#language NVARCHAR(MAX))
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'SELECT '+#parameter1+' AS (SELECT #language FROM Languages WHERE code=somecolumn) '+#paramter2+' AS (SELECT #language FROM Languages WHERE code='+#code+') FROM mytable'
EDIT:
in Stored Procedure, I need something like that.
Thanks for answers..
You cannot use a subquery to build an alias in that way, you would need to use dynamic sql to do this.
DECLARE #language NVARCHAR(255) -- or whatever type your field is
SELECT #language=language FROM Languages WHERE code=#code
DECLARE #sql NVARCHAR(MAX) = 'SELECT ' + #parameter1 + ' AS ' + QUOTENAME(#language) + ' FROM MyTable'
EXEC sp_executesql #sql
(Note the inclusion of QUOTENAME around the alias - this is a safety feature in case of your alias names having invalid characters.)
You can repeat the code above for the second parameter inside your stored procedure.
Try this:
CREATE PROCEDURE sp_NameOfSP
(#parameter1 NVARCHAR(MAX)
,#parameter2 NVARCHAR(MAX)
,#code NVARCHAR(MAX)
,#language NVARCHAR(MAX))
AS
BEGIN
DECLARE #sql NVARCHAR(MAX)
SELECT TOP(1) #language=LanguageColumn FROM Languages WHERE code=somecolumn
SET #sql = 'SELECT '+#parameter1+' AS '+#language+', '
SELECT TOP(1) #language=LanguageColumn FROM Languages WHERE code=#code
SET #sql=#sql+#paramter2+' AS '+#language+' FROM mytable'
EXEC(#SQL)
END
Replace LanguageColumn with proper column name from Languages table
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)
I have some tables for storing different file information, like thumbs, images, datasheets, ...
I'm writing a stored procedure to retrieve filename of a specific ID. something like:
CREATE PROCEDURE get_file_name(
#id int,
#table nvarchar(50)
)as
if #table='images'
select [filename] from images
where id = #id
if #table='icons'
select [filename] from icons
where id = #id
....
How can I rewrite this procedure using case when statement or should I just use table name as variable?
You can't use case .. when to switch between a table in the FROM clause (like you can in a conditional ORDER BY). i.e. so the following:
select * from
case when 1=1
then t1
else t2
end;
won't work.
So you'll need to use dynamic SQL. It's best to parameterize the query as far as possible, for example the #id value can be parameterized:
-- Validate #table is E ['images', 'icons', ... other valid names here]
DECLARE #sql NVARCHAR(MAX)
SET #sql = 'select [filename] from **TABLE** where id = #id';
SET #sql = REPLACE(#sql, '**TABLE**', #table);
sp_executesql #sql, N'#id INT', #id = #id;
As with all dynamic Sql, note that unparameterized values which are substituted into the query (like #table), make the query vulnerable to Sql Injection attacks. As a result, I would suggest that you ensure that #table comes from a trusted source, or better still, the value of #table is compared to a white list of permissable tables prior to execution of the query.
Just build SQL string in another variable and EXECUTE it
DECLARE #sql AS NCHAR(500)
SET #sql=
'SELECT [filename] '+
' FROM '+#table+
' WHERE id = #id'
EXECUTE(#sql)
CREATE PROCEDURE get_file_name(
#id int,
#table nvarchar(50)
)as
DECLARE #SQL nvarchar(max);
SET #SQL = 'select [filename] from ' + #table + ' where id = ' + #id
EXECUTE (#SQL)