WITH表达式
WITH表达式用于定义在大型查询中使用的辅助语句,这些辅助语句通常被称为公共表达式或CTE(即common table expr),可以理解为一个带名称的子查询,之后该子查询可以以其名称在查询中被多次引用。
WITH表达式中的辅助语句可以是SELECT,并且WITH子句本身也可以被附加到一个主语句中,主语句可以是SELECT、INSERT或DELETE。
WITH中的SELECT
在WITH子句中使用SELECT的相关信息。
语法格式
1
|
[WITH with_query [,…] ] SELECT … |
其中,with_query的语法为:
1 2 |
with_query_name [ ( column_name [, ...] ) ] AS [ [ NOT ] MATERIALIZED ] ( {select | values | insert | update | delete} ) |

- 显示指定MATERIALIZED时,将子查询执行一次,并将其结果集进行物化;指定NOT MATERIALIZED时,则将其子查询替换到主查询中的引用处。
- 每个CTE的AS语句指定的SQL语句,必须是可以返回查询结果的语句,目前只支持SELECT查询语句,暂不支持INSERT、UPDATE、DELETE、VALUES等其它数据修改语句。
- 单个WITH表达式表示一个SQL语句块中的CTE定义,可以同时定义多个CTE,每个CTE可以指定列名,也可以默认使用查询输出列的别名。例如:
1
WITH s1(a, b) AS (SELECT x, y FROM t1), s2 AS (SELECT x, y FROM t2) SELECT * FROM s1 JOIN s2 ON s1.a=s2.x;
该语句中定义了两个CTE,s1和s2,其中s1指定了列名为a,b,s2未指定列名,则列名为输出列名x,y。
- 每个CTE可以在主查询中引用0次、1次或多次。
- 同一个语句块中不能出现同名的CTE,但不同语句块中可以出现同名的CTE,此时,语句中引用的CTE则是距离引用位置最近的语句块中的CTE。
- 由于SQL语句中可能包含多个SQL语句块,每个语句块都可以包含一个WITH表达式,每个WITH表达式中的CTE可以在当前语句块、当前语句块的后续CTE中,以及子层语句块中引用,但不能在父层语句块中引用。由于每个CTE的定义也是个语句块,因此也支持在该语句块中定义WITH表达式。
WITH中SELECT的基本价值是将复杂的查询分解称为简单的部分。示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
WITH regional_sales AS ( SELECT region, SUM(amount) AS total_sales FROM orders GROUP BY region ), top_regions AS ( SELECT region FROM regional_sales WHERE total_sales > (SELECT SUM(total_sales)/10 FROM regional_sales) ) SELECT region, product, SUM(quantity) AS product_units, SUM(amount) AS product_sales FROM orders WHERE region IN (SELECT region FROM top_regions) GROUP BY region, product; |
WITH子句定义了两个辅助语句regional_sales和top_regions,其中regional_sales的输出用在top_regions中而top_regions的输出用在主SELECT查询。这个例子可以不用WITH来书写,但是就必须要用两层嵌套的子SELECT,使得查询更长更难以维护。