339 lines
11 KiB
Markdown
339 lines
11 KiB
Markdown
# 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`。
|