在 SQL 中是不是可以在 WITH 中使用 WITH

Posted

技术标签:

【中文标题】在 SQL 中是不是可以在 WITH 中使用 WITH【英文标题】:Is it possible in SQL to use WITH inside a WITH在 SQL 中是否可以在 WITH 中使用 WITH 【发布时间】:2014-06-12 01:46:59 【问题描述】:

在 SQL 中,可以将 WITH 放在 WITH 中吗?

以下面的查询为例,

WITH Temp ([Description], [Amount], [OverdueBy])
AS 
(select Description, SUM(Amount) as Amount, (DATEDIFF(day,DueDate,GETDATE())) as OverdueBy  from brvAPAllInvoices 
Where PaidDate is null and APCo = 1 and Amount > 0 
Group By Description, DueDate, APRef

)

select * from Temp

我想根据上述查询创建一个“虚拟”临时表。是否可以使用另一个 WITH 来包含它?

类似这样的事情:

WITH Temp2 ([Description], [Amount], [OverdueBy])
AS
(
WITH Temp ([Description], [Amount], [OverdueBy])
AS 
(select Description, SUM(Amount) as Amount, (DATEDIFF(day,DueDate,GETDATE())) as OverdueBy  from brvAPAllInvoices 
Where PaidDate is null and APCo = 1 and Amount > 0 
Group By Description, DueDate, APRef

)

select * from Temp)

select * from Temp2

【问题讨论】:

你尝试的时候发生了什么? Msg 156, Level 15, State 1, Line 4 关键字“WITH”附近的语法不正确。消息 319,级别 15,状态 1,第 4 行关键字“with”附近的语法不正确。如果此语句是公用表表达式、xmlnamespaces 子句或更改跟踪上下文子句,则前面的语句必须以分号结束。消息 102,级别 15,状态 1,第 12 行 ')' 附近的语法不正确。 确保使用 实际 RDBMS 进行标记。 【参考方案1】:

根据您的 dbms,您可以有多个 WITH 语句,无论是否嵌套。 (用 PostgreSQL 说明。)SQL Server doesn't allow nesting common table expressions。 (搜索CTE_query_definition。)

嵌套

with today as (
  with yesterday as (select current_date - interval '1' day as yesterday)
  select yesterday + interval '1' day as today from yesterday 
)
select cast(today as date) from today
今天 -- 2014-06-11

当您嵌套公用表表达式时,嵌套的 CTE 在其封闭的 CTE 之外不可见。

with today as (
  with yesterday as (select current_date - interval '1' day as yesterday)
  select yesterday + interval '1' day as today from yesterday 
)
select * from yesterday
错误:关系“昨天”不存在

未嵌套

with yesterday as (
  select current_date - interval '1' day as yesterday
), 
today as (
  select yesterday + interval '1' day as today from yesterday 
)
select cast(yesterday as date) as dates from yesterday
union all
select cast(today as date) from today
日期 -- 2014-06-10 2014-06-11

当您使用连续的、未嵌套的 CTE 时,较早的 CTE 对后面的 CTE 可见,但反之则不然。

with today as (
  select yesterday + interval '1' day as today from yesterday 
),
yesterday as (
  select current_date - interval '1' day as yesterday
) 
select yesterday from yesterday
union all
select today from today
错误:关系“昨天”不存在

【讨论】:

【参考方案2】:

不,您不能在 CTE 中定义 CTE,但是您可以在单个语句中定义多个 CTE 并引用其他 CTE。

; with a as (
    select * from some_table
),
b as (
   select * 
   from another_table t
     inner join a ON (t.key = a.key)
)
select * 
from b

【讨论】:

【参考方案3】:

您通常会执行以下操作;

WITH Temp ([Description], [Amount], [OverdueBy])
AS 
(select Description, SUM(Amount) as Amount, (DATEDIFF(day,DueDate,GETDATE())) as OverdueBy  from brvAPAllInvoices 
Where PaidDate is null and APCo = 1 and Amount > 0 
Group By Description, DueDate, APRef
), Temp2 ([Description], [Amount], [OverdueBy]) AS 
(
    SELECT * FROM Temp
)
select * from Temp2

尽管在您设计的示例中,显然没有太多用处,因为两个表结构几乎相同。我也倾向于将 CTE 视为命名派生表而不是临时表......即使它们不仅仅是派生表

【讨论】:

以上是关于在 SQL 中是不是可以在 WITH 中使用 WITH的主要内容,如果未能解决你的问题,请参考以下文章

SQL 中with的用法

在 Windows Phone 上使用 Linq to SQL 时,是不是可以提高批量删除的性能?

SQL:with 查询

sql里面 with...as 是啥意思啊?如何使用

DB2 中 WITH 查询的 SQL 查询性能改进

phonegap 中是不是有任何可用于 wi-fi direct 的插件?