SQL 中 with as 用法(转)

本文深入探讨了Oracle中WITH子句的使用方法及其带来的优化效果,通过多个例子展示了如何将重复使用的SQL语句封装在WITH子句中,以提高查询效率和代码可读性。同时,解释了WITH子句的工作原理、注意事项以及与Oracle SQL的兼容性,为读者提供了全面的理解。
 

with
sql1 as (select to_char(a) s_name from test_tempa),
sql2 as (select to_char(b) s_name from test_tempb where not exists (select s_name from sql1 where rownum=1))
select * from sql1ITPUB个人空间2g N*` O3y2eB Q6}
union all
select * from sql2
union all
select 'no records' from dual
       where not exists (select s_name from sql1 where rownum=1)
       and not exists (select s_name from sql2 where rownum=1);

再举个简单的例子

with a as (select * from test)

select * from a;

其实就是把一大堆重复用到的SQL语句放在with as 里面,取一个别名,后面的查询就可以用它

这样对于大批量的SQL语句起到一个优化的作用,而且清楚明了


这是搜索到的英文文档资料(说得比较全,但是本人英文特菜,还没具体了解到,希望各高手具体谈谈这个with
as 的好处)

About Oracle WITH clause
Starting in Oracle9i release 2 we see an incorporation of the SQL-99 “WITH clause”, a tool for materializing subqueries to save Oracle from having to re-compute them multiple times.

The SQL “WITH clause” is very similar to the use of Global temporary tables (GTT), a technique that is often used to improve query speed for complex subqueries. Here are some important notes about the Oracle “WITH clause”:

   • The SQL “WITH clause” only works on Oracle 9i release 2 and beyond.
   • Formally, the “WITH clause” is called subquery factoring
   • The SQL “WITH clause” is used when a subquery is executed multiple times
   • Also useful for recursive queries (SQL-99, but not Oracle SQL)

To keep it simple, the following example only references the aggregations once, where the SQL “WITH clause” is normally used when an aggregation is referenced multiple times in a query.
We can also use the SQL-99 “WITH clause” instead of temporary tables. The Oracle SQL “WITH clause” will compute the aggregation once, give it a name, and allow us to reference it (maybe multiple times), later in the query.

The SQL-99 “WITH clause” is very confusing at first because the SQL statement does not begin with the word SELECT. Instead, we use the “WITH clause” to start our SQL query, defining the aggregations, which can then be named in the main query as if they were “real” tables:

WITH
subquery_name
AS
(the aggregation SQL statement)
SELECT
(query naming subquery_name);


Retuning to our oversimplified example, let’s replace the temporary tables with the SQL “WITH  clause”:

WITH
sum_sales AS
  select /*+ materialize */
    sum(quantity) all_sales from stores
number_stores AS
  select /*+ materialize */
    count(*) nbr_stores from stores
sales_by_store AS
  select /*+ materialize */
  store_name, sum(quantity) store_sales from
  store natural join sales
SELECT
   store_name
FROM
   store,
   sum_sales,
   number_stores,
   sales_by_store
where
   store_sales > (all_sales / nbr_stores)
;


Note the use of the Oracle undocumented “materialize” hint in the “WITH clause”. The Oracle materialize hint is used to ensure that the Oracle cost-based optimizer materializes the temporary tables that are created inside the “WITH” clause. This is not necessary in Oracle10g, but it helps ensure that the tables are only created one time.

It should be noted that the “WITH clause” does not yet fully-functional within Oracle SQL and it does not yet support the use of “WITH clause” replacement for “CONNECT BY” when performing recursive queries.

To see how the “WITH clause” is used in ANSI SQL-99 syntax, here is an excerpt from Jonathan Gennick’s great work “Understanding the WITH Clause” showing the use of the SQL-99 “WITH clause” to traverse a recursive bill-of-materials hierarchy

The SQL-99 “WITH clause” is very confusing at first because the SQL statement does not begin with the word SELECT. Instead, we use the “WITH clause” to start our SQL query, defining the aggregations, which can then be named in the main query as if they were “real” tables:

WITH
subquery_name
AS
(the aggregation SQL statement)
SELECT
(query naming subquery_name);


Retuning to our oversimplified example, let’s replace the temporary tables with the SQL “WITH” clause”:

另一个例子:
with tempDeptName(deptName) as
(
      select
             dept_name as deptName
     from
             bas_dept as dept,tpp_materialmuster as muster
     where
             dept.DEPT_ID = muster.NEEDUNIT
           
     union all
     
     select
             corp_name as deptName
     from
              bas_corp as corp,tpp_materialmuster as muster
     where
             corp.corp_id = muster.NEEDUNIT
           
),
tempProjInfo(projName, projCode) as
(
      select
             etfprojName as projName,
            etfprojCode as projCode
     from
             tbi_etfproj as etf, tpp_materialMuster as muster
     where
             etf.etfprojid = muster.projid
           
     union all
     
     select
             etmprojName as projName,
            etmprojCode as projCode
     from
              tbi_etmproj as etm, tpp_materialMuster as muster
     where
               etm.etmprojId = muster.projid
)

select
                   deptname,
                   projname,
                   projcode
      from     tpp_materialmuster as muster,tempDeptName,tempProjInfo
 
文章出处: http://www.blogjava.net/sealyu/archive/2009/11/12/302068.html
### 用法详解 `WITH AS` 是 SQL 中一种用于定义子查询的语法结构,也被称为子查询分解(Subquery Factoring)。它允许将一个复杂的查询片段定义为一个临时的结果集,并在整个查询中多次引用,从而提高 SQL 代码的可读性和可维护性。 #### 1. 基本语法 `WITH AS` 的基本语法如下: ```sql WITH <子查询名称> AS ( <子查询定义> ) SELECT ... FROM <子查询名称> WHERE ... ``` 其中,`<子查询名称>` 是用户定义的别名,`<子查询定义>` 是一个完整的 SELECT 语句,最终的查询部分可以引用这个别名。 #### 2. 提高可读性 通过将复杂的嵌套查询拆分为多个逻辑部分,`WITH AS` 可以显著提高 SQL 的可读性。例如: ```sql WITH A AS ( SELECT * FROM user ) SELECT * FROM A, customer WHERE customer.userid = A.id; ``` 在这个例子中,子查询 `A` 被定义为 `SELECT * FROM user`,然后在主查询中直接引用了 `A`,避免了重复书写查询片段 [^1]。 #### 3. 优化性能 `WITH AS` 在某些情况下可以优化查询性能,特别是当子查询被多次引用时。数据库优化器会自动将这些子查询的结果存储在一个临时表中,避免重复执行。例如: ```sql WITH sql1 AS ( SELECT to_char(a) s_name FROM test_tempa ), sql2 AS ( SELECT to_char(b) s_name FROM test_tempb WHERE NOT EXISTS (SELECT s_name FROM sql1 WHERE rownum = 1) ) SELECT * FROM sql1 UNION ALL SELECT * FROM sql2 UNION ALL SELECT 'no records' FROM dual WHERE NOT EXISTS (SELECT s_name FROM sql1 WHERE rownum = 1) AND NOT EXISTS (SELECT s_name FROM sql2 WHERE rownum = 1); ``` 在这个例子中,`sql1` 和 `sql2` 被多次引用,数据库优化器会将它们的结果缓存,从而减少重复执行的开销 [^4]。 #### 4. 与 `UNION ALL` 的结合使用 `WITH AS` 特别适合与 `UNION ALL` 结合使用,因为它可以避免在多个 `UNION ALL` 部分中重复执行相同的查询逻辑。例如: ```sql WITH data AS ( SELECT id, name FROM table1 UNION ALL SELECT id, name FROM table2 ) SELECT * FROM data WHERE id > 100; ``` 在这个例子中,`data` 是一个包含多个表数据的临时结果集,主查询只需对 `data` 进行过滤即可 [^2]。 #### 5. 强制物化 在某些数据库中(如 Oracle),可以通过 `MATERIALIZED` 提示强制将 `WITH AS` 的结果物化为临时表。例如: ```sql WITH data AS MATERIALIZED ( SELECT * FROM large_table ) SELECT * FROM data WHERE id > 100; ``` 这种方式可以显著提高性能,尤其是当子查询涉及大量数据时 [^2]。 ### 示例 #### 示例 1:简单用法 ```sql WITH A AS ( SELECT * FROM user ) SELECT * FROM A WHERE A.age > 30; ``` 在这个例子中,`A` 被定义为 `user` 表的所有数据,然后主查询对 `A` 进行过滤 [^1]。 #### 示例 2:多次引用 ```sql WITH sales_summary AS ( SELECT product_id, SUM(quantity) total_quantity FROM sales GROUP BY product_id ) SELECT s1.product_id, s1.total_quantity FROM sales_summary s1 JOIN sales_summary s2 ON s1.product_id = s2.product_id WHERE s1.total_quantity > 100; ``` 在这个例子中,`sales_summary` 被多次引用,优化器会自动将其结果缓存 [^2]。 #### 示例 3:与 `UNION ALL` 结合 ```sql WITH active_users AS ( SELECT id, name FROM users WHERE status = 'active' ), inactive_users AS ( SELECT id, name FROM users WHERE status = 'inactive' ) SELECT * FROM active_users UNION ALL SELECT * FROM inactive_users; ``` 在这个例子中,`active_users` 和 `inactive_users` 分别定义了不同的查询片段,然后通过 `UNION ALL` 合并结果 [^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值