【问题标题】:How to return local temporary table from generated sql如何从生成的 sql 返回本地临时表
【发布时间】:2016-11-21 22:44:45
【问题描述】:

我有过滤 SQL,它返回的查询列数不确定,并且想在存储过程中使用结果。

DECLARE @RecordSelectionSql VARCHAR(MAX)
SET @RecordSelectionSql = (SELECT SQLQUERY FROM RecordSelection WHERE Id = @Id) + ' AND ([Active] = 1)'

DECLARE @sql NVARCHAR(MAX) = N'';
SELECT @sql += ',' + CHAR(13) + CHAR(10) + CHAR(9) + name + ' ' + system_type_name
FROM sys.dm_exec_describe_first_result_set(@RecordSelectionSql, NULL, 0);

SELECT @sql = N'CREATE TABLE #TmpImport
(' + STUFF(@sql, 1, 1, N'') + '
);';
EXEC (@sql)

INSERT INTO #TmpImport
EXEC (@RecordSelectionSql)

但是我遇到了错误

Invalid object name '#TmpImport'.

如何正确编码这部分?

编辑:在 RecordSelection 上添加了缺失条件

编辑2: 我不能使用下面的代码,因为在执行 @RecordSelectionSql 后 #TmpImport 被破坏。

DECLARE @RecordSelectionSql AS VARCHAR(MAX)
SET @RecordSelectionSql = 'SELECT X.* INTO #TmpImport FROM (' 
    + (SELECT SQLQUERY FROM RecordSelection WHERE Id = @Id) + ' AND ([Active] = 1) AS X'
EXEC (@RecordSelectionSql)
SELECT * FROM #TmpImport

给出同样的错误

Invalid object name '#TmpImport'.

【问题讨论】:

    标签: sql-server tsql stored-procedures


    【解决方案1】:

    临时表仅在创建它们的会话中可用。对于动态 SQL,这意味着它在动态 SQL 运行后不可用。您的选择是:

    1. 创建一个全局临时表,它将在会话之外持续存在,直到它被显式删除或以另一种方式从 TempDB 中清除,使用双哈希:create table ##GlobalTemp
      --在下面合并 Radu 非常相关的评论:因为此表在您的会话之外持续存在,您需要确保您没有创建其中两个或有两个不同的进程试图处理其中的数据。您需要有一种方法来唯一标识您要处理的全局临时表。
    2. 您可以创建一个常规表,然后记得再次删除它。
    3. 在动态 SQL 脚本中包含需要引用临时表的任何逻辑

    不过,对于您的特定实例,您最好只执行 select into,它将根据所选数据生成您的表结构。

    【讨论】:

    • 全局临时表 (GTT) 的唯一问题是它在其他会话中可见,因此您将无法在其他会话中创建具有相同名称的 GTT。您需要想出一些机制来为每个会话唯一标识一个 GTT,以便在关闭会话之前必须执行清理部分。
    • @RaduGheorghiu 非常相关的附加信息,谢谢。已添加到上面。
    • 我可以创建随机 id DECLARE @ db_id int SET @ db_id = CAST(round(RAND() * 2147483647, 0) AS INT) 使用动态 SQL 选择其中并作为 EXEC 'DROP TABLE # #TmpImport' + CAST(@ db_id AS NVARCHAR)。但是,如果不将整个存储过程逻辑包含到动态 sql 中,我以后不能在 SP 中使用它。
    • @amuliar 是的,但那是您尝试使用保存为表中文本而不是存储过程或视图的查询所付出的代价。你这样做的具体原因是什么?
    • 因为表 RecordSelection 包含动态选择 SQL 以便稍后在 SP 中处理。
    【解决方案2】:

    选择临时表要容易得多。

    例如

    SELECT * INTO #TmpImport FROM SomeTable 
    

    【讨论】:

    • 我没有 SomeTable 但我在变量 @RecordSelectionSql 中有动态 SQL
    • @amuliar 您的问题不是您不能动态创建表,而是您不能引用在动态 SQL 中创建的临时表。通过使用select * into #temptable,您不再需要使用动态 SQL 来指定列。因此,使用 select into 可以解决您在问题上下文中可能遇到的所有问题。
    • "我有过滤 SQL,它返回的查询列数不确定,并且想在存储过程中使用结果。" RecordSelection 是动态的,它可以包含不同列数和行数的选择 SQL。
    猜你喜欢
    • 2017-08-29
    • 1970-01-01
    • 2012-02-17
    • 1970-01-01
    • 2016-02-07
    • 1970-01-01
    • 2010-11-29
    • 1970-01-01
    相关资源
    最近更新 更多