I'm at a loss as to why some SQL leveraging sp_executesql is working the way it is when temporary tables are involved, along with INSERT and SELECT - INTO. I'm using SQL Server.
Here is the code in question:
-- Insert into CREATE TABLE #results ( rid INT, ); declare @sql nvarchar(max) = ''; set @sql = 'INSERT INTO #results (rid) VALUES (1);'; EXEC sp_executesql @sql; select * from #results; -- Select into CREATE TABLE #results2 ( rid INT, ); declare @sql2 nvarchar(max) = ''; set @sql2 = 'select rid into #results2 from #results;'; EXEC sp_executesql @sql2; select * from #results2; -- Clean up drop table #results; drop table #results2; When this runs, #results has a single row where rid = 1, and #results2 has no rows at all, which you can see here:
There are honestly several points of confusion I have with this. To start off, I would expect the SELECT - INTO to fail, since a table called #results2 should already exist in this session.
You can see this error with this similar bit of SQL which doesn't leverage sp_executesql for the SELECT - INTO:
-- Insert into CREATE TABLE #results ( rid INT, ); declare @sql nvarchar(max) = ''; set @sql = 'INSERT INTO #results (rid) VALUES (1);'; EXEC sp_executesql @sql; select * from #results; -- Select into CREATE TABLE #results2 ( rid INT, ); declare @sql2 nvarchar(max) = ''; select rid into #results2 from #results; select * from #results2; -- Clean up drop table #results; drop table #results2; This code, as expected, generates the error:
There is already an object named '#results2' in the database.
Based on this answer, I assumed this was happening because sp_executesql has its own session. Due to this, the SELECT - INTO nested inside of sp_executesql doesn't know that #results2 exists, so it creates its own temporary table called #results2, inserts into it, then drops that table.
That makes sense to me, except, that in that very same sp_executesql is accessing the table #results. So sp_executesql knows about the #results table, but not the #results2 table? Plus my first sp_executesql with than INSERT has no trouble accessing the #results table either. Based on this commnet, it seems to that the reason sp_executesql can access #results is because sp_executesql actually creates its own batch, and batches within the same session can see each others temporary tables. Great, except then we loop back to my original confusion of why isn't sp_executesql complaining about the existence of #results2 when running the SELECT - INTO?
If I had to boil it down, my core points of confusion are:
- Why doesn't the
SELECT - INTOnested inside ofsp_executesqlthrow an error that #results2 already exists? - Why does the
INSERTstatement nested inside ofsp_executesqlhave no problem accessing #results and inserting into it? - Why does the
SELECT - INTOnested inside ofsp_executesqlhave no problem accessing #results, but doesn't seem to recognize the existence of #results2?
