Is it possible to replace a whole table by a parameter?
I would like to write a statement which looks like this:
declare #tab as nvarchar(100);
set #tab = 'dbo.tblCostCenters';
select * from #tab;
However, this does not work.
So the only other way I know so far is to create dynamic SQL. But this then is subject to SQL Injections. Is there possibly a better solution ?
Yes, you can do it. It is a bad idea.
DECLARE #sql nvarchar(max)
SELECT #sql =
'SELECT * FROM '
+ ISNULL(QUOTENAME(PARSENAME(#tab,2))+'.','')
+ QUOTENAME(PARSENAME(#tab,1))
WHERE OBJECT_ID(#tab,'U') IS NOT NULL
EXEC sp_executesql #sql
Related
sorry I am uploading a pic of my query as I dont know to format my text...as a newbie its confusing.
So you want to execute:
select * from File_20170703 -- where your table name is a variable.
It is not possible to use variables for table or column names, what you need to do is to build a dynamic sql and execute it using sp_executesql.
here is an example:
DECLARE #sql nvarchar(4000)
SELECT #sql = 'SELECT * FROM File_20170703'
EXEC sp_executesql #sql
More info about dynamic sql
A simple TSQL "dynamic sql" looks like this:
DECLARE #file_name AS VARCHAR(100)
DECLARE #query AS VARCHAR(MAX)
SET #file_name = 'file_20170101'
SET #query = 'SELECT * FROM ' + #file_name
execute(#query)
Basically you need to create a valid sql query by concatenating various parts of the query together, then you can execute that whole big string as your query.
You can use SQL Cursor along with while loop. Examples are given here:
https://learn.microsoft.com/en-us/sql/t-sql/language-elements/while-transact-sql
can I go like this
USE SELECT databasename from databasenametable
or something similar?
rather than do the select and then put the value in the use satement? I tried brackets around the select and that didnt work. the above didnt work either. i wouldnt know what else to do
If you are using SQL Server, USE statement should get an explicit value for database name:
USE [databasename]
If you insist of doing this dynamically, you can use Dynamic Sql:
DECLARE #db AS NVARCHAR(258);
SET #db = QUOTENAME(N'Pubs'); -- put whatever you want here..
EXEC(N'USE ' + #db);
GO
If you only need to execute one statement in another database, another alternative might be something like :
declare #sql nvarchar(500)
declare #yourDatabaseName nvarchar(50) = 'junk'
declare #yourQuery NVARCHAR(200) = 'select * from someTable'
set #sql = #yourDatabaseName + '..sp_executesql N''' + #yourQuery + ''''
EXEC (#sql)
Can I pass a variable to a SELECT statement?
I keep getting an error message saying I need to declare it.
However, it is declared.
SELECT (list of columns)
FROM #database_table
You are looking to use Dynamic SQL to perform this type of query.
The Curse and Blessings of Dynamic SQL
Here is a quick sample
declare #sqlstatement nvarchar(4000)
declare #table sysname
set #table = 'yourTableName'
set #sqlstatement = 'SELECT * FROM ' + QUOTENAME(#table)
exec(#sqlstatement)
Yes, use dynamic sql statements to build your select statement.
-- Procedure input parameters
#TableName varchar(50)
-- Query guts
Declare #sql varchar(2000)
Set #sql = 'Select columnname from ' + #TableName
exec (#sql)
The one time you can do what you want is when you use table variables. You have to define the variables as:
declare #name table (<column list>)
This is alternative method of declaring a temporary table.
Other than this, I fully agree with bluefeet. You should read the link he posted.
I have created a Temp table(#TempTable). I am trying to insert the date to get but I am getting an error. It's a dynamic query.
I am trying to get the date from another table and inserting the date to temp table
Just to make sure you understand the problem I have given an example
DECLARE #OfferEndDateTime datetime
SELECT #OfferEndDateTime = getdate()-1
print #VOfferEndDateTime
DECLARE #SQL VarChar(1000)
SELECT #SQL ='INSERT INTO #TempTable '+
'SELECT D,Points,#OfferEndDateTime '
exec(#sql)
Please Let me know where I am going wrong
You need to use sp_executesql when passing a parameter to dynamic sql
exec sp_executesql #sql, N'#OfferEndDateTime datetime', #OfferEndDateTime=#OfferEndDateTime
You have, at least, three problems:
The variable needs to be outside:
SELECT #SQL ='INSERT INTO #TempTable '+
'SELECT D,Points,' + #OfferEndDateTime
The variable needs to be varchar type or similar
What is D,Points? They are not defined anywhere. If they are varchar values you nead to quote them (use " or '') for that purpose.
If you need to use the parameter like datetime you should use sp_executesql instead. Check HERE for some info on it!
I'm trying to switch the current database with a SQL statement.
I have tried the following, but all attempts failed:
USE #DatabaseName
EXEC sp_sqlexec #Sql -- where #Sql = 'USE [' + #DatabaseName + ']'
To add a little more detail.
EDIT: I would like to perform several things on two separate database, where both are configured with a variable. Something like this:
USE Database1
SELECT * FROM Table1
USE Database2
SELECT * FROM Table2
The problem with the former is that what you're doing is USE 'myDB' rather than USE myDB.
you're passing a string; but USE is looking for an explicit reference.
The latter example works for me.
declare #sql varchar(20)
select #sql = 'USE myDb'
EXEC sp_sqlexec #Sql
-- also works
select #sql = 'USE [myDb]'
EXEC sp_sqlexec #Sql
exec sp_execsql #Sql
The DB change only lasts for the time to complete #sql
http://blog.sqlauthority.com/2007/07/02/sql-server-2005-comparison-sp_executesql-vs-executeexec/
I have the same problem, I overcame it with an ugly -- but useful -- set of GOTOs.
The reason I call the "script runner" before everything is that I want to hide the complexity and ugly approach from any developer that just wants to work with the actual script. At the same time, I can make sure that the script is run in the two (extensible to three and more) databases in the exact same way.
GOTO ScriptRunner
ScriptExecutes:
--------------------ACTUAL SCRIPT--------------------
-------- Will be executed in DB1 and in DB2 ---------
--TODO: Your script right here
------------------ACTUAL SCRIPT ENDS-----------------
GOTO ScriptReturns
ScriptRunner:
USE DB1
GOTO ScriptExecutes
ScriptReturns:
IF (db_name() = 'DB1')
BEGIN
USE DB2
GOTO ScriptExecutes
END
With this approach you get to keep your variables and SQL Server does not freak out if you happen to go over a DECLARE statement twice.
Just wanted to thank KM for his valuable solution.
I implemented it myself to reduce the amount of lines in a shrinkdatabase request on SQLServer.
Here is my SQL request if it can help anyone :
-- Declare the variable to be used
DECLARE #Query varchar (1000)
DECLARE #MyDBN varchar(11);
-- Initializing the #MyDBN variable (possible values : db1, db2, db3, ...)
SET #MyDBN = 'db1';
-- Creating the request to execute
SET #Query='use '+ #MyDBN +'; ALTER DATABASE '+ #MyDBN +' SET RECOVERY SIMPLE WITH NO_WAIT; DBCC SHRINKDATABASE ('+ #MyDBN +', 1, TRUNCATEONLY); ALTER DATABASE '+ #MyDBN +' SET RECOVERY FULL WITH NO_WAIT'
--
EXEC (#Query)
try this:
DECLARE #Query varchar(1000)
DECLARE #DatabaseName varchar(500)
SET #DatabaseName='xyz'
SET #Query='SELECT * FROM Server.'+#DatabaseName+'.Owner.Table1'
EXEC (#Query)
SET #DatabaseName='abc'
SET #Query='SELECT * FROM Server.'+#DatabaseName+'.Owner.Table2'
EXEC (#Query)
I case that someone need a solution for this, this is one:
if you use a dynamic USE statement all your query need to be dynamic, because it need to be everything in the same context.
You can try with SYNONYM, is basically an ALIAS to a specific Table, this SYNONYM is inserted into the sys.synonyms table so you have access to it from any context
Look this static statement:
CREATE SYNONYM MASTER_SCHEMACOLUMNS FOR Master.INFORMATION_SCHEMA.COLUMNS
SELECT * FROM MASTER_SCHEMACOLUMNS
Now dynamic:
DECLARE #SQL VARCHAR(200)
DECLARE #CATALOG VARCHAR(200) = 'Master'
IF EXISTS(SELECT * FROM sys.synonyms s WHERE s.name = 'CURRENT_SCHEMACOLUMNS')
BEGIN
DROP SYNONYM CURRENT_SCHEMACOLUMNS
END
SELECT #SQL = 'CREATE SYNONYM CURRENT_SCHEMACOLUMNS FOR '+ #CATALOG +'.INFORMATION_SCHEMA.COLUMNS';
EXEC sp_sqlexec #SQL
--Your not dynamic Code
SELECT * FROM CURRENT_SCHEMACOLUMNS
Now just change the value of #CATALOG and you will be able to list the same table but from different catalog.
If SQLCMD is an option, it supports scripting variables above and beyond what straight T-SQL can do. For example: http://msdn.microsoft.com/en-us/library/ms188714.aspx
You can do this:
Declare #dbName nvarchar(max);
SET #dbName = 'TESTDB';
Declare #SQL nvarchar(max);
select #SQL = 'USE ' + #dbName +'; {can put command(s) here}';
EXEC (#SQL);
{but not here!}
This means you can do a recursive select like the following:
Declare #dbName nvarchar(max);
SET #dbName = 'TESTDB';
Declare #SQL nvarchar(max);
SELECT #SQL = 'USE ' + #dbName + '; ' +(Select ... {query here}
For XML Path(''),Type)
.value('text()[1]','nvarchar(max)');
Exec (#SQL)
Use exec sp_execsql #Sql
Example
DECLARE #sql as nvarchar(100)
DECLARE #paraDOB datetime
SET #paraDOB = '1/1/1981'
SET #sql=N'SELECT * FROM EmpMast WHERE DOB >= #paraDOB'
exec sp_executesql #sql,N'#paraDOB datetime',#paraDOB
-- If you are using a variable for the database name.
-- Try something like this.
DECLARE #DBName varchar(50)
Set #DBName = 'Database1'; /* could be passed in by a parameter. */
IF( #DBName = 'Database1')
Begin
USE [Database1];
SELECT FROM Table1;
End
IF( #DBName = 'Database2')
Begin
USE [Database2];
SELECT FROM Table2;
End
IF( #DBName is null)
Begin
USE [Database1];
End