【发布时间】: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 可以在查询中使用