SQL OpenQuery variable tablename - sql

I need to transfer data from a linked server to our main SQL server. The issue is, that the table name changes everyday.
I have looked around this site to find out if it is even possible to have a variable database name, which it is, but also to see if it is possible to have variables in a OPENQUERY, which it also is.
But i am struggling to combine those needs, so i have a variable table name in a OPENQUERY.
I need something like this:
Declare #LinkedServer as varchar(max) = 'LinkedServer'
Declare #TName as varchar(max) = 'TName'+substring(cast(cast(getdate() as date) as
varchar(50)),1,4)+substring(cast(cast(getdate() as date) as
varchar(50)),6,2)+substring(cast(cast(getdate() as date) as
varchar(50)),9,2)
SELECT * FROM OPENQUERY(#LinkedServer, 'SELECT * FROM dbo.#TName')
Is there any way i can make a variable table name in a OPENQUERY ?
Thank you for your help.
/Mikkel

I'd write a synonym which gets updated every day before you kick off your data extraction job. Then you don't need to be updating (potentially a tonne of) references.
CREATE SYNONYM LinkedTableA
FOR
ServerName.DBName.dbo.TName20170331
SELECT * FROM LinkedTableA

The answer i have, is this:
USE [DataBase]
GO
DROP SYNONYM [dbo].[eCallByCallStat]
GO
declare #tablename varchar(50)
set #tablename = 'Server1..dbo.eCallByCallStat'+substring(cast(cast(getdate()-1 as date) as varchar(50)),1,4)+substring(cast(cast(getdate()-1 as date) as varchar(50)),6,2)+substring(cast(cast(getdate()-1 as date) as varchar(50)),9,2)
declare #sql varchar(500)
set #sql = 'CREATE SYNONYM [dbo].[eCallByCallStat] FOR ' + #tablename
exec (#sql)
This will run everymorning updating the table name in the synonym, and then we will insert that data into a prober table so we have all the data.

Related

How to use a variable in "Select [some calculations] insert into #NameOfTheTableInThisVariable"?

I have a procedure in which there are calculations being done and the final result is inserted into a permanent table. I want to remove the permanent table and I cannot use Temp table as well. So i want to use a dynamic table name, which is stored in a variable:
Current scenario:
Insert into xyz_table
Select col1,col2,sum(col3)
from BaseTable
(In reality, there are lot of columns and a lot of calculations)
What I want:
Select col1,col2,sum(col3) into #DynamicTableName
from BaseTable
where the name of the table would be dynamic in nature i.e.,
#DynamicTableName = 'xyz ' + cast(convert(date,getdate()) as nvarchar)+' '+convert(nvarchar(5),getdate(),108)
It will have date and time in its name every time the procedure is run.
I want to use this name in the "Select * into statement"
How can I achieve this?
i tried it with the some short code. But since my procedure has a lot of calculations and UNIONS , I cannot use that code for this. Any help would be appreciated.
declare #tablename nvarchar(30)= 'xyz ' + cast(convert(date,getdate()) as nvarchar)+' '+convert(nvarchar(5),getdate(),108)
declare #SQL_Statement nvarchar(100)
declare #SQL_Statement2 nvarchar(100)
declare #dropstatement nvarchar(100)
SET #SQL_Statement = N'SELECT * Into ' +'['+#tablename +'] '+'FROM '+ 'dimBranch'
print #SQL_Statement
EXECUTE sp_executesql #SQL_Statement
SET #SQL_Statement= N'select * from ' + '['+#tablename + '] '
print #SQL_Statement
EXECUTE sp_executesql #SQL_Statement
set #dropstatement = 'DROP TABLE' + '['+#tablename + '] '
PRINT #dropstatement
exec sp_executesql #dropstatement
Reason why I want this is because I use this procedure in ETL job as well as in SSRS report. And if someone runs the package and the SSRS report at the same time, the incorrect or weird data gets stored in the table. Therefore I need a dynamic name of the table with date and time.
You can't parameterize an identifier in SQL, only a value
--yes
select * from table where column = #value
--no
select * from #tablename where #columnname = #value
The only thin you can do to make these things dynamic is to build an sql string and execute it dynamically, but your code is already doing this with sp_executesql
More telling is your complaint at the bottom of your question, that if the procedure is invoked simultaneously it gives problems. Perhaps you should consider using local table variables for temporary data storage that the report is using rather than pushing data back into the db
DECLARE #temp TABLE(id INT, name varchar100);
INSERT INTO #temp SELECT personid, firstname FROM person;
-- work with temp data
select count(*) from #temp;
--when #temp goes out of scope it is lost,
--no other procedure invoked simultaneously can access this procedure'a #temp
Consider a local temp table, which is automatically session scoped without the need for dynamic SQL. For example:
SELECT *
INTO #YourTempTable
FROM dimBranch;
The local temp table will automatically be dropped when the proc completes so there is no need for an explict drop in the proc code.

How to dynamically create and populate a local temp table (when the table headers are unknown)?

I am currently using code similar to the following:
SET #Query = 'SELECT * INTO #Temp FROM MyTable'
EXEC sp_executesql #Query
Obviously, this does not work. Until now, I have been getting around this problem by using global temporary tables within my dynamic sql. However, this is not an option once the stored procedure is released to users, as their global temp tables would conflict with one another.
How might I get around this issue? I must specify that the structure of the table MyTable is unknown, so creating the temp table outside of the dynamic sql is (presumably?) not an option.
Edit: Apologies if I was not specific enough with exactly what I am trying to achieve - I thought it would be best to keep this question as relevent to the actual issue as possible.
Obviously, the string that I am trying to execute is not fixed. It is instead constructed so that the table, from which the data is being retrieved, may be specified. Although still not overly complex, the actual query string that I am using is more along the lines of
#Query = CONCAT('SELECT * INTO #Temp FROM ', #Environment, '.[schema].', #Table)
Hopefully this sheds more light on the problem?
Few points:
1. If you want to store the output of dynamic sql into temp table, you need to create the temp table structure first(with CREATE TABLE #TEMP script) and then you can insert data by doing something like below:
INSERT INTO #TEMP EXEC sp_executesql #Query
This will populate data into temp table with all properties of local temp table.
Seeing your query, it does not look like you have a need of dynamic sql unless you are forming some clause like where clause dynamically.
Let me know if this helps.
Couldn't you do something like this:
declare #query nvarchar(4000) = '
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''[dbo].[temp]'') AND type in (N''U''))
begin
drop table temp
end
Select top 2 *
into temp
from sys.databases
'
exec sp_executesql #query
Select * from temp
With Select into you don't need to know the structure of your query:
https://www.w3schools.com/sql/sql_select_into.asp
Just as an idea.

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

Creating a dynamic table from dynamic SQL

First of all I'm using ms SQL server 2012. I' trying to use a table based on a string value passed in as a string into a procedure. I found out that you can't use strings are table names when writing a query so I'm trying to find a way around that. The only lead I'm kind of onto is using dynamic SQL which I also am not sure how to make work. Here is what I have:
DECLARE #q AS NVARCHAR(MAX)
SET #q = 'SELECT * FROM ' + #tableName
DECLARE #tableCopy AS EXECUTE(#q)
How can I get the executed #q into #tableCopy? Or is there a better way to access my table when all I know is the tables name as a string?
You can create the temporary table and then insert into that table inside the dynamic sql. There's an example here:
http://smehrozalam.wordpress.com/2009/10/14/t-sql-using-result-of-a-dynamic-sql-query-in-a-variable-or-table/
Unfortunately, you would need to know the schema. The following does not work:
declare #query varchar(max) =
'select * into #t from table'
EXEC(#query)
select * FROM #t

How can I spot in what database is a stored procedure with name 'myStoredProcedure'?

There are bunch of databases to the SQL server I am connected.
How should I query the sysobjects in order to spot in what database a stored procedure with name 'myStoredProcedure' is located ?
The query should return the database name.
Thanks
I know you are not asking for this, but I'd really download RedGate's Sql Search add-in for SSMS and use that. It allows you to find any object (proc, table, view, column, etc) on any database easily.
And it's free!
I'd give this a try:
CREATE TABLE ##DatabaseList
(
DatabaseName varchar(50)
)
EXECUTE SP_MSForEachDB 'USE [?]; INSERT INTO ##DatabaseList SELECT DB_NAME() FROM [sys].[objects] WHERE name = "MyStoredProcedure" AND type_desc = "SQL_STORED_PROCEDURE"'
SELECT * FROM ##DatabaseList
DROP TABLE ##DatabaseList
That's using the undocumented/ unsupported system stored procedure SP_MSForEachDb and writing any hits to a global temp table, then outputting the contents to the Results window before dropping the table. If you just need to know which database (or databases - there may of course be more than one) has an appropriately named SP, this should do it. If you want to use the output elsewhere as a parameter, it may take a little more work.
By the way, I'm only learning this stuff myself over the last few months so if anyone can critique the above and suggest a better way to go at it I'm happy to receive feedback. Equally, I can answer any further questions posted here to the best of my ability.
Cheers
So out of curiosity I decided to try write this myself, especially since ADG mentioned his solution was using an unsupported, undocumented procedure. This could also be expanded to take a 2nd parameter so where it checks the type = P (stored Proc) you could probably change it to look for other things like views / tables etc.
My solution is a bit long but here goes:
CREATE PROCEDURE spFindProceduresInDatabases
(
#ProcedureName NVARCHAR(99)
)
AS
BEGIN
-- Get all the database names and put them into a table
DECLARE #Db TABLE (DatabaseName Varchar(99))
INSERT INTO #Db SELECT name FROM Sys.databases
-- Declare a table to hold our results
DECLARE #results TABLE (DatabaseName VARCHAR(99))
-- Make a Loop
-- Declare a variable to be incremented
DECLARE #count INT
SET #count = 0
-- Declare the end condition
DECLARE #endCount INT
SELECT #endCount = COUNT(*) FROM #Db
-- Loop through the databases
WHILE (#count < #endCount )
BEGIN
-- Get the database we are going to look into
DECLARE #dbWeAreChecking VARCHAR(99)
SELECT TOP 1 #dbWeAreChecking = DatabaseName FROM #Db
DELETE FROM #Db WHERE DatabaseName = #dbWeAreChecking
-- Create and execute our query
DECLARE #Query NVARCHAR(3000)
SET #Query = N'SELECT #outParam = COUNT(*) FROM '+#dbWeAreChecking+'.sys.sysobjects WHERE type = ''P'' and name = #ProcedureName'
Declare #outParam INT
print (#Query)
DECLARE #ParmDefinition NVARCHAR(500)
DECLARE #IntVariable INT
SET #ParmDefinition = N'#ProcedureName VARCHAR(99),#outParam INT OUTPUT'
SET #IntVariable = 35
EXECUTE sp_executesql
#Query ,
#ParmDefinition,
#ProcedureName,
#outParam = #outParam OUTPUT
-- If we have a result insert it into the results table
If (#outParam > 0)
BEGIN
INSERT INTO #results(DatabaseName) VALUES(#dbWeAreChecking)
END
-- Increment the counter
SET #count = (#count + 1)
END
-- SELECT ALL OF THE THINGS!!!
SELECT * FROM #results
END