Creating SQL table using dynamic variable name - sql

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'

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'.

Select into tables dynamically with variables

I have some code to create tables based on a set of dates I define.
Example, I have 5 dates, and they are aren't consecutive. For any of these dates, I want to create a table and I am currently using a Select into.
I am having to do this 5 times, even though the only thing changing is the name of the new table created and the date. Is there a way to do this in an elegant way.
I started writing some code, but I am struggling to get it to loop through all the dates I want. The way I have written it currently, I only works if I edit the date at the start.
DECLARE #MyDate DATE;
SET #MyDate = '2019-01-01';
SET #TableName = 'Table1';
SELECT *
into #TableName
FROM Original_Table
WHERE Query_Date = #MyDate;
Is this a one time thing or do you have to do this on a regular basis?
If it's the first, than I would just do it and get it over with.
If it's the latter, then I suspect something is very wrong with the way that system is designed - but assuming that can't be changed, you can create a stored procedure that will do this using dynamic SQL.
Something like this can get you started:
CREATE PROCEDURE dbo.CreateTableBasedOnDate
(
#MyDate DATE,
-- sysname is a system data type for identifiers: a non-nullable nvarchar(128).
#TableName sysname
)
AS
-- 200 is long enough. Yes, I did the math.
DECLARE #Sql nvarchar(200) =
-- Note: I'm not convinced that quotename is enough to protect you from sql injection.
-- you should be very careful with what user is allowed to execute this procedure.
N'SELECT * into '+ QUOTENAME(#TableName) +N'
FROM Original_Table
WHERE Query_Date = #MyDate;';
-- When dealing with dynamic SQL, Print is your best friend.
-- Remark this row and unremark the next only once you've verified you get the correct SQL
PRINT #SQL;
--EXEC sp_ExecuteSql #Sql, N'#MyDate Date', #MyDate
GO
Usage:
EXEC CreateTableBasedOnDate '2018-01-01', 'zohar';
Use dynamic SQL:
DECLARE #MyDate DATE, #TableName varchar(50);
SET #MyDate = '2019-01-01';
SET #TableName = 'Table1';
DECLARE #sql NVARCHAR(4000);
DECLARE #params NVARCHAR(4000);
SELECT #sql=N'
SELECT *
INTO ' + QUOTENAME(#TableName) + '
FROM Original_Table
WHERE Query_Date = #MyDate;';
SELECT #params = N'#MyDate DATE';
EXEC sys.sp_executesql #sql, #params, #MyDate=#MyDate
Note that dynamic SQL can be dangerous as it opens up a path for SQL injection. Its fine if you are just using it in your own local scripts, but take care if you e.g. wrap this in a procedure that is more widely accessible.
I would use dynamic SQL although I would add another variables for the schema:
DECLARE
#MyDate nVarchar(50) = '2019-01-01',
#Schema nVarchar (50) = 'dbo',
#TableName nVarchar(250) = 'Table1',
#SQL nVarchar(500);
Set #SQL = '
SELECT *
into '+ QUOTENAME(#Schema)+'.'+ QUOTENAME(#TableName) +'
FROM Original_Table
WHERE Query_Date = '+ #MyDate +';
'
--print #SQL
Exec(#SQL)
You can use the print statement to see how the SQL will look before executing this properly. You may also want to look at adding this as a stored procedure.

Is it possible to set a part of a select statement in a variable

I have a query of which the select-part is really long. I'd like to split this in several pieces, especially because some parts are in there twice or even more often.
What I'd like is something like the following:
Declare #SQLPart as varchar(1000)
Set #SQLPart = 'Field1,
case ... as Field2,'
Select ..., #SQLPart, ... From .....
Unfortunately this results error messages. I tried something like EXEC(#SQLPart) as well but of course this also didn't work. How would I solve this?
Yes, dynamic sql and sp_executesql:
CREATE TABLE ##Temp (Field1 int, Field2 int)
Declare #SQLPart nvarchar(1000)
Set #SQLPart = N'Field1, Field2 '
DECLARE #SQL nvarchar(1000) = N'SELECT ' + #SQLPart + 'FROM ##Temp'
PRINT #SQL
EXEC sp_executesql #SQL
DROP TABLE ##Temp
Your SQL code must be nvarchar type.
Alse sp_executesql is better than EXECUTE function, when you have many similar queries, sp_executesql caches executaion plans, and it can be better in perfomance.
You can use dynamic sql here,and use a EXECUTE keyword to execute this dynamic query
Declare #SQLPart as varchar(1000)
Set #SQLPart = 'Field1,
case ... as Field2,'
EXECUTE ('SELECT ....,'+#SQLPart+',... FROM ...')
SQL Server does not support Macro-Substitution, so you would have to use Dynamic SQL.
Declare #SQL varchar(max) ='Select ... ' + #SQLPart + '... from ...'
Exec(#SQL)

Execute sp_executesql, Table Variabe not Declared

I am Using SQL server 2012 and i want to select random columns from my table by applying where condition in this query:
EXECUTE sp_executesql
N'SELECT *
FROM #table
WHERE #Col = #Value',
N'#Value nvarchar(44),#table nvarchar(55),#Col nvarchar(30)',
#Value = 'Cus_1',#Col='CustId',#table='SaleOrder';
But when I execute it, it shows error
Must declare the table variable "#table"
I also tried it to declare by this: #table table(Id nvarchar(30)), but thin it shows again an error on table type...
Please help
This is what you are trying to run:
EXECUTE sp_executesql
N'SELECT * FROM #table WHERE #Col = #Value',
N'#Value nvarchar(44), #table nvarchar(55), #Col nvarchar(30)',
#Value = 'Cus_1', #Col='CustId', #table='SaleOrder';
Alas. You cannot substitute in a table name or column name using parameter substitution. So, SQL Server is looking for a table variable called #table. You can fix this by putting the values directly into the string:
declare #Col = 'CustId', #table = 'SaleOrder';
declare #sql nvarchar(max) = N'SELECT * FROM ' + #table + ' WHERE ' + #Col + ' = #Value';
EXECUTE sp_executesql #sql,
N'#Value nvarchar(44)',
#Value = 'Cus_1';
Unfortunately, I cannot find a good reference in the documentation that explains what is happening. When a statement is compiled, it is allowed to have parameters. However, the parameters are for values in the statement, not for column, table, database, or UDF names or for keywords. The statement itself is compiled, with place holders for the parameters, and in order to be compiled, the SQL engine needs to resolve all object names.

Using variable inside dynamic SQL

I have the below SQL..What I am trying to do is use the Parameter defined at the stored procedure level inside dynamic SQL:
CREATE PROCEDURE [dbo].[Test]
(#DealID NVARCHAR(500),
#OUTPUT NVARCHAR(MAX) OUTPUT,
#FeeType CHAR(1)
) -- I want to use this parameter inside dynamic SQL query
AS
DECLARE #exec_str NVARCHAR(MAX)
DECLARE #ParmDefinition NVARCHAR(MAX)
BEGIN
SET #exec_str = N'DECLARE #ParmDefinition NVARCHAR(500)
SELECT * FROM #FeeType' --This is where I want to use the variable
DECLARE #ParamDefinition nvarchar(max)
SET #ParamDefinition = N'#OUTPUT NVARCHAR(MAX) OUTPUT'
EXEC sp_executesql #exec_str, #ParamDefinition
Can someone please tell me how to do it?
Thanks
In SQL Server Identifiers can't be parameterized.
Since you are using dynamic SQL anyway, you can do something like this:
SET #exec_str= N'Select * from '+ #FeeType
EXEC(#exec_str)
However, this is vulnerable to SQL injection attacks. To reduce the risk to minimum you should check first that such a table name exists, and I would also use quotename just to be on the safe side:
IF EXISTS
(
SELECT 1
FROM Information_Schema.Tables
WHERE TABLE_NAME = #FeeType
)
BEGIN
SET #exec_str= N'Select * from '+ QUOTENAME(#FeeType)
EXEC(#exec_str)
END