Using a Database Name as a Variable - sql

I'm using this method (How to use a variable for the database name in T-SQL?) to pass a DBname into a variable. This variable is then used with something like this (simplified):
Select column From #DBname
However, when executed...You get, Command(s) completed successfully
Is there a way to adapt this method so that you can see the results of a query? (Not just create or alter a DB)

Something like this should work for you.
[[put code here that sets up #DBname]]
DECLARE #stmt NVARCHAR(MAX) = 'SELECT column FROM ' + #DBname;
EXEC sp_ExecuteSQL #stmt;
Edit: Note that I'm assuming you're using SQL server (you didn't specify in the question).

Related

sql server - fill results from executed query string in a temp table dynamically

I'm writing a stored procedure. I have a string which contains an sql query. For example:
DECLARE #sql nvarchar(max)
SET #sql = (N'SELECT pkOrderID FROM Orders')
(Just to note: this isn't what the select statement looks like. This is just an example of what I mean) I then want to execute the string and put the result in a temporary table E.g. #tempTable. I know EXEC(#sql) exists but not sure if it will do me any good in this situation. The other twist is that I do not know the names of all the columns in the returned #sql so the temp table #tempTable needs to be created dyanmically based off the return from #sql. Thanks for any help.
I think you could use SELECT INTO to do what you want but it would mean updating your string:
DECLARE #sql nvarchar(max)
SET #sql = (N'SELECT frompkOrderID INTO #tmporders FROM Orders')
then you should be able to run EXEC #sql to create the table
more information about SELECT INTO here : http://msdn.microsoft.com/en-au/library/ms188029.aspx
There is no simple way to do this. The problem with #JanR's solution is that the #tmporders table will be out of scope to the script that calls your stored procedure (ie It will produce an error like "Invalid object name '#rtmporders'"
One alternative is to use a global temp table (eg ##tmporders).
So your SP might look like this:
CREATE PROCEDURE TestSP
AS
BEGIN
SELECT pkOrderID INTO ##tmporders FROM Orders
END
GO
And the calling script might be like:
EXEC TestSP
SELECT * FROM ##temporders

Select from table with current user's schema

I am working in a database where each user has a table in their schema called FindResults
eg: MyDatabase.User1.FindResults, MyDatabase.User2.FindResults, etc.
If I run a SELECT query on this table while logged in as one of the users it works just fine. However, I have a stored procedure (MyDatabase.dbo.ReadFindResults) that tries to run a SELECT query on this table, it fails because it tries to read MyDatabase.dbo.FindResults (does not exist). I have gotten around this by using dynamic SQL, but I was hoping there was a way to avoid this.
Is there a way to tell the stored procedure to use the current user's schema or perhaps something to change the scope to allow it to find the table I want?
EDIT: Here is the code for the stored procedure
-- Returns the IDs contained in the given find results set
CREATE PROCEDURE [dbo].[ReadFindResults]
#resultsid int -- The ID of the results set
AS
BEGIN
SELECT objectid FROM FindResults WHERE resultsid = #resultsid
END
GO
In your stored procedure you can say:
SELECT cols FROM MyDatabase..FindResults;
(Leaving out the schema name.)
However this seems very error-prone, and IMHO you should either have separate, schema-bound stored procedures as well, or a single table with a column to indicate whose row it is.
A hack could be to execute as the username:
DECLARE #sql NVARCHAR(255) = N'EXECUTE AS USER = N''' + SUSER_SNAME() + '''';
EXEC sp_executesql #sql;
SELECT whatever FROM Findresults;
But I haven't had the opportunity to test this (you're better equipped to test in your scenario anyway).
It still seems like a remarkably avoidable problem in the first place, but maybe that's just me.
You could use dynamic SQL like this:
DECLARE #sql NVARCHAR(1024) = "SELECT something FROM [userName].someTable"
DECLARE #userName NVARCHAR(255) = SUSER_SNAME()
SET #sql = REPLACE(#sql, "[userName]", #userName)
EXEC sp_executesql #sql
That too is a hakish way of doing that query. More reading about dynamic SQL here: http://www.sommarskog.se/dynamic_sql.html
Im at home right now and do not have access to a SQL Server. I will edit my post in the morning when Im at work if needed.

SQL: Select dynamic column name based on variable

I have a Microsoft SQL stored procedure whose column name I want to set via a variable that is passed into it:
CREATE PROCEDURE [My_Procedure]
#myDynamicColumn varchar(50)
AS BEGIN
SELECT 'value' AS #myDynamicColumn
END
This does not work ("Incorrect syntax"). If I wrap the column name with [ ]:
SELECT 'value' AS [#myDynamicColumn]
The column name literally outputs as '#myDynamicColumn' instead of the actual value. Is there any way to do this? I've looked into dynamic SQL articles but nothing is quite what I'm asking for.
EXEC ('SELECT ''value'' AS ' + #myDynamicColumn)
You could build your query into a string and use exec
CREATE PROCEDURE [My_Procedure]
#myDynamicColumn varchar(50)
AS BEGIN
EXEC('SELECT ''value'' AS ' + #myDynamicColumn)
END
Both the upvoted answers are very dangerous here, both are wide open to injection attacks and should not be used.
When injecting dynamic object names you must ensure you properly quote your object names. SQL Server has a built in function for that, QUOTENAME. Thus what you should actually be doing is the following:
CREATE PROCEDURE [My_Procedure] #myDynamicColumn sysname
AS BEGIN
DECLARE #SQL nvarchar(MAX) = N'SELECT ''value'' AS ' + QUOTENAME(#myDynamicColumn) + N';';
EXEC sys.sp_executesql #SQL;
END
You'll note I also change the data type of the parameter to sysname, a synonym for nvarchar(128) NOT NULL, which is the data type SQL Server uses internally for object names.

In SQL Server, how do I create a reference variable to a table?

I'm currently using sp_executesql to execute a T-SQL statement with a dynamic table name. However, it is really ugly to see something like:
set #sql = 'UPDATE '+Table_Name+' SET ... WHERE '+someVar+' = ... AND '+someVar2' = ...'
sp_executesql #sql
What I would rather like to have is a TABLE variable of which is a reference to a table, so I could do for example:
UPDATE TableRef SET ... WHERE ...
Because when I have really long T-SQL statements it gets really hard to read due to the format of it within a string.
Any suggestions would be helpful.
Why don't you pass the parameters to sp_executeSQL instead?
http://msdn.microsoft.com/en-us/library/ms188001.aspx
I'd also have a read of this article too http://www.sommarskog.se/dynamic_sql.html
You can't. If you want to use a dynamic table name in your SQL, you have to concatenate it into your string.
If you have a lot of references to the table name within your query, you can shorten it by aliasing the table name, and for all other instances, use the alias.
e.g.
SET #SQL = 'UPDATE t SET.... FROM ' + #TableName + ' t WHERE ....'
Just be very very careful when using dynamic SQL like this. Make sure you guard yourself against SQL injection.

Using Parameter Values In SQL Statement

I am trying to write a database script (SQL Server 2008) which will copy information from database tables on one server to corresponding tables in another database on a different server.
I have read that the correct way to do this is to use a sql statement in a format similar to the following:
INSERT INTO <linked_server>.<database>.<owner>.<table_name> SELECT * FROM <linked_server>.<database>.<owner>.<table_name>
As there will be several tables being copied, I would like to declare variables at the top of the script to allow the user to specify the names of each server and database that are to be used. These could then be used throughout the script. However, I am not sure how to use the variable values in the actual SQL statements. What I want to achieve is something like the following:
DECLARE #SERVER_FROM AS NVARCHAR(50) = 'ServerFrom'
DECLARE #DATABASE_FROM AS NVARCHAR(50) = 'DatabaseTo'
DECLARE #SERVER_TO AS NVARCHAR(50) = 'ServerTo'
DECLARE #DATABASE_TO AS NVARCHAR(50) = 'DatabaseTo'
INSERT INTO #SERVER_TO.#DATABASE_TO.dbo.TableName SELECT * FROM #SERVER_FROM.#DATABASE_FROM.dbo.TableName
...
How should I use the # variables in this code in order for it to work correctly?
Additionally, do you think my method above is correct for what I am trying to achieve and should I be using NVARCHAR(50) as my variable type or something else?
Thanks
There is probably a better way to do this, but what you are probably trying to do in your example is what's called dynamic SQL where you treat the statement as a string and the execute it. This would be section #2 here:
http://www.mssqltips.com/tip.asp?tip=1160
There are some major downsides to dynamic SQL. You see a couple other approaches that might be better in that article.
If you want to execute a dynamically generated query then you have to use sp_ExecuteSQL
HTH
For the nvarchar(50) - you'd be better using sysname. This is a synonym in SQL Server (for nvarchar(128)) and represents the maximum length of an object identifier.
have a look at http://msdn.microsoft.com/en-us/library/ms188001.aspx - sp_executesql takes a parameter that is a string and executes the sql in that string. so you'd need to concatenate #SERVER_FROM and other params with the INSERT INTO part to make the entire sql statement, and then pass to sp_executesql.
nvarchar(50) is fine, unless your server/database names are longer than that :)
You can create the select statement by concatenating all the information together and then use sp_executesql
so:
sp_executesql 'INSERT INTO ' + #SERVER_TO + '.' + #DATABASE_TO +
'.dbo.TableName SELECT * FROM ' + #SERVER_FROM + '.' +
#DATABASE_FROM+'.dbo.TableName'
I like to make templates for dynamic SQL things like this - it's a lot easier to maintain complex statements and also sometimes easier to handle nested quotes - and definitely easier when terms need to be repeated in multiple places (like column lists):
DECLARE #sql AS nvarchar(max);
SET #sql = 'INSERT INTO {#SERVER_TO}.{#DATABASE_TO}.dbo.TableName
SELECT *
FROM {#SERVER_FROM}.{#DATABASE_FROM}.dbo.TableName'
SET #sql = REPLACE(#sql, '{#SERVER_TO}', QUOTENAME(#SERVER_TO))
SET #sql = REPLACE(#sql, '{#DATABASE_TO}', QUOTENAME(#DATABASE_TO))
SET #sql = REPLACE(#sql, '{#SERVER_FROM}', QUOTENAME(#SERVER_FROM))
SET #sql = REPLACE(#sql, '{#DATABASE_FROM}', QUOTENAME(#DATABASE_FROM))
EXEC(#sql)