本节简要介绍窗口函数等进阶用法,需要时再结合官方语法或产品文档深入。
在「每行保留明细」的前提下,按某维度分组、排序,在组内计算排名、累计和、组内均值等,使用 over 定义窗口。
常用函数:
|
函数 |
说明 |
|---|---|
|
|
组内行号(1, 2, 3, …) |
|
|
排名,同值同排名且留空位 |
|
|
密集排名,同值同排名不留空位 |
|
|
组内相对排名(0~1) |
聚合也可 over 窗口:如 sum(.字段) over (group by ... order by ...)。
方式一:with 中定义窗口,再在 select 中 over win。按订单分组,对订单行按行金额排序并排名、组内金额合计。
with win as window (
OrderLine
group by .order
order by .qty * .price desc
)
select OrderLine {
line_no,
product_name,
qty,
price,
order: { order_no },
rk := win::rank() over win,
order_line_total := sum(.qty * .price) over win
}
order by .order.order_no then .qty * .price desc
方式二:在 select 中就地写 over。订单行按所属订单分组、按单价降序排名。
select OrderLine {
line_no,
product_name,
price,
order: { order_no },
rk := win::rank() over (group by .order order by .price desc)
}
order by .order.order_no then .price desc
结果示意:
[
{ "line_no": 1, "product_name": "商品A", "price": 99.00, "order": { "order_no": "ORD001" }, "rk": 1 },
{ "line_no": 2, "product_name": "商品B", "price": 50.00, "order": { "order_no": "ORD001" }, "rk": 2 }
]
图查询是一种特殊的结果组织方式:最终输出包含两个固定 key——nodes(节点)和 edges(边),用于 UX 图表组件中图结构的数据源渲染。
适用场景:
父子关系图(如组织架构)
指标依赖图(如 KPI 拆解树)
数据血缘图(如 ETL 上下游)
任何可以表达为「节点 + 有向边」的关系
图查询的结果必须是一个对象,包含 nodes 和 edges 两个数组字段:
|
字段 |
类型 |
说明 |
|---|---|---|
|
nodes |
数组 |
节点列表 |
|
nodes[]._id |
str |
节点唯一标识(可以是 id 或业务主键),必填 |
|
nodes[].label |
str |
节点显示名称,必填 |
|
edges |
数组 |
边列表 |
|
edges[].source |
str |
边的起点节点 |
|
edges[].target |
str |
边的终点节点 |
_id 和 label 是图组件的默认字段。_id 必须在 nodes 中唯一,edges 的 source / target 值必须是 nodes 中已有的 _id。
查询某个组织及其所有下级,构建组织架构图。这里用 eff_his_parent_org 计算链接表示层级关系(参见「八、层级与树形」中的 L"链接编码" 用法)。
with
org := (
select
cal::idescendant(<Organization>"60020113", L"eff_his_parent_org")
),
select {
nodes := org {
_id := .code,
label := .name,
},
-- 父指向子
edges := (
source := org.eff_his_parent_org.code,
target := org.code,
)
}
解读:
cal::idescendant(...) 取指定组织及其所有后代,得到节点集合 org。
nodes:对每个 org 取 code 作为 _id、name 作为 label。
edges:每个 org 的父级链接 eff_his_parent_org 的 code 作为 source,自身 code 作为 target——即「父→子」方向的边。根节点没有父级,自动不产生边。
结果示意:
[
{
"nodes": [
{ "_id": "60020354", "label": "HRBP部门" },
{ "_id": "60020905", "label": "办公室员工招聘" },
{ "_id": "60020238", "label": "人才招聘部门" },
{ "_id": "60020236", "label": "人才发展部门" }
],
"edges": [
{ "source": "60020113", "target": "60020354" },
{ "source": "60020354", "target": "60020905" },
{ "source": "60020113", "target": "60020238" },
{ "source": "60020113", "target": "60020236" }
]
}
]
把订单头和订单行的从属关系可视化为图:
with
orders := (select Order filter .status = 'confirmed'),
lines := orders.<order[is OrderLine],
select {
nodes := (
-- 订单头节点
(select orders {
_id := <str>.id,
label := .order_no,
})
union
-- 订单行节点
(select lines {
_id := <str>.id,
label := .product_name,
})
),
edges := (
select lines {
source := <str>.order.id,
target := <str>.id,
}
)
}
当节点来自多种对象类型时,用 union 合并节点集合。每种类型分别定义 _id 和 label 即可。
|
技巧 |
说明 |
|---|---|
|
|
优先用业务主键(code),无主键时用 |
|
边的方向 |
根据业务语义决定:「父→子」或「子→父」、「上游→下游」等 |
|
多类型节点 |
用 |
|
层级遍历 |
配合 |
|
过滤范围 |
先 filter 限定起始节点,再递归展开,避免全量查询 |
|
附加字段 |
nodes 和 edges 中可以加自定义字段(如 |
用业务主键值或 UUID 直接「转换」为对象实例:<对象类型>'主键值'。语法简洁,适合已知主键时快速取对象。
-- 用业务主键直接取对象,继续取属性
select (<Order>'ORD001').order_date
-- 用 UUID 取对象
select (<Order><uuid>'550e8400-e29b-41d4-a716-446655440000') {
order_no,
order_date,
status
}
也可以在 with 中赋值后复用:
with target := (<Customer>'C001')
select Order {
order_no,
order_date
}
filter .customer = target
同样是「按主键取一条对象」,有两种写法:
-- 写法 A:Cast 转换(简洁)
select (<Order>'ORD001') { order_no, order_date, status }
-- 写法 B:select + filter(安全)
select Order { order_no, order_date, status }
filter .order_no = 'ORD001'
|
Cast |
select … filter | |
|---|---|---|
|
语法 |
简洁,一行搞定 |
标准 select 语法 |
|
主键不存在时 |
抛出异常(报错) |
返回空集(不报错) |
|
返回基数 |
确定为单条(One) |
可能为零条或多条(Set) |
|
适用场景 |
确定数据存在时(如关联引用、已知 ID) |
不确定是否存在、需要容错时 |
选择建议:在计算字段、关联引用等确定主键存在的场景用 Cast,更简洁;在用户输入、外部参数等不确定是否存在的场景用 select + filter,更安全。
DeepModel 中的枚举属性底层用 str 类型 + one_of 约束实现——也就是说,属性存储的只是枚举的编码(如 'submitted'、'rejected'),而枚举的中文描述(如「评估中」、「未采纳」)保存在元数据中,查询时需要额外获取。
dm::get_enum_info(模块编码, 对象编码, 属性编码)
返回一个 JSON 对象,key 为枚举编码,value 为该枚举值的多语言描述。可以用枚举编码做下标取出对应的描述。
假设 Requirement 对象有枚举属性 req_status(值为 editing / submitted / rejected 等),要查询每条记录的状态描述:
with enum_mapping := dm::get_enum_info('appzauoyn184', 'Requirement', 'req_status')
select Requirement {
req_name,
req_status,
req_status_desc := <str>enum_mapping[.req_status]['zh-cn']
}
结果示意:
|
req_name |
req_status |
req_status_desc |
|---|---|---|
|
req2 |
submitted |
评估中 |
|
req5 |
rejected |
未采纳 |
|
req6 |
editing |
需求提案 |
|
req7 |
submitted |
评估中 |
解读:
dm::get_enum_info(...) 返回的 JSON 结构类似:{"editing": {"zh-cn": "需求提案", "en": "Proposal"}, "submitted": {"zh-cn": "评估中", ...}, ...}
enum_mapping[.req_status] 用当前记录的状态编码做下标,取出该枚举值的描述对象
['zh-cn'] 再取中文描述
最外层 <str> 将 JSON 值转为字符串
注意:dm::get_enum_info 的第一个参数是模块编码(DeepModel 的应用模块标识),不是对象名。
DeepModel 中的文件属性底层用 multi json 实现——本质是 JSON 类型,但可以为多值(一个字段存多个文件)。每个文件是一个 JSON 对象,包含 fileName、fileSize、fileUrl 等字段。
select Order {
order_no,
-- attachment 是 multi json,每个元素是一个文件的 JSON 对象
attachment_names := .attachment['fileName']
}
如果一个订单附了 2 个文件,.attachment 就是 2 个 JSON 对象的集合,.attachment['fileName'] 得到 2 个文件名。
select Order {
order_no,
-- 收集为数组
file_list := array_agg(<str>.attachment['fileName']),
-- 拼接为一个字符串
file_names := to_str(array_agg(<str>.attachment['fileName']), '、')
}
结果示意:
[
{
"order_no": "ORD001",
"file_list": ["合同.pdf", "报价单.xlsx"],
"file_names": "合同.pdf、报价单.xlsx"
}
]
|
要点 |
说明 |
|---|---|
|
底层类型 |
|
|
单文件 vs 多文件 |
都是 multi,单文件时集合只有 1 个元素 |
|
常用字段 |
|
|
取值方式 |
|
|
转字符串 |
需 |
.__bk__在实际开发中,经常需要取对象或关联对象的业务主键来做过滤、比较、输出。但不同对象的主键字段名各不相同——有的叫 code,有的叫 order_no,有的叫 xx_id,每次都要翻找对象结构确认字段名,非常繁琐。
为了解决这个高频痛点,DeepQL 扩展了一个特殊语法:.__bk__(business key),代表对象的业务主键。执行时会自动替换为该对象实际的主键字段名。
-- .__bk__ 会自动替换为 Order 的业务主键字段(如 order_no)
select Order {
__bk__,
order_date,
status
}
等价于:
select Order {
order_no,
order_date,
status
}
不需要记住主键叫什么,直接用 .__bk__ 过滤:
select Order { * }
filter .__bk__ = 'ORD001'
取关联对象的主键也一样——通过链接「点」到 .__bk__:
select OrderLine {
product_name,
qty,
price,
order_pk := .order.__bk__,
customer_pk := .order.customer.__bk__
}
执行时 .order.__bk__ 替换为 .order.order_no,.order.customer.__bk__ 替换为 .order.customer.code——你不需要知道 Order 的主键是 order_no 还是 Customer 的主键是 code。
|
场景 |
写法 |
|---|---|
|
输出当前对象主键 |
|
|
按主键过滤 |
|
|
取链接对象的主键 |
|
|
多级链接取主键 |
|
|
分组时取主键做维度 |
|
__bk__ 是纯语法糖——执行前由引擎替换为实际字段名,不影响性能。好处是:换了主键字段名也不用改查询语句,降低维护成本。
assert(条件, message?):条件为 false 时报错,可带自定义 message。
win::mode(集合):取集合中出现次数最多的值(众数),多个时随机取一。
ROLLUP / CUBE:在 group 的 by 中做多维度汇总,见「六、分组与汇总」中的详细说明。
需要完整语法或更多函数时,可查阅 DeepModel 参考文档。
回到顶部
咨询热线
