【问题标题】:Microsoft SQL Server: run arbitrary query and save result into temp tableMicrosoft SQL Server:运行任意查询并将结果保存到临时表中
【发布时间】:2023-01-12 19:03:47
【问题描述】:

给定一个随意的select查询,如何将其结果保存到临时表中?

为了简化事情,我们假设 select 查询在顶层不包含 order by 子句;它不是动态 SQL;它确实是一个select(不是存储过程调用),而且是一个查询(不是返回多个结果集的查询)。所有列都有明确的名称。如何运行它并将结果保存到临时表?通过在客户端处理 SQL,或者通过 T-SQL 中的一些聪明的东西。

我不是在询问任何特定的查询——显然,给定一些特定的 SQL,我可以手动重写它以保存到临时表中——而是在询问一个普遍适用且可以编程的规则。

一种可能的“答案”通常不起作用

对于简单的查询,您可以执行 select * into #tmp from (undl) x 其中undl 是基础 SQL 查询。但是如果 undl 是一个更复杂的查询,这将失败;例如,如果它使用使用with 的公用表表达式。

出于类似的原因,with x as (undl) select * into #tmp from x 通常不起作用; with 子句不能嵌套。

我目前的方法,但不容易编程

我发现的最好的方法是找到查询的顶层select,并将其修改为在from 关键字之前添加into #tmp。但是找到哪个 select 来 munge 并不容易;它需要在一般情况下解析整个查询。

具有用户定义函数的可能解决方案

一种方法可能是创建一个用户定义的函数来包装查询,然后 select * into #tmp from dbo.my_function() 然后删除该函数。有更好的东西吗?

  • 有关底层使用 CTE 时简单方法为何失败的更多详细信息。假设我尝试使用规则 select * into #tmp from (undl) x,其中 undl 是底层 SQL。现在让undl成为with mycte as (select 5 as mycol) select mycol from mycte。应用规则后,最终查询是 select * into #tmp from (with mycte as (select 5 as mycol) select mycol from mycte) x,这是无效的 SQL,至少在我的版本 (MSSQL 2016) 上不是。 with 子句不能嵌套。

  • 明确地说,CTE 必须在select 之前的顶层定义。它们不能嵌套,也不能出现在子查询中。我完全理解这一点,这就是我问这个问题的原因。尝试包装最终试图嵌套 CTE 的 SQL 将不起作用。我正在寻找一种可行的方法。

  • “将 into 放在 select 之前”。这肯定会起作用,但在一般情况下需要解析 SQL。 select 需要更改的并不总是很明显(对于计算机程序)。我确实尝试了将其添加到查询中最后一个 select 的规则,但这也失败了。例如,如果基础查询是

with mycte as (select 5 as mycol) select mycol from mycte except select 6

那么into #x需要添加到第二选择,而不是出现在except 之后的那个。在一般情况下要做到这一点涉及将 SQL 解析为语法树。

【问题讨论】:

  • “例如,如果它使用带有 with 的公用表表达式。”不,它没有,它失败了,因为你的语法无效。您当然可以将 SELECT ... INTO 与语句中定义的 CTE 一起使用。如果您在尝试这样做时遇到错误,请在您的问题中包含该尝试。
  • 目前还不清楚问题是什么。 SELECT INTO 工作,有或没有 CTE。如果INTO 指定一个临时表,您将得到一个临时表,当连接关闭时,该临时表将被自动删除。
  • SELECT INTO 是一个带有额外 INTO 子句的实际 SELECT。在所有 SELECT 查询中,必须定义 CTE选择关键字。您不能在子查询中定义 CTE。这与INTO无关
  • 感谢您的 cmets。我已经添加了一些明确的细节,说明为什么天真的 select into 方法不起作用。 @PanagiotisKanavos 你是对的,CTE 必须在选择之前。这就是为什么简单地包装 SQL 不起作用的原因。我正在寻找一个有效的规则。
  • 有用。你的查询是错误的。子查询中不能有 CTE,它们必须在查询本身之前定义。这就是 CTE 的全部意义所在。它们被命名为 sn-ps 可以在查询中使用

标签: sql-server temp-tables


【解决方案1】:

最后创建一个用户定义的函数似乎是唯一的通用答案。如果 undl 是底层的 select 查询,那么你可以说

create function dbo.myfunc() returns table as return (undl)
go
select * into #tmp from dbo.myfunc()
go
drop function dbo.myfunc
go

伪 SQL go 表示开始新的批处理。 create function 必须在select 之前批量执行,否则会出现语法错误。 (仅用 ; 分隔它们是不够的。)

即使 undl 包含使用 with 的子查询或公用表表达式,此方法也适用。但是,当查询使用临时表时它不起作用。

【讨论】:

  • 您不能在不允许用户创建函数的环境中轻松使用它(尤其是在 dbo 模式中)。
猜你喜欢
  • 1970-01-01
  • 2021-02-06
  • 2019-08-08
  • 2021-11-09
  • 1970-01-01
  • 2020-12-05
  • 2021-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多