除了对象的属性,还可以通过链接在结果中带出关联对象的数据:正向是「当前对象指向谁」,反向是「谁指向当前对象」。订单行通过链接 order 指向订单头;订单头还可通过链接 customer、warehouse 指向客户、仓库等主数据。
用 .链接编码 到达关联对象,在 select 的大括号里用嵌套形状写出要带出的属性。
订单行 → 订单头:订单行有链接 order 指向订单头,在查订单行时可带出头的字段,例如 order: { order_no, order_date, status }。
订单头 → 主数据:订单头有链接 customer、warehouse 指向客户、仓库,可带出客户名(多语言字段,取中文名用 <str>.customer.name['zh-cn'])、仓库名等。
语法示例(查订单行,并带出所属订单头的订单号、日期):
select OrderLine {
line_no,
product_name,
qty,
price,
order: { order_no, order_date, status }
}
多级时继续用 . 或嵌套;例如订单行的订单号也可写成 .order.order_no(见下文「多级与计算字段」)。
每条正向链接都有一条虚拟的反向链接:从「被指向的对象」看「谁指向我」。
写法:.<链接名[is 对象类型],其中 < 表示反向,[is 对象类型] 指定链接另一端的对象类型。
例如:订单行有正向链接 order 指向订单头,则在订单头上就有反向链接 .<order[is OrderLine],表示「指向当前订单头的所有订单行」。
典型用法是在头表上统计行表数量:count(.<order[is OrderLine]) 表示该订单下的订单行数量。
正向:.order.order_no、.order.order_date 以及主数据 .customer.name(多语言 JSON)、.warehouse.name 可直接作为输出字段的表达式。客户名为多语言字段,取中文用 <str>.customer.name['zh-cn']。
在 select 里用 := 可给输出起别名,例如在订单头上把「客户中文名」「仓库名」「订单行数量」「订单行金额之和」作为单独字段:
select Order {
order_no,
order_date,
status,
customer_name := <str>.customer.name['zh-cn'],
warehouse_name := .warehouse.name,
line_count := count(.<order[is OrderLine]),
total_amount := sum(.<order[is OrderLine].qty * .<order[is OrderLine].price)
}
查询最近 10 条已确认订单,并带出:订单号、日期、状态、客户名、仓库名、订单行数量、订单行金额合计。
select Order {
order_no,
order_date,
status,
customer_name := <str>.customer.name['zh-cn'],
warehouse_name := .warehouse.name,
line_count := count(.<order[is OrderLine]),
total_amount := sum(.<order[is OrderLine].qty * .<order[is OrderLine].price)
}
filter .status = 'confirmed'
order by .order_date desc
limit 10
结果示意:
[
{
"order_no": "ORD003",
"order_date": "2023-10-03",
"status": "confirmed",
"customer_name": "客户甲",
"warehouse_name": "华北仓",
"line_count": 2,
"total_amount": 350.00
},
{
"order_no": "ORD002",
"order_date": "2023-10-02",
"status": "confirmed",
"customer_name": "客户乙",
"warehouse_name": "华东仓",
"line_count": 1,
"total_amount": 99.00
}
]
查链接数据时,有两种输出方式:拉平到第一层和嵌套结构。
用 := 把链接对象的属性逐个「拉」到当前对象的第一层:
select OrderLine {
line_no,
product_name,
qty,
price,
order_no := .order.order_no,
order_date := .order.order_date,
customer_name := <str>.order.customer.name['zh-cn']
}
结果是扁平的,每行所有字段都在同一层:
[
{ "line_no": 1, "product_name": "商品A", "qty": 2, "price": 50.00, "order_no": "ORD001", "order_date": "2023-10-01", "customer_name": "客户甲" },
{ "line_no": 2, "product_name": "商品B", "qty": 1, "price": 99.00, "order_no": "ORD001", "order_date": "2023-10-01", "customer_name": "客户甲" }
]
用 链接: { 属性 } 保持对象的嵌套关系:
select OrderLine {
line_no,
product_name,
qty,
price,
order: {
order_no,
order_date,
customer: { name }
}
}
结果保留层级关系,链接对象作为子对象嵌在里面:
[
{
"line_no": 1, "product_name": "商品A", "qty": 2, "price": 50.00,
"order": {
"order_no": "ORD001", "order_date": "2023-10-01",
"customer": { "name": { "zh-cn": "客户甲", "en": "Customer A" } }
}
}
]
反向链接同理——从头查行时,嵌套结构天然表达「一对多」:
select Order {
order_no,
lines := .<order[is OrderLine] {
line_no,
product_name,
qty,
price
}
}
结果:一个订单头对象内嵌一个订单行数组,无需像 SQL 那样做 join 然后头信息重复 N 行:
[
{
"order_no": "ORD001",
"lines": [
{ "line_no": 1, "product_name": "商品A", "qty": 2, "price": 50.00 },
{ "line_no": 2, "product_name": "商品B", "qty": 1, "price": 99.00 }
]
}
]
|
拉平( |
嵌套( | |
|---|---|---|
|
输出结构 |
扁平,所有字段在同一层 |
层级,链接对象作为子对象 |
|
类似 |
传统 SQL join 后的表格 |
JSON / 文档型结构 |
|
适用 |
需要平铺表格、或只需取链接对象的个别字段 |
需要完整的关联对象结构、一对多场景 |
|
一对多时 |
每条关联对象独占一行,头信息重复 |
头只出现一次,子对象为数组 |
与传统 SQL 的区别:传统 SQL 只能输出二维表格(join 后头信息重复 N 行),而 DeepQL 天然支持嵌套结构,这是对象层查询语言的核心优势——结果直接就是结构化的数据,无需客户端再做拼装。
通过 Python SDK 等客户端拿到 DeepQL 的嵌套结果后,通常会得到一个含嵌套列的 DataFrame。如果需要将嵌套列展开为扁平行(类似 SQL join 的表格效果),可以使用 Pandas 的 行展开: df.explode()和列展开: df.json_normalize() 方法:
import pandas as pd
# 假设 result 是 DeepQL 查询返回的嵌套结果(list of dict)
df = pd.DataFrame(result)
# lines 列是嵌套的数组,explode 展开为多行
df_flat = df.explode('lines')
# 再将 lines 中的字段拉平到列
lines_df = pd.json_normalize(df_flat['lines'])
df_flat = df_flat.drop(columns=['lines']).reset_index(drop=True)
df_flat = pd.concat([df_flat, lines_df], axis=1)
展开前:
|
order_no |
lines |
|---|---|
|
ORD001 |
[{“line_no”: 1, “product_name”: “商品A”, …}, {“line_no”: 2, …}] |
展开后:
|
order_no |
line_no |
product_name |
qty |
price |
|---|---|---|---|---|
|
ORD001 |
1 |
商品A |
2 |
50.00 |
|
ORD001 |
2 |
商品B |
1 |
99.00 |
在展开链接时,可以直接对链接的嵌套形状加 filter、order by、limit,只筛选/排序/截取需要的关联对象。
示例:查订单头,并只带出单价 > 50 的订单行(按单价降序,最多 5 行):
select Order {
order_no,
lines := .<order[is OrderLine] {
line_no,
product_name,
price
} filter .price > 50
order by .price desc
limit 5
}
注意:嵌套 filter 里的 .price 表示订单行的 price(作用域变为嵌套的对象类型),而非外层 Order 的属性。
当一条链接指向抽象类型或联合类型时,链接的结果可能是多种子类型的混合。可用 [is 子类型] 进行类型交叉,只保留特定子类型的对象。
语法:链接[is 子类型] 或 [is 子类型].属性。
此语法也可用于反向链接中,前文已见:.<order[is OrderLine] 就是一种类型交叉,指定反向链接另一端的对象类型。
|
概念 |
写法 |
说明 |
|---|---|---|
|
正向链接 |
|
从当前对象到关联对象,带出对方属性(行→头) |
|
反向链接 |
|
谁指向当前对象,常用于头表统计行数/金额 |
|
多级 |
|
沿链接链逐级访问 |
|
计算字段 |
|
在结果中输出聚合或表达式结果 |
|
嵌套 filter/order/limit |
|
对展开的链接做筛选、排序、截取 |
|
类型交叉 |
|
只保留特定子类型的链接对象 |
下一步可以让查询支持传入参数、用 with 复用中间结果,见「四、可复用与可传参:变量与 with」。
回到顶部
咨询热线
