【问题标题】:Select INTO Temp table from dynamic sql string variable从动态 sql 字符串变量中选择 INTO Temp 表
【发布时间】:2019-10-29 18:19:26
【问题描述】:

我有一个构建动态 SQL 查询的过程,简化为

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

我想将此查询选择到一个临时表中,以便稍后在我的过程中使用,但我想不出正确的语法。

SELECT * INTO #myTempTable FROM ( @mySQLQuery) x

基本上是我想做的。

我试过sp_executeSQL 'SELECT * INTO #myTempTable FROM (' + @mySQLQuery + ') x' 在我的程序中,这也不起作用。

感谢您的任何建议`

【问题讨论】:

  • 你真的需要开始使用QUOTENAME 并保护你的sql免受注入。 Dos and Don'ts of Dynamic SQL
  • 不知道它会起作用,但您是否尝试将 @mySQLQuery 替换为原始行中的值。我假设 SQL 工作正常。
  • 另外,如果您正在使用带有动态语句的SELECT ... INTO语法,则临时表将保留在动态语句中。这意味着您将无法在 sp_executesql 的动态执行之外访问它。

标签: sql sql-server tsql dynamic-sql


【解决方案1】:

我能想到的唯一方法是在tempdb 中保留一个对象。临时表仅在创建它们的 会话 中持久存在,这意味着如果您使用动态 SQL 创建临时表,则不仅在 sp_executesql 中的该会话中持久。

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

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

因此,您需要在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;

【讨论】:

    【解决方案2】:

    我用过两种方法。

    如果你的临时表的结构是事先知道的,你可以这样做:

    CREATE TABLE #temp (<column list>);
    
    SET @my_sql = <your query syntax, without the INTO clause>;
    
    INSERT #temp (<column list>)
    EXECUTE sp_executesql @my_sql;
    

    另一方面,如果您的表结构事先未知,则可以使用全局临时表 (##temp) 代替本地临时表 (#temp):

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

    可以从EXECUTE 语句之外的过程访问全局表 (##temp)。

    【讨论】:

      【解决方案3】:

      临时表的范围仅在会话处于活动状态之前受到限制。

      在您的情况下,当您使用 sp_executesql 时,一旦对 sp_executesql 的调用完成,本地临时表就会超出范围。

      您需要创建全局临时表。

      看下面一个小例子:

      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';
      

      当你运行上面的代码sn-p,你会看到如下结果:

      col1
      1
      2
      

      【讨论】:

      • 这是一个主要的 SQL 注入问题。如果您使用动态对象名称,请使用正确的数据类型(对象使用数据类型sysname,这是nvarchar(128) NOT NULL 的同义词)并在注入时将名称包装在QUOTENAME 中。
      猜你喜欢
      • 2012-03-21
      • 2014-11-09
      • 1970-01-01
      • 2012-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-14
      相关资源
      最近更新 更多