给定一个任意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
并不容易;在一般情况下,它需要解析整个查询。
使用用户定义函数的可能解决方案
一种方法可能是创建一个用户定义的函数包装查询,然后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将不起作用。我正在寻找一种方法,将工作。 -
"在
select
"前面放一个into
。这当然可以工作,但在一般情况下需要解析SQL。对于计算机程序来说,select
需要改变的地方并不总是显而易见的。我确实尝试了将其添加到查询中的最后一个select
的规则,但这也失败了。例如,如果底层查询是
with mycte as (select 5 as mycol) select mycol from mycte except select 6
则into #x
需要添加到第二个选项中,而不是出现在except
之后的选项中。一般情况下,要做到这一点需要将SQL解析为语法树。
最后,创建用户定义的函数似乎是唯一的一般答案。如果undl
是底层select
查询,那么您可以说
create function dbo.myfunc() returns table as return (undl)
go
select * into #tmp from dbo.myfunc()
go
drop function dbo.myfunc
go
伪sqlgo
表示开始一个新的批处理。create function
必须在select
之前分批执行,否则会出现语法错误。(仅仅用;
分隔它们是不够的。)
此方法即使在undl
包含使用with
的子查询或公共表表达式时也有效。但是,当查询使用临时表时,它不起作用。