Invalid Column name error during execution of stored procedure - sql

I am not able to execute the stored procedure. It is throwing an error
Invalid Column name 'DW201401'
Command used to execute the stored procedure:
exec RM_UTIL_MODE server,'DW201401'
Stored procedure code:
ALTER Procedure [dbo].[RM_UTIL_MODE]
#ServerName varchar(50),
#Value varchar(50)
As
Begin
declare #query nvarchar(max)
set #query = N'SELECT mode FROM ' + #ServerName +
N'.master.dbo.sysdatabases WHERE name =' + #Value
exec sp_executesql #query
End
But when I tried to run the query alone as shown below it is giving me result.
select mode, name
from server.master.dbo.sysdatabases
where name = 'DW201401'

Presumably, the issue is quotes around #Value:
declare #query nvarchar(max)
set #query = N'SELECT mode FROM '
+ #ServerName
+ N'.master.dbo.sysdatabases
WHERE name = '''+#Value+'''';
However, I would use parameter substitution instead:
declare #query nvarchar(max) ;
set #query = N'SELECT mode
FROM ' + #ServerName + N'.master.dbo.sysdatabases
WHERE name = #value';
exec sp_executesql #query, N'#value varchar(50)', #value = #value;
You are already using sp_executesql, so you might as well use it properly. Note: you cannot substitute the server name.
EDIT:
To elaborate on the comment, I would write the code this way:
declare #sql nvarchar(max) ;
set #sql = N'
SELECT mode
FROM #ServerName.master.dbo.sysdatabases
WHERE name = #value';
set #sql = replace(#sql, '#ServerName', quotename(#ServerName));
exec sp_executesql #sql, N'#value varchar(50)', #value = #value;
When using dynamic SQL, I no longer piece together the query using string concatenation. Instead, I put in place holders and use replace(). I find that concatenation is hard to maintain and often obscures what the SQL is doing. Although there is a bit more overhead in using replace() (and I often do it multiple times), it is worth it for preventing errors and maintaining the code (plus, my queries tend to run for a while anyway, so the overhead is minimal compared to the query time).

Your select looks like:
select mode, name from server.master.dbo.sysdatabases where name = DW201401
so you need to add escaped quotes in your dynamic query:
exec RM_UTIL_MODE cefmtqcfindv3,'DW201401'
ALTER Procedure [dbo].[RM_UTIL_MODE]
#ServerName varchar(50),#Value varchar(50)
As
Begin
declare #query nvarchar(max)
set #query = N'SELECT mode FROM '
+ #ServerName
+ N'.master.dbo.sysdatabases
WHERE name ='''+#Value+''''
exec sp_executesql #query
End
Just as a suggestion, when you are building a dynamic sql, try using PRINT instead of EXEC, then get what is printed and try it out. Most of the times you will know what went wrong.
Just as an example:
ALTER Procedure [dbo].[RM_UTIL_MODE]
#ServerName varchar(50),#Value varchar(50)
As
Begin
declare #query nvarchar(max)
set #query = N'SELECT mode FROM '
+ #ServerName
+ N'.master.dbo.sysdatabases
WHERE name ='''+#Value+''''
PRINT #query
--exec sp_executesql #query
End

Related

Setting SQL Variable via Dynamic SQL

