1

I have a procedure that builds out a dynamic SQL query simplified as

@mySQLQuery = 'SELECT ' + @myCol + 'FROM' + @myTable

I would like to select this query into a temp table to be used later in my procedure, but I can't figure out the right syntax.

SELECT * INTO #myTempTable FROM ( @mySQLQuery) x

is basically what I want to do.

I tried sp_executeSQL 'SELECT * INTO #myTempTable FROM (' + @mySQLQuery + ') x' within my procedure and that didn't work either.

Thanks for any suggestions`

3
  • You really need to start using QUOTENAME and protecting your sql from injection. Dos and Don'ts of Dynamic SQL Commented Oct 29, 2019 at 18:21
  • No idea of it would work but have you tried replacing @mySQLQuery with the values from the original line. I assume that that SQL works. Commented Oct 29, 2019 at 18:22
  • 1
    Also, if you are using SELECT ... INTO syntax with a dynamic statement, the temporary table will only persist within the dynamic statement. Meaning you won't be able to access it outside of the dynamic execution of sp_executesql. Commented Oct 29, 2019 at 18:23

3 Answers 3

3

The only way I can think of you could achieve this would be to persist an object in tempdb. Temporary tables only persist for the session they are created in, meaning that if you create a temporary table using dynamic SQL, isn't only persist for that session in sp_executesql.

EXEC sp_executesql N'SELECT 1 AS one INTO #test;';

--This'll fail
SELECT * FROM #test;

Therefore you'll need to use a persisted table in tempdb:

DECLARE @NyCol sysname,
        @MyTable sysname,
        @MySchema sysname;
--Assume these are set somewhere

DECLARE @SQL nvarchar(MAX),
        @CRLF nchar(2) = NCHAR(13) + NCHAR(10);

SET @SQL = N'SELECT ' + QUOTENAME(@MyCol) + @CRLF +
           N'INTO tempdb.dbo.MyTempTable'  + @CRLF +
           N'FROM ' + QUOTENAME(@MySchema) + N'.' + QUOTENAME(@MyTable) + N';';

EXEC sp_executesql @SQL;

--Do Stuff

--Clean up

DROP TABLE tempdb.dbo.MyTempTable;
Sign up to request clarification or add additional context in comments.

Comments

2

There are two ways that I've used.

If the structure of your temp table is known in advance, you can do this:

CREATE TABLE #temp (<column list>);

SET @my_sql = <your query syntax, without the INTO clause>;

INSERT #temp (<column list>)
EXECUTE sp_executesql @my_sql;

If, on the other hand, your table structure is unknown in advance, you can use a global temp table (##temp) instead of a local temp table (#temp):

EXECUTE sp_executesql <your query with INTO ##temp etc>

The global table (##temp) will be accessible from the procedure outside the EXECUTE statement.

Comments

1

Scope of the temporary tables are only limited till the session is alive.

In your case, when you use sp_executesql, the local temp table is out of scope once the call to sp_executesql is finished.

You need to create global temp tables.

See below a small example:

create table dbo.test_mytable( col1 int );
GO

insert into dbo.test_mytable
select 1 union
select 2;
go

create or alter procedure dbo.test_myproc( @mytable varchar(255), @mycol varchar(255) )
as
begin
  declare @mysql varchar(4000);

  drop table if exists ##mytemptable;
  set @mysql = 'select ' + @mycol + ' from ' + @mytable;
  set @mysql = 'select * into ##mytemptable from (' + @mysql + ')  X';

  exec (@mysql);
  select * from ##mytemptable;
end;
GO

exec dbo.test_myproc 'dbo.test_mytable', 'col1';

When you run the above code snippet, you will see the result as below:

col1
1
2

1 Comment

This is a major SQL Injection problem. If you're using dynamic object names, use the right data type (objects use the data type sysname which is a synonym for nvarchar(128) NOT NULL) and wrap the name in QUOTENAME when you inject them.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.