report-sql
> 本技能由老板亲授,定义 report-service 的 SQL 模板协议与变量规范。
by 23396599 · published 2026-04-01
$ claw add gh:23396599/23396599-report-sql# report-sql
> 本技能由老板亲授,定义 report-service 的 SQL 模板协议与变量规范。
Variables
report-service 变量遵循唯一、精确、零容错原则:
✅ 合法语法
#@option.where.<field>#🔑 当前支持字段
| 字段名 | 类型 | 示例值 | 典型 SQL 用法 |
|--------|------|--------|----------------|
| `name` | string | `"张三"` | `WHERE s.name = #@option.where.name#` |
| `status_list` | array | `["draft","published"]` | `WHERE b.status IN (#@option.where.status_list#)` |
| `start_date` | date | `"2026-03-01"` | `AND u.created_at >= #@option.where.start_date#` |
| `limit` | number | `100` | `LIMIT #@option.where.limit#` |
⚠️ 严禁写法(运行时直接失败)
📌 拼接原则
变量只提供值,表别名由 `FROM` 子句决定:
✅ 新增:`${...}` 块级变量语法(2026-03-23 补充)
用于包裹条件片段,典型形式:
${
AND `corpId` = '#@option.where.corpId#' }${
AND `creatorId` = '#@option.where.creatorId#' }#### 规则说明
✅ 新增:模糊匹配常用块(2026-03-23 补充)
用于 `LIKE` 模糊查询,典型形式:
${
AND `name` LIKE '%#@option.where.name#%' }#### 使用说明
✅ 新增:时间范围查询常用块(2026-03-23 补充)
用于 `createdAt` 等时间字段的开闭区间查询,典型形式:
${
AND `createdAt` >= '#@option.where.createdAt[0]#'
AND `createdAt` < '#@option.where.createdAt[1]#' }#### 使用说明
✅ 新增:多值循环块语法(2026-03-23 补充)
用于生成 `IN` 或多条件 `OR` 逻辑,典型形式:
$@option.where.state ->
OR {
AND [state = '#@item#'] }#### 使用说明
#### 🔁 进阶说明:括号语义与等价性
`$@... -> OR { ... }` 生成的 SQL **自动为每个 `{ ... }` 块添加括号**,例如:
$@option.where.types ->
OR {
AND state = 'finished' AND [type = '#@item#'] }解析为:
( state = 'finished' AND type = 'sale' )
OR ( state = 'finished' AND type = 'refund' )此形式在逻辑上 **完全等价于**:
state = 'finished' AND type IN ('sale', 'refund')**或**:
AND state = 'finished' AND ( (type = 'sale') OR (type = 'refund') )✅ 优势:括号强制分组,杜绝 `AND`/`OR` 优先级陷阱;
✅ 优势:可轻松扩展为多字段组合(如 `AND [type = '#@item#'] AND [status = '#@item2#']`);
⚠️ 注意:若需外层统一 `AND`(如所有 `OR` 结果再 `AND` 一个固定条件),请将该固定条件写在 `OR { ... }` 块**之外**(如 `WHERE active = 1 AND (...)`),而非塞进块内。
#### 🌐 高阶用法:对象数组遍历(2026-03-23 补充)
`$@... -> OR { ... }` 支持遍历**对象数组**,并用点语法 `#@item.xxx#` 访问嵌套字段。
**典型形式**:
$@searchOrder -> OR { AND [id = '#@item.corpId#'] }**解析逻辑**:
( id = 'wx123' ) OR ( id = 'wx456' )✅ 优势:直接复用上一步查询结果,实现“查完即用”的流水线;
⚠️ 注意:`#@item.xxx#` 中的 `xxx` 必须是对象存在的字段名,否则该元素被跳过(空安全)。
✅ 新增:复杂 EXISTS 子查询块(2026-03-23 补充)
用于封装高复用业务逻辑(如分发状态判定),典型形式:
${
AND NOT (
EXISTS(
SELECT #@option.where.distributeYes# FROM wq.`joblist` j WHERE j.`JobId` = b.id AND j.active = 1 AND (j.`outUserID` = '' OR j.outUserID IS NULL)) OR (NOT EXISTS(SELECT 1 FROM wq.`joblist` j WHERE j.`JobId` = b.id AND j.active = 1 AND (j.`outUserID` = '' OR j.outUserID IS NULL)) and (b.outUserID is null or b.outUserID = '')))}${ AND (EXISTS(SELECT #@option.where.distributeNo# FROM wq.`joblist` j WHERE j.`JobId` = b.id AND j.active = 1 AND (j.`outUserID` = '' OR j.outUserID IS NULL)) OR (NOT EXISTS(SELECT 1 FROM wq.`joblist` j WHERE j.`JobId` = b.id AND j.active = 1 AND (j.`outUserID` = '' OR j.outUserID IS NULL)) and (b.outUserID is null or b.outUserID = '')))}#### 使用说明
✅ 新增:变量使用场景 — 块级边界原则(2026-03-23 补充)
`${...}` 块不是“值占位符”,而是**自洽 SQL 片段容器**。其边界必须包裹完整语法单元。
#### ❌ 危险写法(绝对禁止)
-- 错!and 在块外 → 空时生成语法错误:`WHERE active = 1 and `
select id, parent, name from department where active = 1 and ${ corpId = '#@option.where.corpId#' }#### ✅ 正确写法(必须)
-- 对!and 在块内 → 空时整块剔除,SQL 依然合法
select id, parent, name from department where active = 1 ${ and corpId = '#@option.where.corpId#' }#### 📌 核心原则
> 这是 `report-service` 空安全的最后防线 —— 宁可多写一个 `and`,不可少包一行 SQL。
Transform
`report-service` 支持链式数据变换操作,用于处理 SQL 查询结果,支持初始化、条件赋值、字段映射、关联补全与结果组装。
变换语法说明
所有变换以 JSON 数组形式声明,每个对象为一个操作步骤,按顺序执行。
| 字段 | 类型 | 说明 |
|------|------|------|
| `method` | string | 操作类型(`setData` / `copyObject` / `leftJoin`) |
| `target` | string | 目标变量名(如 `@result`, `@rows`),以 `@` 开头 |
| `source` | any | 源数据(可为字面值、数组、对象、或另一变量如 `@deptList`) |
| `precondition` | string | 执行前置条件(如 `#@deptList#`,当该变量有值时才执行此步) |
| `attributes` / `fields` | array | 字段映射规则(`from` → `to`,可设 `default`) |
| `targetKey` / `sourceKey` | string | 关联键名(用于 `leftJoin`) |
---
示例 1:结果初始化与条件赋值
[
{
"method": "setData",
"target": "@result",
"source": []
},
{
"method": "setData",
"target": "@result",
"source": "@deptList",
"precondition": "#@deptList#"
}
]> 💡 **权威说明(老板亲授)**:
> `precondition: "#@deptList#"` 的语义是——**判断上一步产生的中间变量 `@deptList` 是否存在且非空**(非 `null` / `undefined` / `[]` / `{}`);
> 仅当该条件为真时,第二步 `setData` 才执行;
> 第一步 `source: []` 确保 `@result` 始终有默认值,避免未定义状态。
---
示例 2:对象字段提取与结构重组
[
{
"method": "setData",
"target": "@result",
"source": {}
},
{
"method": "copyObject",
"target": "@result",
"source": "@countOrder[0]",
"attributes": [
{
"from": "totalCount",
"to": "count",
"default": 0
},
{
"from": "totalMoney",
"to": "money",
"default": 0
}
]
}
]---
示例 3:多源关联与标准响应组装
[
{
"method": "setData",
"target": "@rows",
"source": []
},
{
"method": "setData",
"target": "@rows",
"source": "@searchOrder",
"precondition": "#@searchOrder#"
},
{
"method": "leftJoin",
"target": "@rows",
"source": "@searchCorp",
"targetKey": "corpId",
"sourceKey": "id",
"fields": [
{
"from": "name",
"to": "corpName",
"default": ""
},
{
"from": "nickname",
"to": "corpNickname",
"default": ""
}
]
},
{
"method": "copyObject",
"target": "@result",
"source": "@rows",
"to": "rows",
"default": []
}
]1. 初始化 `@rows` 为空数组;
2. 若 `@searchOrder` 存在,则赋值;
3. 用 `@searchCorp` 左关联 `@rows`(`corpId` ↔ `id`),补全 `corpName`/`corpNickname`;
4. 将最终 `@rows` 数组整体写入 `@result.rows`(非覆盖 `@result`)。
More tools from the same signal band
Order food/drinks (点餐) on an Android device paired as an OpenClaw node. Uses in-app menu and cart; add goods, view cart, submit order (demo, no real payment).
Sign plugins, rotate agent credentials without losing identity, and publicly attest to plugin behavior with verifiable claims and authenticated transfers.
The philosophical layer for AI agents. Maps behavior to Spinoza's 48 affects, calculates persistence scores, and generates geometric self-reports. Give your...