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

11 KiB
Raw Blame History

TSL TS-SQL

文档类型:语法主线 是否可直接用于生成代码:是 是否含可直接照写示例:是 是否含不可照写反例:是 遇到不确定时:先按本页候选页继续判断;13_resultset_and_filters.md12_matrix_and_collections.md23_fmarray.md;仍不命中时回到语法路由中心 index.md;如果问题已经超出语法层,回到 TSL 总入口 ../index.md

这一篇是 TS-SQL 的唯一语法入口:内存数组查询、返回形态、字段访问、where / group by / order by、一维数组查询、多表 jointhisGroupthisRowIndexrefMaxOf / refMinOf 都在这里收拢。

本篇职责

回答“写 TS-SQL 查询时,怎样从最小 select ... from ... end 骨架开始,逐步处理筛选、分组、排序、多表联接、组内子查询和极值引用”。

智能体 TS-SQL 判断流程

  1. 先判断要写 selectsselectvselectmselect,还是 join / thisGroup / 极值引用。
  2. 内存数组查询优先从 select ... from source_rows end 最小骨架起手。
  3. 二维结果集字段访问用 ["字段名"];多表查询字段访问用 [表序号].["字段名"]
  4. 在一维数组上做 TS-SQL 时,优先使用 thisRowthisRowIndex
  5. 只想按已有结果集保留/排除行时跳到 13_resultset_and_filters.md;要做去重型集合关系时跳到 12_matrix_and_collections.md;要在 FMArray 上做查询或写回边界时跳到 23_fmarray.md
  6. 没有对应代码块时不要发明 TS-SQL 写法。

核心规则

  • TS-SQL 是 TSL 自带的类 SQL 查询语法,不是金融业务函数库。
  • 基础查询文档骨架是:以 select / sselect / vselect / mselect 开始,以 end 收尾。
  • from 后面可以直接跟内存数组结果集。
  • 在内存二维结果集上,文档字段访问写法是 ["字段名"]
  • 在一维数组上做 TS-SQL 时,优先使用 thisRowthisRowIndex
  • select 返回二维结果,sselect 返回一维结果,vselect 返回单值,mselect 返回 Matrix
  • wheregroup byorder by 可以直接接在 from 后面继续使用。
  • 多表 join 时,字段访问应写成 [表序号].["字段名"]
  • thisGroup 不是普通值,而是分组后的子结果集;要通过子 select / vselectfrom thisGroup 来访问。
  • thisRowIndexorder by 之后仍可返回原始行位置,而不是排序后的序号。
  • refMaxOf(...)refMinOf(...) 可与 maxOf(...) / minOf(...) 配合,取极值所在行的另一列值。
  • 访问金融表、时间序列或业务数据源时,语法和业务语义要分开看;本页只讲语言层查询骨架。

可直接照写示例

最小查询骨架

代码块身份:可直接照写示例

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

代码块身份:输出片段

2

字段选择

代码块身份:可直接照写示例

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 会按原顺序返回二维结果集

四个查询入口怎样分工

代码块身份:可直接照写示例

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 且保留行列信息”写成文档主干;不要在本页发明直接单元格读取规则

whereorder by

代码块身份:可直接照写示例

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

代码块身份:可直接照写示例

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" 指定返回列名

一维数组上的 thisRowthisRowIndex

代码块身份:可直接照写示例

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

代码块身份:可直接照写示例

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].["字段"] 这种多表字段访问属于文档明确写法

代码块身份:输出片段

1
1
10
100

thisGroup

代码块身份:可直接照写示例

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 在排序后仍指向原始位置

代码块身份:可直接照写示例

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 仍返回原表中的原始下标

refMaxOfrefMinOf

代码块身份:可直接照写示例

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../modules/pytsl_api.md 或项目实际接口。

默认生成模板

TS-SQL 的最短默认骨架如下:

代码块身份:可直接照写示例

query_result := select * from source_rows end;

禁止项

  • 不要把数据库 SQL 方言直接迁移成 TS-SQL 代码。
  • 不要把 select 当成普通函数调用,忘了以 end 收尾。
  • 在二维结果集里直接写 A 而不是 ["A"]
  • 多表联接时继续写成 ["ID"],没有加表序号。
  • 处理一维数组时直接把 [0] 当成稳定列访问。
  • thisGroup 当成普通字段或普通变量。
  • 把排序后的 thisRowIndex 误当成排序序号。
  • with on、写回接口和时间序列缓存写进默认模板。

代码块身份:反例 / 不可照写

query_result := select A from source_rows end;

上面这种写法不要当成本页可靠规则。二维结果集字段访问,本页只把 ["A"] 这种写法写成文档主干。

代码块身份:反例 / 不可照写

query_result := select [0] from values end;

这种对一维数组直接用 [0] 的写法虽然返回长度为 3 的结果,但取到的值是 nil,不能当成可靠入口。对一维数组应改用 thisRowthisRowIndex

代码块身份:反例 / 不可照写

query_result := select ["ID"], ["V1"], ["V2"]
                from left_rows join right_rows on ["ID"] = ["ID"]
                end;

上面这种写法不要当成本页可靠规则。多表查询里,本页只把 [1].["字段"][2].["字段"] 这种带表序号的访问方式写成文档主干。

代码块身份:反例 / 不可照写

group_value := thisGroup;

不要把 thisGroup 当成普通值直接使用。可靠入口是 select ... from thisGroup endvselect ... from thisGroup end