# WITH

> 介绍了如何使用 `WITH` 关键字定义公共表表达式（CTE），包括基本语法和示例。

# WITH

使用 `WITH` 来指定一个公共表表达式（CTE）。

## 什么是公共表表达式（CTE）？

公共表表达式（CTE）是由 `WITH` 子句定义的临时结果集。后续查询可以多次引用同一个 CTE。

## CTE 的基本语法

CTE 通常使用 `WITH` 关键字定义。基本语法如下：

```sql
WITH cte_name [(column1, column2, ...)] AS (
    QUERY
)
SELECT ...
FROM cte_name;
```

## 示例

### 非递归 CTE

```sql
WITH cte AS (SELECT 0 AS number UNION ALL SELECT 1) SELECT * FROM cte t1, cte t2;
```

```sql
+--------+--------+
| number | number |
+--------+--------+
|      0 |      0 |
|      0 |      1 |
|      1 |      0 |
|      1 |      1 |
+--------+--------+
```

如果 CTE 名称后面有一个括起来的名称列表，这些名称就是 CTE 的列名，可以在查询里使用：

```sql
WITH cte (col1, col2) AS
(
  SELECT 1, 2
  UNION ALL
  SELECT 3, 4
)
SELECT col1, col2 FROM cte;
```

列表中的名称数量必须与结果集中的列数相同。

```sql
+------+------+
| col1 | col2 |
+------+------+
|    1 |    2 |
|    3 |    4 |
+------+------+
```

联合查询两个 CTE：

```sql
WITH
  cte1 AS (SELECT 0 AS a UNION ALL SELECT 1),
  cte2 AS (SELECT 0 AS b UNION ALL SELECT 1)
SELECT * FROM cte1 JOIN cte2
ON cte1.a = cte2.b;
```

```sql
+------+------+
| a    | b    |
+------+------+
|    1 |    1 |
|    0 |    0 |
+------+------+
```

### 递归 CTE

递归 CTE 用 `WITH RECURSIVE` 声明，由一个锚点项和一个按名字引用该 CTE 的递归项组成：

```sql
WITH RECURSIVE counter(n) AS (
  SELECT 1 AS n
  UNION ALL
  SELECT n + 1 FROM counter WHERE n < 5
)
SELECT n FROM counter;
```

```sql
+---+
| n |
+---+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
+---+
```

递归在某一轮不再产出新行时停止。引擎没有迭代次数上限，也不做环检测，因此只要递归项一直有输出，查询就会执行到被取消为止。
