Skip to content

Commit

Permalink
docs(sql): update SQL syntax for WINDOW and JOIN
Browse files Browse the repository at this point in the history
SQL changes mainly from #3533 and #3554
  • Loading branch information
aceforeverd committed Oct 16, 2023
1 parent 8c8d070 commit bd277f9
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,23 @@ OpenMLDB仅支持上线[SELECT查询语句](../dql/SELECT_STATEMENT.md)。

下表列出了在线请求模式支持的 `SELECT` 子句。

| SELECT 子句 | 说明 |
|:-------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------|
| 单张表的简单表达式计算 | 简单的单表查询是对一张表进行列运算、使用运算表达式或单行处理函数(Scalar Function)以及它们的组合表达式作计算。需要遵循[在线请求模式下单表查询的使用规范](#在线请求模式下单表查询的使用规范) |
| [`JOIN` 子句](../dql/JOIN_CLAUSE.md) | OpenMLDB目前仅支持**LAST JOIN**。需要遵循[在线请求模式下LAST JOIN的使用规范](#在线请求模式下-last-join-的使用规范) |
| SELECT 子句 | 说明 |
| :--------------------------------------- | :----------------------------------------------------------- |
| 无表查询 | SELECT 没有 FROM 子句, 只做表达式计算 |
| 单张表的简单表达式计算 | 简单的单表查询是对一张表进行列运算、使用运算表达式或单行处理函数(Scalar Function)以及它们的组合表达式作计算。需要遵循[在线请求模式下单表查询的使用规范](#在线请求模式下单表查询的使用规范) |
| [`JOIN` 子句](../dql/JOIN_CLAUSE.md) | OpenMLDB目前仅支持**LAST JOIN**。需要遵循[在线请求模式下LAST JOIN的使用规范](#在线请求模式下-last-join-的使用规范) |
| [`WINDOW` 子句](../dql/WINDOW_CLAUSE.md) | 窗口子句用于定义一个或者若干个窗口。窗口可以是有名或者匿名的。用户可以在窗口上调用聚合函数进行分析计算。需要遵循[在线请求模式下Window的使用规范](#在线请求模式下window的使用规范) |

## 在线请求模式下 `SELECT` 子句的使用规范

### 无表查询

```sql
SELECT sin(30) as out;
```



### 在线请求模式下单表查询的使用规范

- 仅支持列运算,表达式,以及单行处理函数(Scalar Function)以及它们的组合表达式运算。
Expand Down Expand Up @@ -57,15 +66,16 @@ SELECT substr(COL7, 3, 6) FROM t1;

### 在线请求模式下 `LAST JOIN` 的使用规范

- 仅支持`LAST JOIN`类型。
- 至少有一个JOIN条件是形如`left_source.column=right_source.column`的EQUAL条件,**并且`right_source.column`列需要命中右表的索引(key 列)**
- 带排序LAST JOIN的情况下,`ORDER BY`只支持单列的列引用表达式,列类型为 int16, int32, int64 or timestamp, **并且列需要命中右表索引的时间列**
- 右表 TableRef
1. 仅支持`LAST JOIN`类型。
2. 至少有一个JOIN条件是形如`left_source.column=right_source.column`的EQUAL条件,**并且`right_source.column`列需要命中右表的索引(key 列)**
3. 带排序LAST JOIN的情况下,`ORDER BY`只支持单列的列引用表达式,列类型为 int16, int32, int64 or timestamp, **并且列需要命中右表索引的时间列**满足条件 2 和 3 的情况我们简单称做表能被 LAST JOIN 的 JOIN 条件优化
4. 右表 TableRef
- 可以指一张物理表, 或者子查询语句
- 子查询情况, 只支持
- 简单列筛选 (`select * from tb` or `select id, val from tb`)
- 窗口聚合子查询, 例如 `select id, count(val) over w as cnt from t1 window w as (...)`. 这种情况下, 子查询和 last join 的左表必须有相同的主表, 主表指计划树下最左边的物理表节点.
- **Since OpenMLDB 0.8.0** 带 WHERE 条件过滤的简单列筛选 ( 例如 `select * from tb where id > 10`)
- **Since OpenMLDB 0.8.4** 右表是带 LAST JOIN 的子查询 `subquery`, 要求 `subquery` 最左的表能被 JOIN 条件优化, `subquery`剩余表能被自身 LAST JOIN 的 JOIN 条件优化

**Example: 支持上线的 `LAST JOIN` 语句范例**
创建两张表以供后续`LAST JOIN`
Expand Down Expand Up @@ -115,15 +125,46 @@ desc t1;
t1.col0 as t1_col0,
t1.col1 + t2.col1 + 1 as test_col1,
FROM t1
LAST JOIN t2 ORDER BY t2.std_time ON t1.col1=t2.col1;
LAST JOIN t2 ORDER BY t2.std_time ON t1.col1=t2.col1;
```

右表是带 LAST JOIN 或者 WHERE 条件过滤的情况

```sql
CREATE TABLE t3 (col0 STRING, col1 int, std_time TIMESTAMP, INDEX(KEY=col1, TS=std_time, TTL_TYPE=absolute, TTL=30d));
-- SUCCEED

SELECT
t1.col1 as t1_col1,
t2.col1 as t2_col1,
t2.col0 as t2_col0
FROM t1 LAST JOIN (
SELECT * FROM t2 WHERE strlen(col0) > 0
) t2
ON t1.col1 = t2.col1

-- t2 被 JOIN 条件 't1.col1 = tx.t2_co1l' 优化, t3 被 JOIN 条件 't2.col1 = t3.col1'
SELECT
t1.col1 as t1_col1,
tx.t2_col1,
tx.t3_col1
FROM t1 LAST JOIN (
SELECT t2.col1 as t2_col1, t3.col1 as t3_col1
FROM t2 LAST JOIN t3
ON t2.col1 = t3.col1
) tx
ON t1.col1 = tx.t2_col1
```



### 在线请求模式下Window的使用规范

- 窗口边界仅支持`PRECEDING``CURRENT ROW`
- 窗口类型仅支持`ROWS``ROWS_RANGE`
- 窗口`PARTITION BY`只支持列表达式,可以是多列,并且所有列需要命中索引,主表和 union source 的表都需要符合要求
- 窗口`ORDER BY`只支持列表达式,只能是单列,并且列需要命中索引的时间列,主表和 union source 的表都需要符合要求
- 窗口`ORDER BY`只支持列表达式,只能是单列,并且列需要命中索引的时间列,主表和 union source 的表都需要符合要求. 从 OpenMLDB 0.8.4 开始, ORDER BY 可以不写, 但需要满足额外的要求, 详见 [WINDOW CLAUSE](../dql/WINDOW_CLAUSE.md)
- **OpenMLDB 0.8.4 版本开始, 支持窗口定义不带 ORDER BY**, 具体要求如
- 可支持使用 `EXCLUDE CURRENT_ROW``EXCLUDE CURRENT_TIME``MAXSIZE``INSTANCE_NOT_IN_WINDOW`对窗口进行其他特殊限制,详见[OpenMLDB特有的 WindowSpec 元素](#openmldb特有的-windowspec-元素)
- `WINDOW UNION` source 要求,支持如下格式的子查询:
- 表引用或者简单列筛选,例如 `t1` 或者 `select id, val from t1`。union source 和 主表的 schema 必须完全一致,并且 union source 对应的 `PARTITION BY`, `ORDER BY` 也需要命中索引
Expand Down
15 changes: 12 additions & 3 deletions docs/zh/openmldb_sql/dql/WINDOW_CLAUSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ partition key相等的所有行,还不是窗口,经由order by列排序后

## 基本的 WindowSpec 语法元素

### Window Partition Clause 和 Window OrderBy Clause
### WINDOW PARTITION BY clause 和 WINDOW ORDER BY clause

```sql
WindowPartitionClause
Expand All @@ -129,9 +129,18 @@ WindowOrderByClause
::= ( 'ORDER' 'BY' ByList )
```

`PARTITION BY`选项将查询的行分为一组进入*partitions*, 这些行在窗口函数中单独处理。`PARTITION BY`和查询级别`GROUP BY` 子句做相似的工作,除了它的表达式只能作为表达式不能作为输出列的名字或数。OpenMLDB要求必须配置`PARTITION BY`。并且目前**仅支持按列分组**,无法支持按运算和函数表达式分组。
`PARTITION BY`选项将查询的行分为一组进入*partitions*, 这些行在窗口函数中单独处理。`PARTITION BY`和查询级别`GROUP BY` 子句做相似的工作, 只是它只能作为表达式不能作为查询结果的输出列或输出列 ID。OpenMLDB要求必须配置`PARTITION BY`。PARTITION BY list 可以有多个, 但**仅支持按列分组**,无法支持按运算或函数表达式分组。

`ORDER BY` 选项决定分区中的行被窗口函数处理的顺序。它和查询级别`ORDER BY`子句做相似的工作, 同样不能作为查询结果的输出列或者输出列 ID。OpenMLDB 目前**仅支持按列排序**,ORDER BY list 有且只能有一个, 不支持按运算或函数表达式排序。**OpenMLDB 0.8.4** 以后, ORDER BY 子句可以不写, 表示窗口内的列将以不确定的顺序处理, 不带 ORDER BY 子句需要满足如下条件:

1. 不能有`EXCLUDE CURRENT_TIME`
2. 对于 ROWS 类型窗口没有更多限制, 对于 ROWS_RANGE 类型窗口:
1. 窗口 FRAME 的边界不能是 `offset [OPEN] PRECEDING/FOLLOWING` 的格式, 目前情况只能为 `UNBOUNDED PRECEDING AND CURRENT ROW`

```{note}
窗口不带 ORDER BY 的情况, 意味着对于在线预览模式, 计算结果是不确定的. 同时对于一些通用窗口函数, 例如 `lag, first_value`, 在所有模式下得到的计算结果都是不确定的.
```

`ORDER BY` 选项决定分区中的行被窗口函数处理的顺序。它和查询级别`ORDER BY`子句做相似的工作, 但是同样的它不能作为输出列的名字或数。同样,OpenMLDB要求必须配置`ORDER BY`。并且目前**仅支持按列排序**,无法支持按运算和函数表达式排序。

### Window Frame Clause

Expand Down
12 changes: 6 additions & 6 deletions docs/zh/openmldb_sql/sql_difference.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ WINDOW 子句和 GROUP BY & HAVING 子句不支持同时使用。上线时 WINDO

特殊限制:

- 在线请求模式下,WINDOW 的输入是 LAST JOIN 或者子查询内的 LAST JOIN, 注意窗口的定义里 `PARTITION BY` & `ORDER BY` 的列都必须来自 JOIN 最左边的表。
- 在线请求模式下,WINDOW 的输入是 LAST JOIN 或者带子查询内的 LAST JOIN, 注意窗口的定义里 `PARTITION BY` & `ORDER BY` 的列都必须来自 JOIN 最左边的表。

### GROUP BY & HAVING 子句

Expand All @@ -101,7 +101,7 @@ OpenMLDB 仅支持 LAST JOIN 一种 JOIN 语法,详细描述参考扩展语法
| **应用于** | **离线模式** | **在线预览模式** | **在线请求模式** |
| ------------------------------------------------------------ | ------------ | ---------------- | ---------------- |
| 两个表引用 ||||
| 子查询, 仅包括:<br>左右表均为简单列筛选<br>左右表为 WINDOW 或 LAST JOIN 操作 ||||
| 子查询, 仅包括:<br>左右表均为简单列筛选<br>左右表为 WINDOW 或 LAST JOIN 操作<br>带 WHERE 条件过滤的单表查询 ||||

特殊限制:

Expand All @@ -118,7 +118,7 @@ OpenMLDB (>= v0.7.2) 支持非递归的 WITH 子句。WITH 子句等价于其它

### ORDER BY 关键字

排序关键字 `ORDER BY` 仅在窗口定义 `WINDOW` 和拼表操作 `LAST JOIN` 子句内部被支持,并且不支持倒排序关键字 `DESC`。参见 WINDOW 子句和 LAST JOIN 子句内的相关说明。
排序关键字 `ORDER BY` 仅在窗口定义 `WINDOW` 和拼表操作 `LAST JOIN` 子句内部被支持,并且不支持倒排序关键字 `DESC` OpenMLDB 0.8.4 以后支持窗口定义不带 ORDER BY, 但需额外满足特定条件. 参见 WINDOW 子句和 LAST JOIN 子句内的相关说明。

### 聚合函数

Expand Down Expand Up @@ -149,10 +149,10 @@ OpenMLDB 主要对 `WINDOW` 以及 `LAST JOIN` 语句进行了深度定制化开
| **语句元素** | **支持语法** | **说明** | **必需 ?** |
| ---------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | ----------- |
| 数据定义 | PARTITION BY | 可支持多列<br>支持的列数据类型: bool, int16, int32, int64, string, date, timestamp ||
| 数据排序 | ORDER BY | 仅支持对单一列排序<br>可支持数据类型: int16, int32, int64, timestamp<br>不支持倒序 `DESC` | |
| 数据排序 | ORDER BY | 仅支持对单一列排序<br>可支持数据类型: int16, int32, int64, timestamp<br>不支持倒序 `DESC`<br>OpenMLDB 0.8.4 之前必填 | - |
| 范围定义 | <br>基本上下界定义语法:ROWS/ROWS_RANGE BETWEEN ... AND ...<br>支持范围定义关键字 PRECEDING, OPEN PRECEDING, CURRENT ROW, UNBOUNDED | 必须给定上下边界<br>不支持边界关键字 FOLLOWING<br>在线请求模式中,CURRENT ROW 为当前的请求行。在表格视角下,当前行将会被虚拟的插入到表格根据 ORDER BY 排序的正确位置上。 ||
| 范围单位 | ROWS<br>ROWS_RANGE(扩展) | ROWS_RANGE 为扩展语法,其定义的窗口边界属性等价于标准 SQL 的 RANGE 类型窗口,支持用数值或者带时间单位的数值定义窗口边界,后者为拓展语法。<br>带时间单位定义的窗口范围,等价于时间转化成毫秒数值后的窗口定义。例如 `ROWS_RANGE 10s PRCEDING ...``ROWS_RANGE 10000 PRECEDNG ...` 是等价的。 ||
| 窗口属性(扩展) | MAXSIZE <br>EXCLUDE CURRENT_ROW<br>EXCLUDE CURRENT_TIME<br>INSTANCE_NOT_IN_WINDOW | MAXSIZE 只对 ROWS_RANGE 有效 | - |
| 范围单位 | ROWS<br>ROWS_RANGE(扩展) | ROWS_RANGE 为扩展语法,其定义的窗口边界属性等价于标准 SQL 的 RANGE 类型窗口,支持用数值或者带时间单位的数值定义窗口边界,后者为拓展语法。<br>带时间单位定义的窗口范围,等价于时间转化成毫秒数值后的窗口定义。例如 `ROWS_RANGE 10s PRCEDING ...``ROWS_RANGE 10000 PRECEDNG ...` 是等价的。 ||
| 窗口属性(扩展) | MAXSIZE <br>EXCLUDE CURRENT_ROW<br>EXCLUDE CURRENT_TIME<br>INSTANCE_NOT_IN_WINDOW | MAXSIZE 只对 ROWS_RANGE 有效<br>不带 ORDER BY 和 EXCLUDE CURRENT_TIME 不能同时使用 | - |
| 多表定义(扩展) | 实际使用中语法形态较为复杂,参考:<br>[跨表特征开发教程](../tutorial/tutorial_sql_2.md)<br>[WINDOW UNION 语法文档](../openmldb_sql/dql/WINDOW_CLAUSE.md#1-window--union) | 允许合并多个表<br>允许联合简单子查询<br>实践中,一般和聚合函数搭配使用,实现跨表的聚合操作 | - |
| 匿名窗口 | - | 必须包括 PARTITION BY、ORDER BY、以及窗口范围定义 | - |

Expand Down

0 comments on commit bd277f9

Please sign in to comment.