# 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`。