I know I am overthinking this, but I've been banging against this for too long so I'm reaching out for help.
This is the statement I'm trying to run: SELECT #cntMax = MAX(id) FROM [Raw_Item-FieldReport]
BUT, the table name is a variable #reportTable
This doesn't work:
SET #sql = 'SELECT #cntMax = MAX(id) FROM #reportTable'
EXEC sp_executesql #sql
I even tried having the actual table name in the SET #sql and that doesn't work either.
I didn't think it would be this difficult, please tell me I'm missing something easy/obvious.
Here's the full bit of code for those who want it:
DECLARE
#inTable nvarchar(255) = 'Raw_Item',
#reportTable nvarchar(255),
#fieldName nvarchar(255),
#cnt int,
#cntMax int,
#sql nvarchar(max)
SET #reportTable = #inTable + '-FieldReport'
SET #cnt = 1
SELECT #cntMax = MAX(id) FROM [Raw_Item-FieldReport]
PRINT #cntMax
SET #cntMax = 0
SET #sql = 'SELECT #cntMax = MAX(id) FROM [Raw_Item-FieldReport]'
EXEC sp_executesql #sql
PRINT #cntMax
SQL Server 12.0.2008.8 (on Azure)
You need to use an output parameter, otherwise SQL Server has no idea how to connect #cntMax in the dynamic SQL to #cntMax not in the dynamic SQL, since they are different scopes. And to protect yourself from SQL injection (some tips here and here), always check that your object exists, and use QUOTENAME() as opposed to manually adding square brackets (and you should always use QUOTENAME() when building object names from user input or variables, even when they don't have bad characters like dashes):
DECLARE #sql nvarchar(max),
#inTable nvarchar(255) = N'Raw_Item',
#reportTable nvarchar(255);
SET #reportTable = N'dbo.' + QUOTENAME(#inTable + '-FieldReport');
IF OBJECT_ID(#reportTable) IS NOT NULL
BEGIN
SET #sql = N'SELECT #cntMax = MAX(id) FROM ' + #reportTable + N';';
EXEC sys.sp_executesql #sql,
N'#cntMax int output',
#cntMax = #cntMax OUTPUT;
PRINT #cntMax;
END
ELSE
BEGIN
PRINT 'Nice try, h#xx0rs!';
END
Always use schema reference (dbo), always use statement terminators, and please try to avoid naming things with invalid identifier characters like dash (-). And one additional tip: always use N prefix on N'nvarchar string literals'.

How to create sp_executesql to drop tables dynamicaly

For some reasons, I am trying to create a dynamic script to drop tables that I created before. I couldnt do the syntax right and I need help for this matter.
When I run my script, it gives the error:
"Procedure expects parameter '#statement' of type 'ntext/nchar/nvarchar'."
and this is my script. It has an error in sp_executesql statement, I guess. How can I fix this?
DECLARE #sql VARCHAR(MAX);
DECLARE #tmpTableName VARCHAR(max);
SET #tmpTableName = '##gmAAA_COLLATION';
SET #sql = 'DROP TABLE #tmpTableName';
EXEC sp_executesql #sql, N'#tmpTableName NVARCHAR(max)', #tmpTableName;
You cannot do this with static SQL, i.e. a table name can never be a parameter in SQL statements like these. This is also true for column names, schema names etc.
If you want to do this using sp_executesql, you can build the SQL dynamically as follows:
SET #sql = 'DROP TABLE '+QUOTENAME(#tmpTableName);
EXEC sp_executesql #sql;
PS: The #stmt parameter of the sp_executesql procedure needs to be of type NVARCHAR(...).
SET #sql = 'DROP TABLE '+#tmpTableName;
EXEC sp_executesql #sql;
The sp_executesql requires nvarchar for the #stmt and #params parameters
so change the data Types of variables form varchar to be nvarchar as following
DECLARE #sql NVARCHAR(MAX);
DECLARE #tmpTableName VARCHAR(max);
Try the following query:-
SET #sql = 'DROP TABLE #tmpTableName'; EXEC (#sql)
OR
DECLARE #sql NVARCHAR(MAX);
DECLARE #tmpTableName NVARCHAR(max)
SET #tmpTableName = '##gmAAA_COLLATION';
SET #sql = 'DROP TABLE'+QUOTENAME(#tmpTableName);
EXEC sp_executesql #sql,N'#tmpTableName NVARCHAR(max)',#tmpTableName

How to pass a table variable using sp_executesql

I'm trying to create a table using sp_executesql but I keep getting an error that says "Incorrect syntax near '#_TableName'. Any idea what I'm doing wrong here?
Here's the code that I'm using:
DECLARE #SQLString NVARCHAR(MAX),
#ParamDefinition NVARCHAR(MAX),
#TableName NVARCHAR(MAX);
SET #TableName = N'[dbo].[MyTable]';
SET #SQLString = N'SELECT * FROM #_TableName;';
SET #ParamDefinition = N'#_TableName NVARCHAR(max)';
EXEC sp_executesql #SQLString, #ParamDefinition,
#_TableName = #TableName;
That yields the error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '#_TableName'.
If I hard code the table name and the column type (I have to do both) then the query works, otherwise I get the incorrect syntax message for both those variables.
In case you're wondering, I want to put this code inside a stored procedure, so that if anyone wants to create or modify a table then they call this stored procedure which can run additional validations.
Figured out the problem.
Apparently sp_executesql expects the parameter definition for a table to be of a table type (see this answer for an example: https://stackoverflow.com/a/4264553/21539).
An easier way to solve this problem was to insert the variables names directly into the SQLStatement string as follows:
DECLARE #SQLString NVARCHAR(MAX),
#TableName NVARCHAR(MAX);
SET #TableName = N'[dbo].[MyTable]';
SET #SQLString = N'SELECT * FROM ' + #TableName + ';';
SET #ParamDefinition = N'#_TableName NVARCHAR(max);
EXEC sp_executesql #SQLString;

How a store executed variable output into another variable, SQL

Here is my snippets:
create procedure sp (#pre nvarchar(50), #count nvarchar(50))
as
declare #preval nvarchar(500);
declare #countval nvarchar(500);
select #preval = 'select '+ #prefix + ' from tblc'
select #countval= 'select '+ #counter + ' from tblc'
exec sp_executesql #preval,#countval
pre and count are a 2 input parameters which has gives "columnsname1" and "columnname2" which are dynamic. I want to build a query/sp which gives me the value inside that particular columns and i want to store them in 2 different or single variable inside my sp. Til now I'm getting column name as result which I don't want, I want value inside the particular column.nd also want that value in a 3rd variable! If any doubt let me know.
Well... assuming that your example is pseudo code, and not expected to work verbatim, you could benefit from reading how sp_executesql works - noting that the second parameter is not a subsequent command to execute.
Having done that, you might try the following:
create procedure sp (#prefix nvarchar(50), #counter nvarchar(50))
as
declare #preval nvarchar(500);
declare #countval nvarchar(500);
select #preval = 'select '+ #prefix + ' from tblc'
select #countval= 'select '+ #counter + ' from tblc'
declare #cmd as nvarchar(500);
set #cmd = #preval+';'+#countval
exec sp_executesql #cmd
...and pray someone doesn't do this...
sp '1; delete',''
Personally, I would question why you feel the need to go down this road.
However, you will probably find that if you read up on sp_executesql, and look at the following example, you will find a way to get what you need. I'm guessing that the 'tblc' table only has a single row ?
declare #sql as nvarchar(4000)
declare #p1 as integer
set #sql = 'select #p1=count(*) from tblc'
exec sp_executesql #sql, N'#p1 int output', #p1 output
select #p1

Creating SQL table using dynamic variable name

I want to create backup SQL tables using variable names.
something along the lines of
DECLARE #SQLTable Varchar(20)
SET #SQLTable = 'SomeTableName' + ' ' + '20100526'
SELECT * INTO quotename(#SQLTable)
FROM SomeTableName
but i'm getting
Incorrect syntax near '#SQLTable'.
It's just part of a small script for maintence so i don't have to worry about injections.
DECLARE #MyTableName sysname;
DECLARE #DynamicSQL nvarchar(max);
SET #MyTableName = 'FooTable';
SET #DynamicSQL = N'SELECT * INTO ' + QUOTENAME(#MyTableName) + ' FROM BarTable';
EXEC sp_executesql #DynamicSQL;
Unfortunately, you can't use bind variables for table names, column names, etc. IN this case you must generate dynamic SQL and use exec.
DECLARE #Script NVARCHAR(MAX);
SET #Script = N'SELECT * INTO SomeTableName_' + N'20100526' + N' FROM SomeTableName';
EXEC sp_executesql #Script
I've left the date separate as I assume you want to calculate it for every run.
You should look into using synonyms:
-- Create a synonym for the Product table in AdventureWorks2008R2.
CREATE SYNONYM MyProduct
FOR AdventureWorks2008R2.Production.Product;
GO
-- Query the Product table by using the synonym.
USE tempdb;
GO
SELECT ProductID, Name
FROM MyProduct
WHERE ProductID < 5;
GO
http://msdn.microsoft.com/en-us/library/ms177544.aspx
DECLARE #MyTableName nvarchar(20);
DECLARE #DynamicSQL nvarchar(1000);
SET #MyTableName = "FooTable";
SET #DynamicSQL = N'SELECT * INTO ' + #MyTableName + ' FROM BarTable';
exec #DynamicSQL;
this query is correct but just use single quote at the ("FooTable")='FooTable'