playbook/docs/tsl/syntax/14_ts_sql.md

339 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TSL TS-SQL
文档类型:语法主线
是否可直接用于生成代码:是
是否含可直接照写示例:是
是否含不可照写反例:是
遇到不确定时:先按本页候选页继续判断;[13_resultset_and_filters.md](13_resultset_and_filters.md)、[12_matrix_and_collections.md](12_matrix_and_collections.md)、[23_fmarray.md](23_fmarray.md);仍不命中时回到语法路由中心 [index.md](index.md);如果问题已经超出语法层,回到 TSL 总入口 [../index.md](../index.md)
这一篇是 TS-SQL 的唯一语法入口:内存数组查询、返回形态、字段访问、`where` / `group by` / `order by`、一维数组查询、多表 `join`、`thisGroup`、`thisRowIndex`、`refMaxOf` / `refMinOf` 都在这里收拢。
## 本篇职责
回答“写 TS-SQL 查询时,怎样从最小 `select ... from ... end` 骨架开始,逐步处理筛选、分组、排序、多表联接、组内子查询和极值引用”。
## 智能体 TS-SQL 判断流程
1. 先判断要写 `select`、`sselect`、`vselect`、`mselect`,还是 `join` / `thisGroup` / 极值引用。
2. 内存数组查询优先从 `select ... from source_rows end` 最小骨架起手。
3. 二维结果集字段访问用 `["字段名"]`;多表查询字段访问用 `[表序号].["字段名"]`
4. 在一维数组上做 TS-SQL 时,优先使用 `thisRow``thisRowIndex`
5. 只想按已有结果集保留/排除行时跳到 [13_resultset_and_filters.md](13_resultset_and_filters.md);要做去重型集合关系时跳到 [12_matrix_and_collections.md](12_matrix_and_collections.md);要在 `FMArray` 上做查询或写回边界时跳到 [23_fmarray.md](23_fmarray.md)。
6. 没有对应代码块时不要发明 TS-SQL 写法。
## 核心规则
- TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。
- 基础查询文档骨架是:以 `select` / `sselect` / `vselect` / `mselect` 开始,以 `end` 收尾。
- `from` 后面可以直接跟内存数组结果集。
- 在内存二维结果集上,文档字段访问写法是 `["字段名"]`
- 在一维数组上做 TS-SQL 时,优先使用 `thisRow``thisRowIndex`
- `select` 返回二维结果,`sselect` 返回一维结果,`vselect` 返回单值,`mselect` 返回 `Matrix`
- `where`、`group by`、`order by` 可以直接接在 `from` 后面继续使用。
- 多表 `join` 时,字段访问应写成 `[表序号].["字段名"]`
- `thisGroup` 不是普通值,而是分组后的子结果集;要通过子 `select` / `vselect``from thisGroup` 来访问。
- `thisRowIndex``order by` 之后仍可返回原始行位置,而不是排序后的序号。
- `refMaxOf(...)``refMinOf(...)` 可与 `maxOf(...)` / `minOf(...)` 配合,取极值所在行的另一列值。
- 访问金融表、时间序列或业务数据源时,语法和业务语义要分开看;本页只讲语言层查询骨架。
## 可直接照写示例
### 最小查询骨架
代码块身份:可直接照写示例
```tsl
source_rows := array(
("A": 1, "B": 3),
("A": 2, "B": 1)
);
query_result := select * from source_rows end;
writeLn(length(query_result));
```
结果说明:
- `query_result` 的长度是 `2`
- 两行依次是 `(1,3)`、`(2,1)`
- 说明 TS-SQL 的最短可靠入口就是“准备结果集,然后 `select ... from source_rows end`
代码块身份:输出片段
```text
2
```
### 字段选择
代码块身份:可直接照写示例
```tsl
source_rows := array(
("A": 1, "B": 3),
("A": 2, "B": 1),
("A": 1, "B": 2)
);
query_result := select ["A"], ["B"] from source_rows end;
writeLn(length(query_result));
```
结果说明:
- `query_result` 的长度是 `3`
- 三行依次是 `(1,3)`、`(2,1)`、`(1,2)`
- 说明 `select ["A"], ["B"] from source_rows end` 会按原顺序返回二维结果集
### 四个查询入口怎样分工
代码块身份:可直接照写示例
```tsl
source_rows := array(
("A": 1, "B": 3),
("A": 2, "B": 1),
("A": 1, "B": 2)
);
selected_values := sselect ["A"] from source_rows end;
sum_value := vselect sumOf(["B"]) from source_rows end;
matrix_result := mselect * from source_rows end;
col_index := mcols(matrix_result, 1);
```
结果说明:
- `sselect ["A"] from source_rows end` 返回一维数组 `array(1, 2, 1)`
- `vselect sumOf(["B"]) from source_rows end` 返回单值 `6`
- `mselect * from source_rows end` 的行数是 `3`、列数是 `2`
- `mcols(matrix_result, 1)` 返回列索引 `array("A", "B")`
- 本页只把 `mselect` 的“返回 Matrix 且保留行列信息”写成文档主干;不要在本页发明直接单元格读取规则
### `where` 和 `order by`
代码块身份:可直接照写示例
```tsl
source_rows := array(
("A": 1, "B": 3),
("A": 2, "B": 1),
("A": 1, "B": 2)
);
query_result := select * from source_rows where ["B"] > 1 order by ["B"] end;
```
结果说明:
- `query_result` 的长度是 `2`
- 两行依次是 `(1,2)`、`(1,3)`
- 说明 `where ["B"] > 1` 会先筛选,再按 `order by ["B"]` 的升序返回
### `group by`
代码块身份:可直接照写示例
```tsl
source_rows := array(
("A": 1, "B": 3),
("A": 2, "B": 1),
("A": 1, "B": 2)
);
group_result := select ["A"], sumOf(["B"]) as "SumB"
from source_rows
group by ["A"]
order by ["A"]
end;
```
结果说明:
- `group_result` 的长度是 `2`
- 第一行是 `(1,5)`
- 第二行是 `(2,1)`
- 说明 `group by ["A"]` 后可以直接接聚集函数,并用 `as "SumB"` 指定返回列名
### 一维数组上的 `thisRow` 与 `thisRowIndex`
代码块身份:可直接照写示例
```tsl
values := array(10, 20, 30);
row_values := sselect thisRow from values end;
row_indexes := sselect thisRowIndex from values end;
query_result := select thisRow as "Value", thisRowIndex as "Idx"
from values
where thisRow > 15
order by thisRow
end;
```
结果说明:
- `sselect thisRow from values end` 返回 `array(10, 20, 30)`
- `sselect thisRowIndex from values end` 返回 `array(0, 1, 2)`
- 上面的 `select ... from values where thisRow > 15 order by thisRow end` 返回两行:第一行 `Value=20, Idx=1`,第二行 `Value=30, Idx=2`
### `join`
代码块身份:可直接照写示例
```tsl
left_rows := array(
("ID": 1, "V1": 10),
("ID": 2, "V1": 20)
);
right_rows := array(
("ID": 1, "V2": 100),
("ID": 3, "V2": 300)
);
join_result := select [1].["ID"], [1].["V1"], [2].["V2"]
from left_rows join right_rows on [1].["ID"] = [2].["ID"]
end;
writeLn(length(join_result));
writeLn(join_result[0]["ID"]);
writeLn(join_result[0]["V1"]);
writeLn(join_result[0]["V2"]);
```
结果说明:
- `join_result` 的长度是 `1`
- 唯一一行是 `(1,10,100)`
- 说明 `from left_rows join right_rows on ...``[1].["字段"]`、`[2].["字段"]` 这种多表字段访问属于文档明确写法
代码块身份:输出片段
```text
1
1
10
100
```
### `thisGroup`
代码块身份:可直接照写示例
```tsl
source_rows := array(
("A": 1, "B": 3, "Name": "x"),
("A": 2, "B": 1, "Name": "y"),
("A": 1, "B": 2, "Name": "z")
);
group_result := select ["A"], maxb := maxOf(["B"]) as "MaxB",
vselect ["Name"] from thisGroup where ["B"] = maxb end as "TopName"
from source_rows
group by ["A"]
order by ["A"]
end;
```
结果说明:
- `group_result` 的长度是 `2`
- 第一行是 `(1,3,"x")`
- 第二行是 `(2,1,"y")`
- 说明 `thisGroup` 可以在分组上下文里作为子结果集继续 `vselect`
### `thisRowIndex` 在排序后仍指向原始位置
代码块身份:可直接照写示例
```tsl
source_rows := array(
("A": 1, "B": 3),
("A": 2, "B": 1),
("A": 1, "B": 2)
);
query_result := select thisRowIndex as "Idx", ["B"]
from source_rows
order by ["B"]
end;
```
结果说明:
- `query_result` 的三行依次是 `(1,1)`、`(2,2)`、`(0,3)`
- 说明 `order by ["B"]` 之后,`thisRowIndex` 仍返回原表中的原始下标
### `refMaxOf` 与 `refMinOf`
代码块身份:可直接照写示例
```tsl
source_rows := array((6, 20), (5, 20), (9, 2), (2, 20), (7, 18));
max_ref_result := select maxOf([0]) as "MaxA", refMaxOf([1]) as "RefB" from source_rows end;
min_ref_result := select minOf([0]) as "MinA", refMinOf([1]) as "RefB" from source_rows end;
```
结果说明:
- `max_ref_result` 只有一行,结果是 `(9,2)`
- `min_ref_result` 只有一行,结果是 `(2,20)`
- 说明 `refMaxOf([1])` 取到了 `[0]` 最大值所在行的 `[1]``refMinOf([1])` 取到了 `[0]` 最小值所在行的 `[1]`
## 本页不生成的范围
- `with on`
- `left join` / `right join` / `full join`
- `RefsOf`
- `insert` / `update` / `delete`
- `TSQLInsert` / `TSQLSetValue` / `TSQLBatchInsert`
- `TSQLEdit` / `TSQLPost` / `TSQLFinal`
- 面向 SQL 表、业务表或时间序列的数据查询与写回
这些内容不作为本页可生成事实;业务数据源先查 [../reference/catalog/datawarehouse.md](../reference/catalog/datawarehouse.md)、[../modules/pytsl_api.md](../modules/pytsl_api.md) 或项目实际接口。
## 默认生成模板
TS-SQL 的最短默认骨架如下:
代码块身份:可直接照写示例
```tsl
query_result := select * from source_rows end;
```
## 禁止项
- 不要把数据库 SQL 方言直接迁移成 TS-SQL 代码。
- 不要把 `select` 当成普通函数调用,忘了以 `end` 收尾。
- 在二维结果集里直接写 `A` 而不是 `["A"]`
- 多表联接时继续写成 `["ID"]`,没有加表序号。
- 处理一维数组时直接把 `[0]` 当成稳定列访问。
-`thisGroup` 当成普通字段或普通变量。
- 把排序后的 `thisRowIndex` 误当成排序序号。
-`with on`、写回接口和时间序列缓存写进默认模板。
代码块身份:反例 / 不可照写
```text
query_result := select A from source_rows end;
```
上面这种写法不要当成本页可靠规则。二维结果集字段访问,本页只把 `["A"]` 这种写法写成文档主干。
代码块身份:反例 / 不可照写
```text
query_result := select [0] from values end;
```
这种对一维数组直接用 `[0]` 的写法虽然返回长度为 `3` 的结果,但取到的值是 `nil`,不能当成可靠入口。对一维数组应改用 `thisRow``thisRowIndex`
代码块身份:反例 / 不可照写
```text
query_result := select ["ID"], ["V1"], ["V2"]
from left_rows join right_rows on ["ID"] = ["ID"]
end;
```
上面这种写法不要当成本页可靠规则。多表查询里,本页只把 `[1].["字段"]`、`[2].["字段"]` 这种带表序号的访问方式写成文档主干。
代码块身份:反例 / 不可照写
```text
group_value := thisGroup;
```
不要把 `thisGroup` 当成普通值直接使用。可靠入口是 `select ... from thisGroup end``vselect ... from thisGroup end`