Inserting data into a temp table from an open query - sql-server

I've looked online and you can not drop variables into an open query so easily so I modified my query and it says the #TempOT temp table is "Invalid object name '#TempOT'." What am I doing wrong that is causing the temp table not to get populated?
BEGIN
IF OBJECT_ID('tempdb..#TempOT') IS NOT NULL
BEGIN
DROP TABLE #TempOT
END;
DECLARE #TSQL As varchar(1024)
DECLARE #AS400Query As varchar(1024)
SET #AS400Query = 'SELECT * from blah.blahlibrary.AS400Table where DATETS BETWEEN '+ #BegofMonthForAS400 + ' AND ' + #DateForAS400
SET #TSQL = 'SELECT * FROM OPENQUERY(ISERIES,' + '''' + #AS400Query +'''' + ')'
INSERT INTO #TempOT
EXEC(#TSQL)
END
i have also tried this and it does not work
BEGIN
IF OBJECT_ID('tempdb..#TempOT') IS NOT NULL
BEGIN
DROP TABLE #TempOT
END;
DECLARE #TSQL As varchar(1024)
DECLARE #AS400Query As varchar(1024)
SET #AS400Query = 'SELECT * from valdosta.PRDATA.PRTIMELM where DATETS BETWEEN '+ #BegofMonthForAS400 + ' AND ' + #DateForAS400
SET #TSQL = ' INSERT INTO #TempOT SELECT * FROM OPENQUERY(ISERIES,' + '''' + #AS400Query +'''' + ')'
EXEC(#TSQL)
END

You DROP the TEMP table and then you are trying to INSERT data into it.
You need to create the TEMP table within your script first.

The problem is in fact, that you are creating temporary table within EXEC statement. Created table #TempOT is dropped immediately after batch is executed` and is not visible for your main query. There are at least two possibilities (if you want to use temp tables):
Instead of creating local temporary table, create global temporary table with ## before table name (difference between them is explained here). In my opinion, you should drop this table at the end of your main query.
Create #TempOt with all columns before EXEC statement where you will be able without problem to populate table #TempOt with desired data.

Related

Global temporary table scope behaves differently inside a stored procedure

The following code executes successfully, unless I add create procedure dbo.proc_name ... as to it:
use db_name
go
declare #sp_date date;
select #sp_date = getdate();
if object_id('tempdb..##global_tmp_tbl') is not null drop table ##global_tmp_tbl;
begin transaction
set xact_abort on
declare #query varchar(250), #exec_stmnt varchar(500);
set #query = 'exec remote_db.dbo.remote_sp' + ' ''''' + cast(#sp_date as varchar(10)) + ''''' ';
set #query = '''' + #query + '''';
set #exec_stmnt = 'select * into ##global_tmp_tbl from openquery(LS_RMT,' + #query + ')';
exec (#exec_stmnt);
commit transaction
go
if object_id('tempdb..#local_tmp_tbl') is not null drop table #local_tmp_tbl;
select * into #local_tmp_tbl from ##global_tmp_tbl;
Here LS_RMT is a linked server, and remote_sp is a stored procedure on the database remote_db on that linked server.
When I try to put this code into a stored procedure, SQL Server complains that ##global_tmp_tbl is an invalid name when trying to read from it after executing the stored procedure on the linked server which loads it.
I'm guessing that the scope of the global temporary table changes once within the context of a stored procedure, but I can't find any documentation on why that might be the case so I'm not sure.
Is this a scope issue, or is it actually possible to use the global temporary table within a stored procedure after it has been created inside a transaction that loads it from an openquery statement and I am just doing it wrong?
Although I am not entirely sure why the code above works when outside the context of a stored procedure, I did determine that embedding all references to the global temporary table within the committed transaction allowed the stored procedure to work. So something like the following:
use db_name
go
create procedure dbo.proc_name
#sp_date date = NULL
as
if isnull(#sp_date,'') = ''
begin
select #sp_date = getdate();
end
if object_id('tempdb..##global_tmp_tbl') is not null drop table ##global_tmp_tbl;
begin transaction
set xact_abort on
declare #query varchar(250), #exec_stmnt varchar(500);
set #query = 'exec remote_db.dbo.remote_sp' + ' ''''' + cast(#sp_date as varchar(10)) + ''''' ';
set #query = '''' + #query + '''';
set #exec_stmnt = 'select * into ##global_tmp_tbl from openquery(LS_RMT,' + #query + ')';
exec (#exec_stmnt);
if object_id('tempdb..#local_tmp_tbl') is not null drop table #local_tmp_tbl;
select * into #local_tmp_tbl from ##global_tmp_tbl;
commit transaction
go

How to create duplicate tables with 'similar' names of a column of a table?

I have a table that contains the names of tables.
The structure is the following:
table_name
dbo.2017_10_8
dbo.2017_10_19
dbo.2017_10_30
dbo.2017_11_10
dbo.2017_11_21
dbo.2017_12_2
dbo.2017_12_13
dbo.2017_12_24
dbo.2018_1_4
dbo.2018_1_15
dbo.2018_1_26
dbo.2018_2_6
dbo.2018_2_17
dbo.2018_3_11
dbo.2018_2_28
I would like to create tables that have name of table like
dbo.2017_10_8_cs
dbo.2017_10_19_cs
dbo.2017_10_30_cs
dbo.2017_11_10_cs
dbo.2017_11_21_cs
dbo.2017_12_2_cs
dbo.2017_12_13_cs
dbo.2017_12_24_cs
dbo.2018_1_4_cs
dbo.2018_1_15_cs
dbo.2018_1_26_cs
dbo.2018_2_6_cs
dbo.2018_2_17_cs
dbo.2018_3_11_cs
dbo.2018_2_28_cs
I know that if for example t contains the first block of values.
I can just
select table_name + '_cs' from t
and then I have the names in the format I want, but how can I create all tables with the name of the table having the second block of values? Thank you in advance
You can use a CURSOR to cycle each table.
DECLARE #SourceTableName VARCHAR(100)
DECLARE #DestinationTableName VARCHAR(100)
DECLARE TableNameCursor CURSOR FOR
SELECT
SouceTableName = QUOTENAME(table_name),
DestinationTableName = QUOTENAME(table_name + '_cs')
FROM
t
OPEN TableNameCursor
FETCH NEXT FROM TableNameCursor INTO #SourceTableName, #DestinationTableName
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #DynamicSQLCreate VARCHAR(MAX) = 'SELECT * INTO ' + #DestinationTableName + ' FROM ' + #SourceTableName
DECLARE #DynamicSQLDrop VARCHAR(MAX) = 'DROP TABLE ' + #SourceTableName
EXEC (#DynamicSQLCreate)
EXEC (#DynamicSQLDrop)
FETCH NEXT FROM TableNameCursor INTO #SourceTableName, #DestinationTableName
END
CLOSE TableNameCursor
DEALLOCATE TableNameCursor
Please note that I used SELECT INTO to create your new tables. This command will copy the source table structure and load it with all it's data, but not it's indexes or constraints.
You can switch the EXEC for a PRINT to validate the script before actually executing.
EDIT:
You can use the system stored procedure sp_rename to change the new table to the original one (once dropped). Put this inside the while loop:
DECLARE #DynamicSQLCreate VARCHAR(MAX) = 'SELECT * INTO ' + #DestinationTableName + ' FROM ' + #SourceTableName
DECLARE #DynamicSQLDrop VARCHAR(MAX) = 'DROP TABLE ' + #SourceTableName
DECLARE #DynamicSQLRename VARCHAR(MAX) = 'EXEC sp_rename ' + #DestinationTableName + ' , ' + #SourceTableName
EXEC (#DynamicSQLCreate)
EXEC (#DynamicSQLDrop)
EXEC (#DynamicSQLRename)

Need help. Message says temp table doesn't exist: 'Invalid object name '#TempCodes'.'

If I run the select statement below by itself (with the table name hard coded in) it runs fine and the temp table is created. If I run it as below it says 'Invalid object name '#TempCodes'' although when I print #Sql1 it looks exactly the same as when I run it by itself (with the table name hard coded in).
Any ideas on what's going on here will be appreciated.
DECLARE #TableName NVARCHAR(50)
SET #TableName = '[My Table Name]'
DECLARE #Sql1 NVARCHAR(MAX);
SET #Sql1 = N'SELECT AccountNumber,LTRIM(RTRIM(m.n.value(''.[1]'',''varchar(8000)''))) AS mdcodes INTO #TempCodes FROM (SELECT AccountNumber,CAST(''<XMLRoot><RowData>''
+ REPLACE(MD_Results,'','',''</RowData><RowData>'')
+ ''</RowData></XMLRoot>'' AS XML) AS x FROM ' + #TableName
+ N')t CROSS APPLY x.nodes(''/XMLRoot/RowData'')m(n)'
IF OBJECT_ID('tempdb.dbo.#TempCodes', 'U') IS NOT NULL
BEGIN
drop table #TempCodes
END
EXECUTE sp_executesql #Sql1
Select * from #TempCodes
I believe ## is a typo. Even if you fix it to # it will throw same error.
EXECUTE sp_executesql #Sql1
A local temporary table created in a stored procedure is dropped
automatically when the stored procedure is finished.
In your case sp_executesql is the stored procedure.
the table created inside the dynamic query will be dropped after the exec sp_executesql is completed. That's why you are getting that error.
You need to create table outside and use Insert into table..select syntax inside the dynamic query
IF OBJECT_ID('tempdb.dbo.#TempCodes', 'U') IS NOT NULL
drop table #TempCodes
create table #TempCodes(AccountNumber varchar(100),mdcodes varchar(100))
SET #Sql1 = N'Insert into #TempCodes
SELECT AccountNumber,LTRIM(RTRIM(m.n.value(''.
[1]'',''varchar(8000)''))) AS mdcodes FROM (SELECT
AccountNumber,CAST(''<XMLRoot><RowData>'' +
REPLACE(MD_Results,'','',''</RowData><RowData>'') + ''</RowData></XMLRoot>''
AS XML) AS x FROM '+#TableName+ N')t CROSS APPLY
x.nodes(''/XMLRoot/RowData'')m(n)'
Try using a global temp table ##TempCodes as local temporary tables are only visible in current session.
DECLARE #TableName NVARCHAR(50)
SET #TableName = '[My Table Name]'
DECLARE #Sql1 NVARCHAR(MAX);
SET #Sql1 = N'SELECT AccountNumber,LTRIM(RTRIM(m.n.value(''.
[1]'',''varchar(8000)''))) AS mdcodes INTO ##TempCodes FROM (SELECT
AccountNumber,CAST(''<XMLRoot><RowData>'' +
REPLACE(MD_Results,'','',''</RowData><RowData>'') + ''</RowData></XMLRoot>''
AS XML) AS x FROM '+#TableName+ N')t CROSS APPLY
x.nodes(''/XMLRoot/RowData'')m(n)'
IF OBJECT_ID('tempdb.dbo.##TempCodes', 'U') IS NOT NULL
BEGIN
drop table ##TempCodes
END
EXECUTE sp_executesql #Sql1
Select * from ##TempCodes

Stored Procedure and populating a Temp table from a linked Stored Procedure with parameters

I have a Stored Procedure (SP) in which I pass in one value. In this SP, I am trying to create/populate a Temp Table from the result of another SP that is on a Linked/remote server. That is I am trying to executute an SP in my SP and populate a temp table which my query will use.
I have tried using the following syntax, but it does not work as it seems openquery does not like the "+" or the #param1 parameter.
select * into #tempTable
from openquery([the Linked server],'exec thelinkedSPname ' + #param1)
If I have the parameter value hard coded in this it works fine.
select * into #tempTable
from openquery([the Linked server],'exec thelinkedSPname 2011')
I have also gone as far as manually building the temp table and trying to execute the linked SP but that does not work as well.
create table #tempTable(
.
.
.
)
insert into #tempTable
(
.
.
.
)
Exec [the Linked server],'exec thelinkedSPname ' + #param1
Any suggestions as to how to populate a temp table from within a SP that executes a SP via a linked server. Note the above SQL is only pseudo code
I think you are gonna need dynamic SQL, since you can't pass the parameter to an OPENQUERY like that (but first visit this link) So you would have something like this:
create table #tempTable(
.
)
DECLARE #param1 VARCHAR(10), #Query VARCHAR(8000)
SET #param1 = '2011'
SET #Query = '
SELECT *
FROM OPENQUERY([Linked Server],''exec thelinkedSPname '' + #param1+''')'
INSERT INTO #tempTable
EXEC(#Query)
With the usual disclaimers about guarding dynamic SQL, you can do this without OPENQUERY etc. Just call sp_executesql remotely:
DECLARE #sql NVARCHAR(MAX);
SET #sql = N'EXEC thelinkedSPname ' + #param1 + ';';
INSERT #temptable EXEC [LinkedServerName].database.dbo.sp_executesql #sql;
I use this method quite frequently:
DECLARE #YEAR AS VARCHAR(4) SET #YEAR = 2015
DECLARE #SQL AS VARCHAR(MAX)
DECLARE #OPENQUERY AS VARCHAR(MAX)
DECLARE #LINKEDSERVER AS VARCHAR(MAX) SET #LINKEDSERVER = 'Name of Linked Server here with out brackets'
SET #SQL='
Select
tbl1.*
FROM
dbo.Table_ON_LINKED_SERVER AS tbl1
WHERE
tbl1.number_id = ''''1''''
AND YEAR(tbl1.DATETIME) = ' + #YEAR + '
AND tbl1.NAME <> ''''%JONES%''''
'''
SET #OPENQUERY = 'SELECT * INTO ##GLOBAL_TEMP_NAME FROM OPENQUERY(['+ #LINKEDSERVER +'],''' + #SQL + ')'
--SELECT #OPENQUERY
EXEC(#OPENQUERY)
Two words: Dynamic Query.
Try this:
DECLARE #TSQL varchar(8000)
SELECT #TSQL = 'SELECT * INTO #tempTable FROM OPENQUERY([the Linked server],''exec [the Linked server].DBName.dbo.thelinkedSPname ' + #param1 + ''')'
EXEC (#TSQL)
This is well documented here:
How to pass a variable to a linked server query
With some care you could use a shared temp table:
DECLARE #Qry AS VARCHAR(MAX)
SET #Qry = 'select * into ##tempTable from openquery([the Linked server],''exec thelinkedSPname ' + #param1 + ''')'
EXEC (#Qry)
-- Now just use the shared Temp table, or I suppose you could copy it to a temp table just as you wanted it:
SELECT * INTO #tempTable FROM( SELECT * FROM ##tempTable)tbl
DROP TABLE ##tempTable

Dynamic SQL results into temp table in SQL Stored procedure

The code is as follows:
ALTER PROCEDURE dbo.pdpd_DynamicCall
#SQLString varchar(4096) = null
AS
Begin
create TABLE #T1 ( column_1 varchar(10) , column_2 varchar(100) )
insert into #T1
execute ('execute ' + #SQLString )
select * from #T1
End
The problem is that I want to call different procedures that can give back different columns.
Therefore I would have to define the table #T1 generically.
But I don't know how.
Can anyone help me on this problem?
Try:
SELECT into #T1 execute ('execute ' + #SQLString )
And this smells real bad like an sql injection vulnerability.
correction (per #CarpeDiem's comment):
INSERT into #T1 execute ('execute ' + #SQLString )
also, omit the 'execute' if the sql string is something other than a procedure
You can define a table dynamically just as you are inserting into it dynamically, but the problem is with the scope of temp tables. For example, this code:
DECLARE #sql varchar(max)
SET #sql = 'CREATE TABLE #T1 (Col1 varchar(20))'
EXEC(#sql)
INSERT INTO #T1 (Col1) VALUES ('This will not work.')
SELECT * FROM #T1
will return with the error "Invalid object name '#T1'." This is because the temp table #T1 is created at a "lower level" than the block of executing code. In order to fix, use a global temp table:
DECLARE #sql varchar(max)
SET #sql = 'CREATE TABLE ##T1 (Col1 varchar(20))'
EXEC(#sql)
INSERT INTO ##T1 (Col1) VALUES ('This will work.')
SELECT * FROM ##T1
Hope this helps,
Jesse
Be careful of a global temp table solution as this may fail if two users use the same routine at the same time as a global temp table can be seen by all users...
create a global temp table with a GUID in the name dynamically. Then you can work with it in your code, via dyn sql, without worry that another process calling same sproc will use it. This is useful when you dont know what to expect from the underlying selected table each time it runs so you cannot created a temp table explicitly beforehand. ie - you need to use SELECT * INTO syntax
DECLARE #TmpGlobalTable varchar(255) = 'SomeText_' + convert(varchar(36),NEWID())
-- select #TmpGlobalTable
-- build query
SET #Sql =
'SELECT * INTO [##' + #TmpGlobalTable + '] FROM SomeTable'
EXEC (#Sql)
EXEC ('SELECT * FROM [##' + #TmpGlobalTable + '] ')
EXEC ('DROP TABLE [##' + #TmpGlobalTable + ']')
PRINT 'Dropped Table ' + #TmpGlobalTable
INSERT INTO #TempTable
EXEC(#SelectStatement)
Try Below code for creating temp table dynamically from Stored Procedure Output using T-SQL
declare #ExecutionName varchar(1000) = 'exec [spname] param1,param2 '
declare #sqlStr varchar(max) = ''
declare #tempTableDef nvarchar(max) =
(
SELECT distinct
STUFF(
(
SELECT ','+a.[name]+' '+[system_type_name]
+'
' AS [text()]
FROM sys.dm_exec_describe_first_result_set (#ExecutionName, null, 0) a
ORDER BY a.column_ordinal
FOR XML PATH ('')
), 1, 1, '') tempTableDef
FROM sys.dm_exec_describe_first_result_set (#ExecutionName, null, 0) b
)
IF ISNULL(#tempTableDef ,'') = '' RAISERROR( 'Invalid SP Configuration. At least one column is required in Select list of SP output.',16,1) ;
set #tempTableDef='CREATE TABLE #ResultDef
(
' + REPLACE(#tempTableDef,'
','') +'
)
INSERT INTO #ResultDef
' + #ExecutionName
Select #sqlStr = #tempTableDef +' Select * from #ResultDef '
exec(#sqlStr)
DECLARE #EmpGroup INT =3 ,
#IsActive BIT=1
DECLARE #tblEmpMaster AS TABLE
(EmpCode VARCHAR(20),EmpName VARCHAR(50),EmpAddress VARCHAR(500))
INSERT INTO #tblEmpMaster EXECUTE SPGetEmpList #EmpGroup,#IsActive
SELECT * FROM #tblEmpMaster
CREATE PROCEDURE dbo.pdpd_DynamicCall
AS
DECLARE #SQLString_2 NVARCHAR(4000)
SET NOCOUNT ON
Begin
--- Create global temp table
CREATE TABLE ##T1 ( column_1 varchar(10) , column_2 varchar(100) )
SELECT #SQLString_2 = 'INSERT INTO ##T1( column_1, column_2) SELECT column_1 = "123", column_2 = "MUHAMMAD IMRON"'
SELECT #SQLString_2 = REPLACE(#SQLString_2, '"', '''')
EXEC SP_EXECUTESQL #SQLString_2
--- Test Display records
SELECT * FROM ##T1
--- Drop global temp table
IF OBJECT_ID('tempdb..##T1','u') IS NOT NULL
DROP TABLE ##T1
End
Not sure if I understand well, but maybe you could form the CREATE statement inside a string, then execute that String? That way you could add as many columns as you want.

Resources