Microsoft SQL Server:运行任意查询并将结果保存到临时表中



给定一个任意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的子查询或公共表表达式时也有效。但是,当查询使用临时表时,它不起作用。

最新更新