How to pass a table variable using sp_executesql - sql

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;

Related

Query with variable tablename

I don't know why I keep bumping into these, but I have a small problem with a stored procedure. The only special in it is the variable Tablename:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE dbo.ProdTijdCompare
#TABLENAME SYSNAME,
#scanner nvarchar(50)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #SQL NVARCHAR(MAX);
SELECT #SQL = 'select SUM(tijd) from ' + #TABLENAME + 'where Scanner = #scanner'
EXEC sp_executesql #SQL;
END
GO
The error I'm getting when executing in SSMM:
Msg 102, Level 15, State 1, Line 3
Incorrect syntax near '='.
(1 row(s) affected)
You need a space between #TableName and where:
SELECT #SQL = 'select SUM(tijd) from ' + #TABLENAME + ' where Scanner = #scanner';
This type of error is incredibly obvious if you just print out the SQL before running it.
Always quote table names in dynamic SQL to avoid SQL Injection (cf QUOTENAME)
Second, supply the #scanner parameter to the sp_executesql procedure as you can see in the sample below:
SELECT #SQL = 'select SUM(tijd) from ' + QUOTENAME(#TABLENAME) + ' where Scanner = #scanner'
EXEC sp_executesql #SQL, N'#scanner NVARCHAR(50)', #scanner;

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

Invalid Column name error during execution of stored procedure

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

Dynamic SQL gives "Incorrect Syntax Near '+'"

I am probably being extremely dumb here but why does this simple dynamic query:
EXEC sp_executesql N'SELECT Id FROM dbo.Widgets WHERE Id = ' + 1;
Give "Incorrect syntax near '+'"
?
You can't formulate the expression as part of the argument. And you shouldn't be concatenating that way anyway (think SQL injection) - you're using sp_executesql already, why not use a proper parameter?
DECLARE #Id INT, #sql NVARCHAR(MAX);
SET #Id = 1; -- presumably this will come from elsewhere
SET #sql = N'SELECT Id FROM dbo.Widgets WHERE Id = #Id;';
EXEC sp_executesql #sql, N'#Id INT', #Id;

Create table with instruction into #parameter in stored procedure

I want to create a table from this code in SQL Server, but the stored procedure returns an error
CREATE PROCEDURE Recovery_CountryCode (#NombreTabla SYSNAME)
AS
DECLARE #ParamDefinition nvarchar(500);
DECLARE #SQLString nvarchar (4000);
SET #SQLString=N'SELECT Name
INTO #TableName
FROM AdventureWorks2008R2.Production.Location';
SET #ParamDefinition=N'#TableName SYSNAME';
EXECUTE sp_executesql #SQLString, #ParamDefinition, #TableName=#NombreTabla;
GO
I want avoid define table
When I call the stored procedure:
EXEC Recovery_CountryCode #NombreTabla='Paises';
I get the follow message:
Mens. 102, Nivel 15, Estado 1, LĂ­nea 2
Sintaxis incorrecta cerca de '#TableName'.
You can just concatenate the SQL inside your procedure
CREATE PROCEDURE Recovery_CountryCode (#NombreTabla SYSNAME)
AS
DECLARE #ParamDefinition nvarchar(500);
DECLARE #SQLString nvarchar (4000);
SET #SQLString=N'SELECT Name INTO ' +
#NombreTabla +
' FROM AdventureWorks2008R2.Production.Location';
EXECUTE sp_executesql #SQLString
GO
You can't bind variables to table names in this way. You need to do something like
Declare #sql nvarchar(max), #NombreTable sysname = 'Test'
Set #sql = N'Select Name Into ' + #NombreTable +
N' From AdventureWorks2008R2.Production.Location
exec sp_executesql #sql
http://www.sommarskog.se/dynamic_sql.html is recommended reading.