WITH子句和子查询的区别?

Posted

技术标签:

【中文标题】WITH子句和子查询的区别?【英文标题】:Difference between WITH clause and subquery? 【发布时间】:2015-07-16 16:36:14 【问题描述】:

WITH 子句和子查询有什么区别?

1. WITH table_name as ( ... )

2. select *
    from ( select curr from tableone t1
             left join tabletwo t2
               on (t1.empid = t2.empid)
         ) as temp_table

【问题讨论】:

这能回答你的问题吗? Difference between CTE and SubQuery? 【参考方案1】:

可能没有。在实际优化查询之前,Oracle 能够进行许多代数转换。很可能这两个查询将以相同的方式进行评估(它们将具有相同的执行计划)。

【讨论】:

【参考方案2】:

WITH 子句用于subquery factoring,也称为公用表表达式或 CTE:

WITH query_name 子句允许您为子查询块分配名称。然后,您可以通过指定 query_name 在查询中的多个位置引用子查询块。 Oracle 数据库通过将查询名称视为内联视图或临时表来优化查询。

在您的第二个示例中,您所称的 temp_table 是内联视图,而不是临时表。

在许多情况下,选择使用哪一个取决于您喜欢的样式,而 CTE 可以使代码更具可读性,尤其是在具有多级子查询的情况下(当然意见会有所不同)。如果您只参考 CTE/inline 视图一次,您可能不会看到任何性能差异,并且优化器最终可能会采用相同的计划。

当您需要在多个地方(例如在联合中)使用相同的子查询时,它们特别有用。您可以将内联视图拉出到 CTE 中,这样代码就不会重复,并且它允许优化器在认为有益的情况下将其具体化。

例如,这个人为的例子:

select curr from (
  select curr from tableone t1
  left join tabletwo t2 on (t1.empid = t2.empid)
) temp_table
where curr >= 0
union all
select -1 * curr from (
  select curr from tableone t1
  left join tabletwo t2 on (t1.empid = t2.empid)
) temp_table
where curr < 0

可以重构为:

with temp_table as (
  select curr from tableone t1
  left join tabletwo t2 on (t1.empid = t2.empid)
)
select curr from temp_table
where curr >= 0
union all
select -1 * curr from temp_table
where curr < 0

不再需要重复子查询。重复代码越复杂,从维护的角度来看,使用 CTE 就越有利。而且,子查询的开销越大,您可以从使用 CTE 中看到的性能优势就越大,尽管优化器通常很擅长弄清楚您在做什么。

【讨论】:

【参考方案3】:

此外,如果子查询包含分析函数 (LEAD/LAG/etc),并且如果您想过滤分析函数的结果 - 使用 SUBQUERY 方法,您必须将结果插入临时表并在临时表上执行过滤等,同时使用WITH 子句,您可以在同一查询中使用结果进行过滤/分组/等

;WITH temp AS
(
    SELECT 
        ID
        , StatusID
        , DateChanged
        , LEAD(StatusID,1) OVER (PARTITION BY ID ORDER BY ID, DateChanged, StatusID) NextStatusID
    FROM 
        myTable 
    WHERE 
        ID in (57,58)
)
SELECT
    ID
    , StatusID
    , DateChanged
FROM
    temp
WHERE
    temp.NextStatusID IS NULL

【讨论】:

以上是关于WITH子句和子查询的区别?的主要内容,如果未能解决你的问题,请参考以下文章

SQL相关子查询和嵌套子查询的区别

在 IN 子句中使用硬编码值和子查询

hive UNION和子查询

选择带有“is null”子句的查询和子选择/左连接不返回结果

Oracle 12c 子查询的 WITH 子句中的函数

EXISTS 不适用于 WITH 子句中的子查询