When I create a temporary table and insert data into that temporary table through dynamic SQL its work fine. But when I use select * into #TempTable1 from YourTable in dynamic SQL it throw error. I am unable to understand the cause of this error.
Table:
create table YourTable(Id int identity(1,1),Col1 varchar(100));
insert into YourTable(Col1)
values('Stack'),('Over'),('Flow')
Working Code:-
Declare #SqlStr varchar(max)
create table #TempTable(Id int identity(1,1),Col1 varchar(100))
set #SqlStr='Insert into #TempTable(Col1) select Col1 from YourTable'
exec(#SqlStr)
select * from #TempTable
Not Working Code:
Declare #SqlStr varchar(max)
set #SqlStr='select * into #TempTable1 from YourTable'
exec(#SqlStr)
select * from #TempTable1
Error:
Msg 208 Level 16 State 0 Line 4
Invalid object name '#TempTable1'.
For Reference data is here.
The cause of this error is that a temp table is session bound and your dynamic SQL runs in a separate session.
Use a global temp table (prefix: ##) and make this one unique by naming (i.e. add a guid to the name). This way the dynamic SQL can see it.
Different types temporary tables: http://www.sqlines.com/articles/sql-server/local_and_global_temporary_tables
Related
I have a user-defined table type tyAnalysisNumbers. I need to populate my user defined data type within a stored procedure with a SELECT statement and I am struggling to get that working within my stored procedure.
The following ways I have tried do not work
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM ' + #someTable);
I get this error:
An INSERT EXEC statement cannot be nested
I am unsure how to insert into my custom table via a select statement.
Can anyone help me accomplish this?
An INSERT EXEC statement cannot be nested
Above error is self explanatory. Please look at below scenario:
For example, we have one procedure which inserts data in table type and return result.
CREATE PROCEDURE uspInsertData1
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM someTable');
select * from #MyTable
END
Now, let's say we have another procedure which will call above procedure and again insert data in another table.
CREATE PROCEDURE uspInsertData2
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO sometable
EXEC uspInsertData1
END
Now, if you execute 1st procedure it will work fine but if you execute second procedure you will get this error.
An INSERT EXEC statement cannot be nested.
Because now you have nested EXEC statements.
I suggest to finish your work in single stored procedure if possible.
Try it like this:
DECLARE #MyTable tyAnalysisNumbers;
SELECT * INTO #Temp FROM #MyTable;
DECLARE #tblName AS SYSNAME = (SELECT name FROM sys.tables WHERE name = #someTable);
EXEC ('INSERT INTO #Temp SELECT * FROM ' + #tblName);
This also addresses the SQL Injection problem.
I have a stored procedure in other database which is maintained by other team. Assume that it is currently returning 3 columns, and my system only needs those 3 columns
but the other team can add few more columns for their own use which is causing my system to fail.
Other database SP
ALTER PROCEDURE FirstSP
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #A (Id INT, Name VARCHAR(200), Amount VARCHAR(100), TestColumn INT)
INSERT INTO #A VALUES
(1,'ABC','23',1), (2,'CDF','35454',2), (3,'hjhj','9809909',3)
SELECT * FROM #A
DROP TABLE #A
END
GO
And below is my query, which was only expecting 3 columns from the source
CREATE TABLE #MyTable (Id INT, Name VARCHAR(200), Amount INT)
INSERT INTO #MyTable
EXEC dbo.FirstSP;
SELECT * FROM #MyTable
DROP TABLE #MyTable
Is there any way I can provide the column list?
This is what I am trying but it seems that I can't use server name as the parameter
DECLARE #ServerName VARCHAR(100) = ##SERVERNAME
SELECT * FROM OPENQUERY(#ServerName,'EXEC dbo.FirstSP')
My whole problem is to just select required columns from the SP. SP can have many columns in future.
Try this:
/*
-----------------------------------------------------------------------
Replace <SERVERNAME>\<INSTANCENAME>], <DATABASENAME> with your names
*/ ------------------------------------------------------------------------
-- First, enable Data Access (One time only)
EXEC sp_serveroption '<SERVERNAME>\<INSTANCENAME>', 'DATA ACCESS', TRUE;
-- Then SELECT just the fields you need
SELECT ID, Name, Amount
FROM OPENQUERY([<SERVERNAME>\<INSTANCENAME>], 'EXEC <DATABASENAME>.dbo.FirstSP')
I would ask the team that develops the stored procedure to create a parameter "Team" or something and slightly change the sp so that it will return the expected columns based on this parameter.
A more cumbersome solution is to use this stored procedure the get the colum names of the (first) result returned by the sp.
sp_describe_first_result_set 'dbo.usp_mySp';
And then use the result to create some dynamic SQL.
So I have declared a query within a varchar variable like:
DECLARE #sql VARCHAR(MAX) = 'select * from table'
I've also declared a temp table #Results that matches the column structure of the query.
I then call:
INSERT INTO #Results
EXEC (#sql)
The error I get is:
An INSERT EXEC statement cannot be nested.
I would also like to add that the query executes fine without the part
INSERT INTO #Results
What could be causing it? Any tips will be greatly appreciated
You can't stack together more than 1 INSERT INTO + EXEC, this is a limitation from SQL Server.
DECLARE #Test TABLE (Number INT)
INSERT INTO #Test (Number)
EXEC ('
CREATE TABLE #InnerTable (SomeColumn INT);
INSERT INTO #InnerTable (SomeColumn)
EXEC (''SELECT 1'');
SELECT 1;')
Msg 8164, Level 16, State 1, Line 4 An INSERT EXEC statement cannot be
nested.
If we remove the inner INSERT INTO + EXEC...
DECLARE #Test TABLE (Number INT)
INSERT INTO #Test (Number)
EXEC ('
CREATE TABLE #InnerTable (SomeColumn INT);
SELECT 1;')
Succeed!
There are multiple ways to workaround this limitation, however most of them will require modifying the EXEC content. You can find an exhaustive explanation here. The one I usually use with my procedures is sharing a temporary table. You need to create a temporary table outside the EXEC then load it inside. The table is still accessible outside the EXEC scope because it was created outside.
IF OBJECT_ID('tempdb..#Test') IS NOT NULL
DROP TABLE #Test
CREATE TABLE #Test (Number INT)
EXEC ('INSERT INTO #Test (Number) SELECT 1')
SELECT * FROM #Test
Downside of this approach is that the EXEC part might fail if the temporary table wasn't created or it was created with wrong column names or data types. Keep in mind that this won't work with variable tables, they need to be temporary (at least) to be accessible inside the EXEC scope.
I'm inserting data into a temp table and querying the temp table fails
DECLARE #SQLQuery AS NVARCHAR(500)
SET #SQLQuery = 'SELECT Top 100 *
INTO #tempTable
FROM ' + #origDB + '.dbo.' + #origTable + ' o WITH (NOLOCK) '
EXECUTE sp_executesql #SQLQuery
and when I try to query the temp table , like so
select * from #tempTable
I get the following error :
Invalid object name '#tempTable'.
Courtesy of MSDN
The problem that you have is with the scope. The TEMP table is creatd at the scope of the EXEC() method and hence it is not available after the function returns. To fix this, create your temp table before calling EXEC() and use an INSERT INTO instead of SELECT INTO.
As others have said, the scope of a temporary table is limited to the session context in which it is created - a stored procedure runs in its own context.
You could use a global temporary table ##tempTable, but it's generally a bad idea as it would be available to other sessions than the one creating it.
I have a stored procedure that is responsible to import data from database A to database B. I have customers, they all have their own database B (with the same tables etc.) They also have their own database A. The stored procedure will be executed (deployed) on database B.
The problem:
Each customer have another database name for A and B. I found also that database A can be on a different server/instance. I need a generic way to put automatically the server/instance name and the database name from A in my stored procedure to select data from there. Every customer has a connectstring to database A which is already exists in database B. So from the connecstring, I can get the server/instance name and the databasename of A. (I already created a linked server)
1. What is the best way to put the server/instance name and the database name before the table name??
Stored procedure
In my stored procedure I have used a lot of variable (declare) tables to insert the data from database A. There are many articles about using dynamic sql but, I cant find an example with a declare table.
My solution
I am thinking about inserting all the data from database A to variable tables. I am importing data from 7 tables, so I need to declare 7 tables and further in my SP I can select data from my declare tables. Note that the hole stored procedure is very huge.
Questions
2.What do you think about my solution?
3.Do you have another solution?
4.How can I insert into my declare table using dynamic sql?
**note that I am using sql server 2005.
I have a few statements like below:
declare #Temp table (Id int, etc
insert into #Temp (Id, etc)
Select Id, etc
From [databasename].dbo.TableName //hardcoded
Where .......
// doing staff like selecting from the #Temp table etc.
I also have subqueries, but I can change if it is necessary.
You can't use dynamic sql to enter into declare tables as the temporary table is only available in the session. Executing any new sql i.e. through dynamic sql will create a new session.
You can get around it by not using any declared or temp tables but instead using a normal table. The dynamic sql will have access to this and anything you do to it isnt lost.
You can prefix your normal tables with something like Temp_ just to note they are temp tables and then make sure you drop them at the beginning of each query i.e.
DROP TABLE TEMP_Table
You can call multiple local databases by doing
SELECT * FROM [DatabaseName].dbo.[TableName]
Instead of creating #temp, create it as [TempDB].[DBO].[Temp] and it will be accessible outside the dynamic SQL. However, remember to explicitly drop the table, once you are done
DECLARE #sql VARCHAR(200)
SET #sql = 'CREATE TABLE tempdb.dbo.temp(id INT IDENTITY(1,1), DESCRIPTION VARCHAR(100))
INSERT INTO tempdb.dbo.temp SELECT ''1'' SELECT * FROM tempdb.dbo.temp'
PRINT (#sql)
EXEC (#sql)
SELECT * FROM tempdb.dbo.temp
DROP TABLE tempdb.dbo.temp
Raj
Check this for creating temporary table in dynamic query
DECLARE #sql VARCHAR(200)
SET #sql = 'CREATE TABLE #temp(id INT IDENTITY(1,1), DESCRIPTION VARCHAR(100))
INSERT INTO #temp SELECT ''1'' SELECT * FROM #temp'
PRINT (#sql)
EXEC (#sql)
SQLFiddle
to be precise
DECLARE #sql VARCHAR(1000)
SET #sql =
'DECLARE #Temp TABLE (
Id INT,
etc
INSERT INTO #Temp (Id, etc)
SELECT Id,
etc
FROM [databasename].dbo.TableName / / hardcoded
WHERE ....... SELECT * FROM #temp'
PRINT (#sql)
EXEC (#sql)