I need to execute certain script on various SQL Server instances. They use the database with a different identification. However, all the databases have the same table (same name and structure) that should be processed. Because of that I want to detect the name of the database, set it to a string variable, construct the SQL statement, and execute the constructed string via sp_executesql. The bare command that executes correctly is:
USE [1000574];
SELECT TOP 10 temperature_1, UTC FROM dbo.Data;
Then I am trying to execute the equivalent string with the #database_name placeholder:
DECLARE #database_name nvarchar(100);
SET #database_name = '1000574';
EXEC sp_executesql N'USE [#database_name];
SELECT TOP 10 temperature_1, UTC FROM dbo.Data;',
N'#database_name nvarchar(100)',
#database_name = #database_name
What I get is the following error message:
*Msg 911, Level 16, State 1, Line 1
Database '#database_name' does not exist. Make sure that the name is entered correctly.*
Where is the error?
Thanks, Petr
You cannot parameterize the argument to use: it expects a literal. Construct the query dynamically instead:
declare #sql nvarchar(max)
set #sql = 'USE [' + #database_name + '];' +
'SELECT TOP 10 temperature_1, UTC FROM dbo.Data;';
exec (#sql)
One more way of doing this:
DECLARE #database_name NVARCHAR(100),#sp_executesql NVARCHAR(100),#sql_cmd NVARCHAR(512);
SET #database_name = N'1000574';
SET #sp_executesql = #database_name + N'.dbo.sp_executesql';
SET #sql_cmd = N'SELECT TOP 10 temperature_1, UTC FROM dbo.Data;';
EXEC #sp_executesql #sql_cmd;
Why not:
DECLARE #sql NVARCHAR(MAX), #database_name SYSNAME;
SET #database_name = N'1000574';
SET #sql = N'SELECT TOP 10 temperature_1, UTC FROM '
+ QUOTENAME(#database_name) + '.dbo.Data;';
EXEC sp_executesql #sql;
Also why is there no order by to tell SQL Server what you mean by TOP?
Or simply use the qualified name, as documented here:
SELECT TOP 10 1000574..temperature_1, UTC FROM dbo.Data
The query can, of course, be built dynamically.
Related
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;
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
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;
I have a few stored procedures which I call in this order.
So, from the first stored procedure, importTaxonomy I call parseXBRL and from parseXBRL I call createTaxonomyStructure.
But in this flow, when the code of the last stored procedure is executed I get an error.
Msg 1087, Level 15, State 2, Line 1
Must declare the table variable "#temporaryTable".
Below you can find the first few lines code of this stored procedure:
CREATE PROCEDURE createTaxonomyStructure #taxonomy_table nvarchar(max), #debug bit = 0
AS
DECLARE #statement NVARCHAR(MAX)
DECLARE #temporaryTable TABLE (taxonomyLine NVARCHAR(MAX)) -- declared a temporary table to avoid creating a Dynamic Query with the entire cursor, but just with the temporary table
DECLARE #taxonomyLine NVARCHAR(MAX) -- variable that will store one line of the taxonomy
SET #statement = 'INSERT INTO #temporaryTable SELECT taxText FROM ' + #taxonomy_table -- statement that will import the taxonomy in the temporary table
EXEC sp_executesql #statement
DECLARE taxonomyCursor CURSOR READ_ONLY FAST_FORWARD FOR -- read each line in the taxonomy to parse afterwards
SELECT taxonomyLine
FROM #temporaryTable
OPEN taxonomyCursor
FETCH NEXT FROM taxonomyCursor INTO #taxonomyLine -- parsing each taxonomy line and extracting the values from important attributes
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #id_element NVARCHAR(MAX)
DECLARE #leaf_element NVARCHAR(MAX)
SELECT #id_element = (SELECT dbo.extract_IDElement(#taxonomyLine))
SELECT #leaf_element = (SELECT dbo.extract_IDLeafElement(#taxonomyLine))
SET #statement = 'UPDATE ' + #taxonomy_table + ' SET fullName = ''' + #id_element + ''', leafName = ''' + #leaf_element + '''';
EXEC sp_executesql #statement
END
I do declare this variable, but I still get the error and I don't understand why.
How can I get over this error?
Thanks!
the error is here:
SET #statement = 'INSERT INTO #temporaryTable SELECT taxText FROM ' + #taxonomy_table -- statement that will import the taxonomy in the temporary table
EXEC sp_executesql #statement
change it to
set #statement = 'select taxText from ' + #taxonomy_table
insert into #temporaryTable
exec sp_executesql #statement
The error is happening because in the scope of executing #statement there's no variable table #temporaryTable.
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'