@finebi/finebi-cli 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -39
- package/package.json +38 -35
- package/skills/finebi-cli-agent/SKILL.md +133 -0
- package/skills/finebi-cli-agent/agents/openai.yaml +7 -0
- package/skills/finebi-cli-agent/references/analysis-dsl-api.md +318 -0
- package/skills/finebi-cli-agent/references/artifact-ordering.md +29 -0
- package/skills/finebi-cli-agent/references/command-workflows.md +194 -0
- package/skills/finebi-cli-agent/references/dashboard-dsl-api.md +1025 -0
- package/skills/finebi-cli-agent/references/dsl-handoff-contract.md +195 -0
- package/skills/finebi-cli-agent/references/file-to-dashboard.md +65 -0
- package/skills/finebi-cli-agent/references/formula-basics.md +102 -0
- package/skills/finebi-cli-agent/references/formula-contexts.md +66 -0
- package/skills/finebi-cli-agent/references/formula-functions.md +247 -0
- package/skills/finebi-cli-agent/references/formula-generation.md +121 -0
- package/skills/finebi-cli-agent/references/formula-glossary.md +17 -0
- package/skills/finebi-cli-agent/references/formula-help-boundaries.md +87 -0
- package/skills/finebi-cli-agent/references/formula-help-index.md +264 -0
- package/skills/finebi-cli-agent/references/formula-parameters-aggregate.md +143 -0
- package/skills/finebi-cli-agent/references/formula-parameters-analysis.md +223 -0
- package/skills/finebi-cli-agent/references/formula-parameters-date.md +236 -0
- package/skills/finebi-cli-agent/references/formula-parameters-math-logic.md +271 -0
- package/skills/finebi-cli-agent/references/formula-parameters-text.md +217 -0
- package/skills/finebi-cli-agent/references/formula-recipes-analysis.md +124 -0
- package/skills/finebi-cli-agent/references/formula-recipes-text-date.md +86 -0
- package/skills/finebi-cli-agent/references/formula-semantics.md +39 -0
- package/skills/finebi-cli-agent/references/formula-syntax.md +70 -0
- package/skills/finebi-cli-agent/references/formula-troubleshooting.md +63 -0
- package/skills/finebi-cli-agent/references/formula-validation.md +36 -0
- package/skills/finebi-cli-agent/references/formula.md +37 -0
- package/skills/finebi-cli-agent/references/handoff-contract.md +210 -0
- package/skills/finebi-cli-agent/references/mapping-rules.md +423 -0
- package/skills/finebi-cli-agent/references/mutation-confirmation-contract.md +150 -0
- package/skills/finebi-cli-agent/references/scenario-workflows.md +75 -0
- package/skills/finebi-cli-agent/references/widget-dsl-api-examples.md +457 -0
- package/skills/finebi-cli-agent/references/widget-dsl-api.md +1340 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/package.json +11 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/access-key-contract.js +2 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/access-key.js +174 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/auth-failure.js +18 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/auth-headers.js +21 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/auth.js +116 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/branding.js +31 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/browser-auth.js +331 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/capability.js +122 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/config-permissions.js +87 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/config.js +189 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/dynamic-command.js +324 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/error-catalog.js +482 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/errors.js +22 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/help.js +467 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/index.js +1343 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/install-skill.js +87 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/output-limits.js +188 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/output.js +33 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/profiles.js +158 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/schema-options.js +265 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/schema-validator.js +194 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli/src/skill-files.js +94 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli-runner-core.mjs +399 -0
- package/skills/finebi-cli-agent/scripts/finebi-cli-runner.mjs +29 -0
- package/src/error-catalog.js +12 -0
- package/src/help.js +15 -0
- package/src/index.js +6 -1
- package/src/install-skill.js +87 -0
- package/src/skill-files.js +94 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# 文本、日期与条件处理模板
|
|
2
|
+
|
|
3
|
+
按任务读取相关小节;签名和引擎限制分别查 [函数库](formula-functions.md)、[使用边界](formula-help-boundaries.md)。以下表达式将官方界面字段标签规范化为 `${字段名}`,有边界保护的写法是基于原文语义的改写,未在目标实例执行。字段必须替换为真实目录项。
|
|
4
|
+
|
|
5
|
+
## 1. 文本清洗与拆分
|
|
6
|
+
|
|
7
|
+
来源:[文本合并、截取、分列](https://help.fanruan.com/finebi/doc-view-1331.html)、[截取字符](https://help.fanruan.com/finebi/doc-view-878.html)、[多次分隔符](https://help.fanruan.com/finebi/doc-view-1092.html)、[字符次数](https://help.fanruan.com/finebi/doc-view-1078.html)、[特殊字符](https://help.fanruan.com/finebi/doc-view-1481.html)、[字段拼接](https://help.fanruan.com/finebi/doc-view-1143.html)。
|
|
8
|
+
|
|
9
|
+
| 需求 | 模板与前提 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| 拼接地域路径 | `CONCATENATE(${国家}, "-", ${省份}, "-", ${城市})`;字段空值的展示规则先明确 |
|
|
12
|
+
| 清首尾空格、统一大小写 | `UPPER(TRIM(${编码}))` 或 `LOWER(TRIM(${编码}))`;不要无条件修改大小写敏感的业务 ID |
|
|
13
|
+
| 单词首字母大写 | 抽取 `PROPER(${标题})` |
|
|
14
|
+
| 取尾部 8 个字符 | `RIGHT(${电话}, 8)`;电话保持文本,保留前导零 |
|
|
15
|
+
| 是否包含“省” | `FIND("省", ${地址}, 1)>0`;需输出 0/1 时 `IF(FIND("省", ${地址}, 1)>0,1,0)` |
|
|
16
|
+
| 首个冒号前的内容 | `IF(FIND(":",${内容},1)>0,LEFT(${内容},FIND(":",${内容},1)-1),${内容})`;未找到时保留原文 |
|
|
17
|
+
| 首个冒号后的内容 | `IF(FIND(":",${内容},1)>0,RIGHT(${内容},LEN(${内容})-FIND(":",${内容},1)),NULL)`;未找到时空值 |
|
|
18
|
+
| 两分隔符之间 | 先求起点和终点,确认两者存在且终点大于起点,再 `MID(${内容},${起点}+1,${终点}-${起点}-1)`;多字符分隔符按实际长度修正 |
|
|
19
|
+
| 最后一个下划线后的内容 | 抽取 `INDEXOF(SPLIT(${内容},"_"),LEN(SPLIT(${内容},"_"))-1)`;空值、末尾分隔符须核验拆分结果 |
|
|
20
|
+
| 倒数第二段 | 抽取同上把索引改为 `LEN(SPLIT(...))-2`,先确认至少两段 |
|
|
21
|
+
| 统计单字符 `/` 出现次数 | 抽取 `LEN(${内容})-LEN(SUBSTITUTE(${内容},"/",""))`;直连使用支持的 REPLACE 版本 |
|
|
22
|
+
| 指定第 n 次替换 | 抽取 `SUBSTITUTE(${内容},"_","-",2)` 替换第二处;三参 REPLACE 用于按内容替换,四参 REPLACE 用于按位置替换 |
|
|
23
|
+
| 电话脱敏 | `REPLACE(${电话},4,4,"****")`,确认号码长度及规则 |
|
|
24
|
+
| 删除前/后 n 个字符 | `RIGHT(${内容},LEN(${内容})-n)` / `LEFT(${内容},LEN(${内容})-n)`,先确保长度 ≥ n;n 是数值占位,不是字段 |
|
|
25
|
+
|
|
26
|
+
同列相似字符不一定同码点:英文 `:` 与中文 `:` 要按输入实际字符匹配。统计多字符片段次数时,长度差还要除以片段长度,并明确非重叠计数规则。
|
|
27
|
+
|
|
28
|
+
## 2. 金额、正则和特殊字符
|
|
29
|
+
|
|
30
|
+
来源:[金额字段清洗](https://help.fanruan.com/finebi/doc-view-1867.html)、[去除指定字符](https://help.fanruan.com/finebi/doc-view-820.html)、[正则示例](https://help.fanruan.com/finebi/doc-view-1155.html)。
|
|
31
|
+
|
|
32
|
+
会计文本如 `¥1,234.50`、`(¥123.45)`:先识别括号负号,再去币符、逗号和括号,最后转数值。以下拆为两列便于核对:
|
|
33
|
+
|
|
34
|
+
```text
|
|
35
|
+
金额文本 = IF(LEFT(TRIM(${原金额}),1)="(",
|
|
36
|
+
CONCATENATE("-",REPLACE(REPLACE(REPLACE(REPLACE(TRIM(${原金额}),"¥",""),",",""),"(",""),")","")),
|
|
37
|
+
REPLACE(REPLACE(TRIM(${原金额}),"¥",""),",",""))
|
|
38
|
+
金额 = IF(ISNULL(${金额文本}),NULL,TODOUBLE(${金额文本}))
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
先用正数、括号负数、空值、非法金额四类样本核对。TODOUBLE 是转换函数,不能把原文示例显示两位小数当成精度保证;需要舍入时显式 ROUND。
|
|
42
|
+
|
|
43
|
+
纯数字且非空:`REGEXP(${编码},"^[0-9]+$")`。原文 `*` 允许零次匹配,是否接受空串取决于业务。REGEXP 用于匹配,不是提取子串或正则替换。
|
|
44
|
+
|
|
45
|
+
删除一对 `【】` 包围的片段:先确认 `FIND("【",...)>0` 且 `FIND("】",...)` 在其后,再用四参 REPLACE 删除从左括号起到右括号止的长度;未找到/顺序异常时保留原值或返回异常标签。删除英文双引号使用公式文本 `REPLACE(${内容},"\"","")`;单引号是普通字符 `REPLACE(${内容},"'","")`。嵌入 JS/JSON 时另做宿主转义。
|
|
46
|
+
|
|
47
|
+
## 3. 日期转换、边界和差值
|
|
48
|
+
|
|
49
|
+
来源:[常用日期公式](https://help.fanruan.com/finebi/doc-view-1326.html)、[日期与字符串互转](https://help.fanruan.com/finebi/doc-view-1346.html)、[IF 处理数据](https://help.fanruan.com/finebi/doc-view-1315.html)。
|
|
50
|
+
|
|
51
|
+
| 需求 | 模板 |
|
|
52
|
+
|---|---|
|
|
53
|
+
| `20260522` 文本转日期 | `TODATE(${日期文本},"yyyyMMdd")` |
|
|
54
|
+
| `20260522165050` 文本转时间 | `TODATE(${时间文本},"yyyyMMddHHmmss")` |
|
|
55
|
+
| 毫秒时间戳 | `TODATE(${毫秒时间戳})` |
|
|
56
|
+
| 秒时间戳 | `TODATE(${秒时间戳}*1000)` |
|
|
57
|
+
| 本月第一天 | `DATE(YEAR(TODAY()),MONTH(TODAY()),1)` |
|
|
58
|
+
| 本月最后一天 | `DATE(YEAR(TODAY()),MONTH(TODAY()),DAYSOFMONTH(TODAY()))` |
|
|
59
|
+
| 去年同日 / 上月同日 | `YEARDELTA(${日期},-1)` / `MONTHDELTA(${日期},-1)`;闰日和月末用目标环境样本确认 |
|
|
60
|
+
| 去除时分秒,仍返回日期 | `TODATE(FORMAT(${时间},"yyyy-MM-dd"))` |
|
|
61
|
+
| 只展示年月 | `FORMAT(${日期},"yyyy-MM")`;结果为文本,需要日期分组时保留日期型 |
|
|
62
|
+
| 当前分组最新日期 | `TODATE(MAX_AGG(DATETONUMBER(${日期})))`;需要展示时再 FORMAT |
|
|
63
|
+
| 非空日期后移十天 | `IF(ISNULL(${日期}),NULL,DATEDELTA(${日期},10))` |
|
|
64
|
+
| 两个日期相差天数 | `IF(OR(ISNULL(${开始}),ISNULL(${结束})),NULL,DATEDIF(${开始},${结束},"D"))` |
|
|
65
|
+
| 两个时刻相差小时 | `IF(OR(ISNULL(${开始}),ISNULL(${结束})),NULL,DATESUBDATE(${结束},${开始},"H"))` |
|
|
66
|
+
| 半开时间区间 | `${日期}>=DATE(2026,1,1) && ${日期}<DATE(2026,2,1)`;保留时分秒时更容易正确覆盖整月 |
|
|
67
|
+
|
|
68
|
+
日历序号、年月字符串、Unix 秒和 Unix 毫秒是不同输入类型,先辨别再转换。YEAR/MONTH/DAY 的空参取服务器时间;相对“今天”的公式应说明刷新时间和时区。以“满 18 周岁”为条件时不能只用 `DATEDIF(...,"Y")>=18`,还要比较月日。
|
|
69
|
+
|
|
70
|
+
## 4. 分类、去重与异常值
|
|
71
|
+
|
|
72
|
+
来源:[IF 嵌套](https://help.fanruan.com/finebi/doc-view-2510.html)、[空值与无穷](https://help.fanruan.com/finebi/doc-view-1111.html)、[不同列重复数据](https://help.fanruan.com/finebi/doc-view-1482.html)、[包含字符串](https://help.fanruan.com/finebi/doc-view-896.html)。
|
|
73
|
+
|
|
74
|
+
| 需求 | 选择 |
|
|
75
|
+
|---|---|
|
|
76
|
+
| 连续区间分级 | `IF(${成绩}<60,"不及格",${成绩}<70,"及格",${成绩}<80,"良好","优秀")`;先匹配先返回,空成绩先单独处理 |
|
|
77
|
+
| 枚举转标签 | `SWITCH(${班级},"Class1","一班","Class2","二班","其他")`;日期枚举值要先构造成日期类型 |
|
|
78
|
+
| 多个条件全满足 / 任一满足 | `IF(AND(条件1,条件2),"是","否")` / `IF(OR(条件1,条件2),"是","否")`,条件须替换为布尔或数值表达式 |
|
|
79
|
+
| 集合分类 | `IF(IN(${状态},"跟进","合作"),"服务","不服务")`;反向用 NOT(IN(...)) |
|
|
80
|
+
| 检查两列是否完全相同 | `EXACT(${文本1},${文本2})`,区分大小写;跨行重复计数应使用 COUNTD/DEF,不能把逐行相等当作去重 |
|
|
81
|
+
| 负数截为 0 | `IF(${利润}>0,${利润},0)`;需保留空值则在外层先 ISNULL |
|
|
82
|
+
| 空值默认 0 | `NVL(${销售额},0)` |
|
|
83
|
+
| 除零与空分母 | `IF(OR(ISNULL(${成本}),${成本}=0),NULL,${销售额}/${成本})`;默认值用 NULL 还是 0 由业务决定 |
|
|
84
|
+
| 无穷/NaN 替换 | `IFERROR(${表达式结果},0)`;空值另用 NVL/ISNULL,不把 IFERROR 当语法错误兜底 |
|
|
85
|
+
|
|
86
|
+
数值指标的结果分支保持数值或 NULL;诊断文案放另一列。聚合后比率的判断也要用聚合分母,见 [分析模板](formula-recipes-analysis.md#1-条件统计与比率)。
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
## 三、公式的语义模型与计算分层
|
|
2
|
+
|
|
3
|
+
要正确解析或生成公式,需要理解一个公式从字符串到结果经过了哪些阶段,以及它最终以哪种"计算层级"参与查询——这决定了"哪些函数能组合、哪些不能"。
|
|
4
|
+
|
|
5
|
+
### 公式的处理阶段
|
|
6
|
+
|
|
7
|
+
1. **语法解析**:按公式文法把字符串拆成一棵公式节点树(函数节点、字段引用、字面量、运算符)。括号不匹配、运算符写错等语法层错误在此阶段报出;函数名是否在允许名单、参数个数/类型等留到下一阶段校验。
|
|
8
|
+
2. **合法性校验**:对节点树做类型检查与"聚合性质"检查,包括函数参数约束、聚合与非聚合混用限制、嵌套深度、引擎可用性等(详见"公式合法性约束清单")。
|
|
9
|
+
3. **语义建模**:把公式归类到四种"计算维度"之一——明细聚合、公式计算、定义计算(DEF 家族,LOD 同属)、窗口计算(WINDOW 家族)——生成查询语义树。这一步决定公式是普通指标、聚合指标、静态/动态指标还是窗口指标。
|
|
10
|
+
4. **生成查询并执行**:查询语义树转成"主表 + 卫星表"的查询结构(DEF/LOD/WINDOW 各自形成独立的卫星查询与主查询关联),再翻译成引擎的查询描述(HyperCriteria)交给引擎执行,产出结果列。
|
|
11
|
+
|
|
12
|
+
### 计算分层模型
|
|
13
|
+
|
|
14
|
+
一个公式最终落在下面四层之一或组合:
|
|
15
|
+
|
|
16
|
+
| 层级 | 包含内容 | 特点 |
|
|
17
|
+
|------|---------|------|
|
|
18
|
+
| **① 明细层** | 明细字段、普通函数、算术表达式;以及 `SUM_AGG` 等聚合函数 | 未聚合的表达式按明细行逐行计算;聚合函数按分析视图的维度分组聚合(每个维度组输出一行) |
|
|
19
|
+
| **② 分析函数独立聚合层** | `DEF` / `DEF_ADD` / `DEF_SUB`、LOD(`FIXED`/`INCLUDE`/`EXCLUDE`)、`WINDOW_` 系列、`RANK_AGG` | 各自定义一个独立的聚合范围,作为卫星查询与主查询关联 |
|
|
20
|
+
| **③ 表格计算层** | `TOTAL` / `ACC_SUM` / `RANK_ANLS` / `PREVIOUS_PERIOD` / `SAME_PERIOD` / `PERIOD_ANLS` / `PERIOD_TD` | 在聚合结果之上按行/组计算,不改变聚合粒度 |
|
|
21
|
+
| **④ 输出层** | 最终结果 | 度量值列或明细列 |
|
|
22
|
+
|
|
23
|
+
**"组"的含义**:表格计算的 `range`(0 所有行 / 1 组内)里的"组",由分析视图的行/列维度树决定(例如按"部门"分行,则每个部门是一个组),**不是公式参数**。AI 生成公式时如需"组内排名/组内累计",应确认目标组件行/列维度符合需求。
|
|
24
|
+
|
|
25
|
+
### 关键推论(解析与生成公式时直接使用)
|
|
26
|
+
|
|
27
|
+
- **聚合函数的参数必须是明细级表达式**:指标字段、维度、或指标字段与普通函数的运算结果;聚合函数内不能再套聚合函数(规则 7)。
|
|
28
|
+
- **表格计算的指标参数必须是聚合结果或常量**:不能直接放明细字段(`TOTAL(${销售额})` 非法,`TOTAL(SUM_AGG(${销售额}))` 合法)。
|
|
29
|
+
- **表格计算可以嵌套表格计算**(如 `TOTAL(TOTAL(SUM_AGG(...)))`);但**窗口函数不能与表格计算混用**,窗口函数的排序/分组字段必须是严格的聚合结果。
|
|
30
|
+
- **分析函数的"同级 vs 嵌套"边界**(重要,旧口径"一个公式只能有一个分析函数"是错的):**同级可共存,嵌套受限**。
|
|
31
|
+
- ✅ **同级(兄弟节点)合法**:多个分析函数可作为兄弟节点出现在同一公式,各自形成独立卫星查询。例:`DEF_ADD(SUM_AGG(${x}), [${d}]) / DEF_ADD(COUNTD_AGG(${x}), [${d}])`(分子分母各一个 DEF_ADD,合法)、`DEF(SUM_AGG(${x}), [${d}]) - ${明细字段}`(DEF 与明细字段同级,合法,因 DEF 校验层是 disAgg)。
|
|
32
|
+
- ❌ **嵌套受限**(来自代码 `JudgeAggNodeCollectorV2`):
|
|
33
|
+
- DEF 家族(`DEF`/`DEF_ADD`/`DEF_SUB`)的**维度区**(第 2 参数)不能含 `DEF_ADD`/`DEF_SUB`(报 `DIMENSION_NO_DEF_SUB_OR_DEF_ADD`);`DEF` 的维度区里若再嵌 `DEF`,内层 DEF 的维度不能含 `ADD_DIM`/`SUB_DIM`/`FIELD_IN`
|
|
34
|
+
- DEF 家族的**指标参数**(第 1 参数)必须是 agg——因 DEF 家族本身是 disAgg,这隐性禁止了 DEF 家族互相嵌套于指标位(如 `DEF(DEF_ADD(...), [${d}])` 非法)
|
|
35
|
+
- LOD 的**维度区**不能含 `INCLUDE`/`EXCLUDE`
|
|
36
|
+
- **预计算 vs 运行时**:简单聚合与普通函数的组合可预计算;`DEF`/LOD/`WINDOW_`、表格计算、`FIELD_IN`、`ADD_DIM`/`SUB_DIM` 等要在运行时计算(会附带额外计算成本)。
|
|
37
|
+
- **校验层性质 ≠ 语义层性质**:上表把 DEF 家族 / LOD / WINDOW 都归入"分析函数独立聚合层"(语义层口径,确实各自定义独立聚合范围),但**校验层性质不同**——DEF 家族 / LOD / `ADD_DIM`/`SUB_DIM` 归 **disAgg**,WINDOW 系列 / `RANK_AGG` 归 **agg**。混用合法性以校验层为准(详见规则 9)。
|
|
38
|
+
|
|
39
|
+
---
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
## 一、公式语法规范(必须严格遵守)
|
|
2
|
+
|
|
3
|
+
**规则 1:从函数库选择候选,并核对目标主题函数面板。** 本地参考不构成实例函数白名单;未核实的函数不套用 Excel / SQL / 其他 BI 语法。以下需求优先使用右侧写法:
|
|
4
|
+
|
|
5
|
+
- ❌ `COALESCE(${a}, ${b}, ${c})` / `IFNULL(${x}, 默认)` → ✅ `NVL(${a}, ${b}, ${c})`
|
|
6
|
+
- 包含判断用 ✅ `FIND("x", ${字段}, 1)>0`;模式匹配可用 `REGEXP(${字段}, ".*x.*")`,其中 x 须按正则转义。前缀/后缀用 `STARTWITH` / `ENDWITH`;`INDEXOF(文本,数值索引)` 是取字符,不是查找子串。
|
|
7
|
+
- ❌ `NOTNULL(${字段})` → ✅ `!ISNULL(${字段})` 或 `NOT(ISNULL(${字段}))`
|
|
8
|
+
- ❌ `LENB(s)` → ✅ `LEN(s)`(LEN 按字符计,中文算 1 个字符)
|
|
9
|
+
- ❌ `IF(条件, 真值, 假值)` 之外的 IFS 等 → 多条件用 ✅ `IF(条件1, 结果1, 条件2, 结果2, ..., 其他结果)`(IF 本身就是多分支,见函数库)
|
|
10
|
+
|
|
11
|
+
**规则 2:AND / OR / IN / LIKE / BETWEEN / IS NULL 都不是中缀运算符。** 这些 SQL 关键字写成中缀形式都会报错,公式里这样表达:
|
|
12
|
+
|
|
13
|
+
- ❌ `${A} > 1 AND ${B} > 2` → ✅ `${A} > 1 && ${B} > 2`,或 `AND(${A} > 1, ${B} > 2)`
|
|
14
|
+
- ❌ `${城市} = "北京" OR "上海"` → ✅ `${城市} = "北京" || ${城市} = "上海"`,或 `OR(${城市} = "北京", ${城市} = "上海")`
|
|
15
|
+
- ❌ `${城市} IN ("北京", "上海")` → ✅ `IN(${城市}, "北京", "上海")`(IN 是**函数**,不是中缀运算符)
|
|
16
|
+
- ❌ `${名称} LIKE "%三维%"` → ✅ `FIND("三维", ${名称}, 1)>0`;前缀 `STARTWITH(${名称}, "三维")`;后缀 `ENDWITH(${名称}, "三维")`;正则 `REGEXP(${名称}, ".*三维.*")`
|
|
17
|
+
- ❌ `${日期} BETWEEN a AND b` → ✅ `${日期} >= a && ${日期} <= b`
|
|
18
|
+
- ❌ `${字段} IS NULL` / `${字段} IS NOT NULL` → ✅ `ISNULL(${字段})` / `!ISNULL(${字段})`
|
|
19
|
+
- 需要"等于/不等于且双方可能为 NULL"的**空值安全比较**,用 `IS DISTINCT FROM` / `IS NOT DISTINCT FROM`(运算符),例如 `${A} IS DISTINCT FROM ${B}`
|
|
20
|
+
|
|
21
|
+
**规则 3:判断结果按逻辑值使用。** 官方函数页会用 1/0 或 true/false 表示结果,类型表标注 bool。需要数值计数时显式 `IF(条件,1,0)`,例如 `IF(ISNULL(${A}),1,0)+IF(ISNULL(${B}),1,0)`,避免依赖跨引擎隐式转换。
|
|
22
|
+
|
|
23
|
+
**规则 4:生成字符串拼接优先用 `CONCATENATE`。** 官方运算符文档支持 `+` 的文本拼接重载;显式函数便于区分数字相加与文本拼接。`||` 是逻辑或。
|
|
24
|
+
|
|
25
|
+
- ✅ `CONCATENATE(${省份}, ${城市})`;解析已有 `${省份}+${城市}` 时按字段类型判断,不直接判错。
|
|
26
|
+
|
|
27
|
+
**规则 5:日期不能和字符串直接比较,先统一类型。**
|
|
28
|
+
|
|
29
|
+
- ❌ `${日期} >= "2024-01-01"` → ✅ `${日期} >= TODATE("2024-01-01")`
|
|
30
|
+
- ✅ 日期范围:`${日期} >= TODATE("2024-01-01") && ${日期} < TODATE("2024-02-01")`
|
|
31
|
+
- ✅ 也可提取数字部分再比:`YEAR(${日期}) = 2024 && MONTH(${日期}) >= 3`
|
|
32
|
+
|
|
33
|
+
**规则 6:公式内的字符串常量一律用双引号。**
|
|
34
|
+
|
|
35
|
+
- ❌ `DATEDIF(${签单日期}, TODAY(), D)` → ✅ `DATEDIF(${签单日期}, TODAY(), "D")`
|
|
36
|
+
- 字符串常量必须带引号:❌ `IF(${城市} = 北京, ...)` → ✅ `IF(${城市} = "北京", ...)`
|
|
37
|
+
- 输出固定文本要写成文本字面量:✅ `IF(${销售额} > 10000, "高", "低")`
|
|
38
|
+
|
|
39
|
+
**规则 7:聚合计算不能嵌套聚合。** 聚合函数(`SUM_AGG` 等)的参数必须是**非聚合**的表达式——指标字段、维度、或指标字段与普通函数的计算结果;聚合函数里再写聚合函数会报错。
|
|
40
|
+
|
|
41
|
+
- ❌ `SUM_AGG(SUM_AGG(${销售额}))` → ✅ `SUM_AGG(${销售额})`
|
|
42
|
+
- ✅ `SUM_AGG(${销售额} * ${单价})`(内部是普通运算,允许)
|
|
43
|
+
|
|
44
|
+
**规则 8:字段引用统一用 `${...}` 形式,区分大小写。** `${Sales}` 与 `${sales}` 是不同字段;引用时务必与字段实际名称一致。`${...}` 内部可以是"字段名""字段ID"或"组件参数名"(详见下方"字段引用语法");AI 生成公式时统一用已有字段名 `${字段名}`(涉及组件参数时用参数名 `${参数名}`),AI 解析公式时要能识别 `${字段ID}` 与组件参数两种形式。通过 `calculated-field validate/add/update` 校验或写入计算字段时,公式中的每次字段出现还必须在 `CalculatedFieldModel` 中声明来源:主题字段用 `.reference(fieldName, position, tableNames)`,BI 业务模型字段用 `.modelReference(fieldName, position, modelName)`。
|
|
45
|
+
|
|
46
|
+
**规则 9:聚合函数 vs 普通函数的混用限制。** 系统按**校验层性质**把表达式分四类(这是混用判定的唯一依据,不是按语义层"是否聚合"判):
|
|
47
|
+
|
|
48
|
+
- **聚合类(agg)**:`SUM_AGG`/`AVG_AGG`/`COUNT_AGG`/`COUNTD_AGG`/`APPROX_COUNTD_AGG`/`MAX_AGG`/`MIN_AGG`/`MEDIAN_AGG`/`PERCENTILE_AGG`/`STDEV_AGG`/`VAR_AGG`、**WINDOW 系列(`WINDOW_SUM` 等)/ `RANK_AGG`**(性质继承指标参数,必为 agg)
|
|
49
|
+
- **非聚合类(disAgg)**:普通函数(数学/日期/文本/逻辑)、明细字段、维度字段、**`DEF` 家族(`DEF`/`DEF_ADD`/`DEF_SUB`)**、**LOD(`FIXED`/`INCLUDE`/`EXCLUDE`)**、`ADD_DIM`/`SUB_DIM`
|
|
50
|
+
- **表格计算类(tableCal)**:`TOTAL`/`ACC_SUM`/`RANK_ANLS`/`PREVIOUS_PERIOD`/`SAME_PERIOD`/`PERIOD_ANLS`/`PERIOD_TD`
|
|
51
|
+
- **常量类(dual)**:字面量数值/字符串、`TRUE/FALSE/NULL`、组件参数、用户标记的常量字段、`FIELD_IN` 及纯常量组合表达式
|
|
52
|
+
|
|
53
|
+
**混用规则(按节点边界判,不是公式级全局禁止)**:
|
|
54
|
+
|
|
55
|
+
- **"混用报错"只发生在普通运算符与普通(非聚合)函数的同一参数列表内**——`+`/`-`/`*`/`/`/比较/逻辑/`IF`/`CONCATENATE` 等(非聚合函数)的兄弟子节点里,不能同时出现「agg/tableCal」与「disAgg」。
|
|
56
|
+
- ❌ `SUM_AGG(${x}) + ${明细字段}`(agg 与 disAgg 同级,报错)
|
|
57
|
+
- ❌ `RANK_ANLS(SUM_AGG(${x}), 0, "desc") + ${明细字段}`(tableCal 与 disAgg 同级,报错)
|
|
58
|
+
- ✅ `SUM_AGG(${x}) + SUM_AGG(${y})`(都 agg)、`${A} + ${B}`(都 disAgg)、`RANK_ANLS(SUM_AGG(${x}), 0, "desc") + SUM_AGG(${y})`(tableCal 与 agg 同级,合法,整体 tableCal)
|
|
59
|
+
- **tableCal 在校验层"形如聚合"**:`likeAgg() = agg || dual || tableCal`——可与 agg / dual / tableCal 同级,不能与 disAgg 同级;与 dual 同级整体仍是 tableCal(不是 dual)。
|
|
60
|
+
- **函数边界可以穿越性质**(这是合法的,不算混用):
|
|
61
|
+
- 聚合函数的参数须为 disAgg/dual,**不能是 agg/tableCal**(聚合不嵌套聚合)——如 `SUM_AGG(${x} + 1)`、`SUM_AGG(IF(${x} > 0, ${y}, 0))` 合法
|
|
62
|
+
- `DEF` 家族:第 1 参数须为 agg,维度/过滤参数须为 disAgg/dual
|
|
63
|
+
- 表格计算 / WINDOW 系列 / `RANK_AGG`:指标参数须为 agg
|
|
64
|
+
- **常量类跨界**:既可出现在聚合公式里(如 `SUM_AGG(${x} + 1)` 里的 `1`),也可出现在非聚合公式里,不触发混用限制。
|
|
65
|
+
|
|
66
|
+
> 一句话:**"公式里既有 agg 又有 disAgg"不一定非法**——`SUM_AGG(${x} + 1)`、`TOTAL(SUM_AGG(${x}), 0, "sum")`、`DEF(SUM_AGG(${x}), [${d}]) - ${明细字段}` 都合法;只有当 agg 与 disAgg **直接做同级兄弟节点**(落在同一个普通运算符/普通函数的参数列表里)时才报错。
|
|
67
|
+
|
|
68
|
+
> **关键(易踩坑,DEF vs WINDOW 的差别)**:`DEF` 家族与 LOD 在**语义层**各自定义独立聚合范围(卫星查询),但在**校验层**被当作**非聚合(disAgg)**——因此 `DEF(SUM_AGG(${x}), [${d}]) - ${明细字段}`、`{FIXED ${d}: SUM_AGG(${x})} - ${明细字段}` **合法**;而 WINDOW 系列 / `RANK_AGG` 在校验层是**聚合(agg)**,`WINDOW_SUM(SUM_AGG(${x}), ...) - ${明细字段}` 会触发混用报错。判断"能否与明细字段混用"等混用问题,一律以**校验层性质**为准。
|
|
69
|
+
|
|
70
|
+
---
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# 公式排错与扩展
|
|
2
|
+
|
|
3
|
+
来源:[函数计算格式](https://help.fanruan.com/finebi/doc-view-2.html)、[语法 FAQ](https://help.fanruan.com/finebi/doc-view-1323.html)、[运算符和不合法报错](https://help.fanruan.com/finebi/doc-view-1287.html)、[公式不合法原因](https://help.fanruan.com/finebi/doc-view-849.html)。先读取实际表达式、字段类型、公式位置、主题 profile 和完整报错;节点性质细则见 [合法性约束](formula-validation.md)。
|
|
4
|
+
|
|
5
|
+
## 1. 按现象定位
|
|
6
|
+
|
|
7
|
+
| 现象 | 检查与处理 |
|
|
8
|
+
|---|---|
|
|
9
|
+
| 缺少标示符 | 找缺失操作数、尾部运算符、不配对括号,如 `ABS(${金额})+` |
|
|
10
|
+
| 字符错误 | 配对英文双引号;区分公式转义和 JS/JSON 宿主转义;清除复制网页带来的零宽字符 |
|
|
11
|
+
| 字段识别失败 | 设计器需选择字段形成标签;CLI 则使用真实 `${字段名}` 并声明每个出现位置及来源,不把裸中文当作字段 |
|
|
12
|
+
| 操作符两端类型不同 | 日期常量用 DATE/TODATE;算术前将数值文本转换,确保 IF/SWITCH 分支类型一致 |
|
|
13
|
+
| `开始<NOW()<结束` | 改为 `${开始}<NOW() && NOW()<${结束}`;不能写链式比较 |
|
|
14
|
+
| 不支持直接输出聚合函数 | 判断是否数据编辑/明细表;改用组件计算,或用明确维度的 DEF 提供明细结果 |
|
|
15
|
+
| 聚合嵌套聚合 | 去掉重复汇总层;“记录数”已是聚合结果,不能再 AVG_AGG;跨行平均用支持的窗口或快速计算 |
|
|
16
|
+
| 聚合与非聚合混用 | 对同一运算节点检查性质;例如 `IF(${销量}=0,0,SUM_AGG(${销售额})/SUM_AGG(${销量}))` 中判断也应使用 SUM_AGG(销量) |
|
|
17
|
+
| 指标条件后的字段不允许普通函数 | 保留指标条件语义并在聚合层使用,或选适合该口径的过滤;不要为了通过校验随意清掉过滤 |
|
|
18
|
+
| 窗口分组/排序性质不一致 | 字段来自当前分析视图,或在 DEF 包裹时来自该 DEF 独立视图;不能拿 TOTAL 等表格计算结果给 RANK_AGG 排序 |
|
|
19
|
+
| 快速计算指标标红 | 日期字段、分组方式及行列布局是否满足该函数;检查 Y/M/W、range=0/1 等常量参数 |
|
|
20
|
+
| 合计不等于可见行求和 | 识别自动合计重算粒度、去重成员是否跨组、分母是否变动;FIELD_IN 分支在合计视图可能不同 |
|
|
21
|
+
| 日期差突然变成距今天的差 | 空日期参与 DATEDIF,先 ISNULL;核对参数方向及 M 的月/分钟含义 |
|
|
22
|
+
| 公式合法但结果错误 | 手算一组含零、空、负值、重复成员和时间缺口的数据;分别对照明细、分组、小计/总计 |
|
|
23
|
+
|
|
24
|
+
错误码只引用实例实际返回值或 [合法性约束](formula-validation.md) 中已知码;无法取得原生结果时明确“静态检查/待目标主题校验”,不编造执行成功。
|
|
25
|
+
|
|
26
|
+
## 2. Excel / SQL 迁移
|
|
27
|
+
|
|
28
|
+
来源:[BI 与 Excel 对照](https://help.fanruan.com/finebi/doc-view-1349.html),单函数页用于裁决其过时条目。
|
|
29
|
+
|
|
30
|
+
| 原需求 | FineBI 选择 |
|
|
31
|
+
|---|---|
|
|
32
|
+
| SUM / AVERAGE 跨行统计 | SUM_AGG / AVG_AGG;MAX/MIN 比较参数,MAX_AGG/MIN_AGG 才聚合当前视图 |
|
|
33
|
+
| SUMIF(S) / COUNTIF(S) | 当前视图 `SUM_AGG(IF(...))` / `COUNTD_AGG(IF(...,成员,NULL))`;固定维度或独立过滤用 DEF |
|
|
34
|
+
| IFS | 多条件 IF;旧版本用嵌套 IF |
|
|
35
|
+
| VLOOKUP / 跨表查值 | 先核对模型关系或数据编辑合并,不虚构同名公式函数 |
|
|
36
|
+
| SEARCH / LIKE | FIND 查位置,STARTWITH/ENDWITH 查前后缀,REGEXP 做模式匹配 |
|
|
37
|
+
| TEXT 格式化 | FORMAT,但直连只支持日期首参;格式化返回文本 |
|
|
38
|
+
| `<>` / `AND` / `IS NULL` | `!=` / `AND(...)` 或 `&&` / `ISNULL(...)` |
|
|
39
|
+
| Excel WEEKDAY | FineBI 返回 0=周日到 6=周六 |
|
|
40
|
+
| STDEV | STDEV_AGG 官方对应 STDEV.P,总体标准差,不直接当样本标准差 |
|
|
41
|
+
|
|
42
|
+
## 3. 自定义函数
|
|
43
|
+
|
|
44
|
+
来源:[自定义函数简介](https://help.fanruan.com/finebi/doc-view-13.html)、[StringCat 示例](https://help.fanruan.com/finebi/doc-view-1244.html)。
|
|
45
|
+
|
|
46
|
+
仅抽取数据支持,且不支持自定义聚合或快速计算函数。官方机制为 Java 类实现 Function,或继承 AbstractFunction 并实现 `run(Object[] args)`;自定义函数名以 class 文件名为准、只支持英文字母,在“其他函数”中展示。
|
|
47
|
+
|
|
48
|
+
StringCat 是部署后的自定义函数示例,不是所有实例都具备的内置函数;普通拼接优先 CONCATENATE。只有目标实例确认已注册并提供签名时,才把自定义名写进公式。
|
|
49
|
+
|
|
50
|
+
用户明确需要开发/部署自定义函数时再读原文对应部署方式:容器部署需每个 bi-web 和 bi-engine-worker 都具备对应 package 路径的 class,依赖 JAR 放相应 customlib,重启后生效;示例的方法一不支持 EXE 安装版。检查实际版本、部署拓扑和权限后制定变更方案;“写公式”的请求不包含上传 class、注册或重启服务的授权。
|
|
51
|
+
|
|
52
|
+
## 4. 来源冲突处理
|
|
53
|
+
|
|
54
|
+
官方文档也存在示例误植。按单函数签名、适用版本和实际面板核对,业务数学含义单独验证。
|
|
55
|
+
|
|
56
|
+
- Excel 对照页称 NOT 不支持、IFERROR 需手工组合,但两者均有独立函数页;以 [NOT](https://help.fanruan.com/finebi/doc-view-2189.html)、[IFERROR](https://help.fanruan.com/finebi/doc-view-2324.html) 与目标版本为准。
|
|
57
|
+
- [INCLUDE](https://help.fanruan.com/finebi/doc-view-2772.html) 表头出现 EXCLUDE、参数解释出现“排除”,但正文和示例明确是增加维度;生成 `{INCLUDE ...}`。
|
|
58
|
+
- [EXCLUDE](https://help.fanruan.com/finebi/doc-view-2771.html) 参数表称空维度整表聚合,与本页“不排除任何维度”的示例冲突;按保留当前视图维度解释,实际主题验证。
|
|
59
|
+
- [WEEK](https://help.fanruan.com/finebi/doc-view-1419.html) 部分文字将 F1/F7 与周起始日绑定;本页参数定义和平台设置示例表明周起始日单独配置。
|
|
60
|
+
- 数值概览的 ROUND 示例与单函数页不一致,以 [ROUND](https://help.fanruan.com/finebi/doc-view-1379.html) 的 `ROUND(2.15,1)=2.2` 为参考;精度疑问用目标数据验证,不把 OLD_ROUND 默认加入可用清单。
|
|
61
|
+
- 报错汇总仍写 PERCENTILE_AGG 仅实时支持,但 [单函数页](https://help.fanruan.com/finebi/doc-view-1395.html) 记载 6.1.4 起支持抽取;汇总中的 APPROX_COUNT_AGG、案例中的 SUMS_AGG / DATEIF 不作为新函数收录。
|
|
62
|
+
- EARLIER 漏斗示例文字存在转化率分子分母方向问题;按业务约定的当前/上一节点或当前/首节点计算。
|
|
63
|
+
- 图片中才有的公式不据标题猜抄;本 Skill 用可读签名和正文提供规范化模板。需要严格复现图示布局或隐藏参数时打开原页确认。
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
## 五、公式合法性约束清单
|
|
2
|
+
|
|
3
|
+
系统对公式做合法性校验时,主要按下表把关。AI 生成公式后应逐条自查,避免生成即报错。
|
|
4
|
+
|
|
5
|
+
### 聚合性质规则
|
|
6
|
+
|
|
7
|
+
| 规则 | 说明 | 报错提示 |
|
|
8
|
+
|------|------|---------|
|
|
9
|
+
| 聚合不能嵌套聚合 | `SUM_AGG(SUM_AGG(...))` 非法;聚合参数必须是明细级表达式 | 报"聚合函数嵌套聚合函数"类错误 |
|
|
10
|
+
| 聚合与非聚合不能混用 | **"混用"指同一普通运算符/普通函数的参数列表里同时出现 agg 与 disAgg 兄弟子节点**(如 `SUM_AGG(${x}) + ${明细字段}` 报错),**不是公式级全局禁止**——公式里同时存在 agg 和 disAgg 不一定非法。函数边界可穿越性质:聚合函数收 disAgg 参数(`SUM_AGG(${x} + 1)`)、`DEF`/表格计算/WINDOW 收 agg 指标参数,都合法。**此处"聚合类"指 `SUM_AGG` 等 / WINDOW 系列 / `RANK_AGG`,不含 DEF 家族与 LOD**——DEF 家族 / LOD 在校验层属 disAgg,可与明细字段自由混用(如 `DEF(SUM_AGG(${x}), [${d}]) - ${明细字段}` 合法)。常量类(字面量、`TRUE/FALSE/NULL`、组件参数、常量字段、`FIELD_IN`)可跨界(规则 9) | 报"聚合函数和非聚合函数混用"类错误 |
|
|
11
|
+
| 表格计算指标参数须为聚合或常量 | `TOTAL(${销售额})` 非法,`TOTAL(SUM_AGG(${销售额}))`、`TOTAL(SUM_AGG(${x})+1)` 合法;第一个参数必须为聚合函数 | "参数只有是聚合函数或者常量,且第一个参数必须为聚合函数"(错误码 61500006) |
|
|
12
|
+
| 窗口函数排序/分组字段须为聚合 | `RANK_AGG` 等窗口函数的排序/分组/寻址字段必须都是聚合结果,表格计算结果不能用作排序字段 | "指标/分组字段/寻址字段的性质必须一致,需要都为聚合"(错误码 61500035) |
|
|
13
|
+
| 窗口函数不能与表格计算混用 | 同一公式内窗口函数(`WINDOW_`/`RANK_AGG`)与表格计算(`TOTAL`/`ACC_SUM`/`RANK_ANLS` 等)不能同时出现 | "窗口函数不能与表格计算混用"(错误码 61500036) |
|
|
14
|
+
|
|
15
|
+
### 嵌套与共存规则
|
|
16
|
+
|
|
17
|
+
| 规则 | 说明 |
|
|
18
|
+
|------|------|
|
|
19
|
+
| 分析函数同级共存合法 | 多个分析函数可作为**兄弟节点**出现在同一公式(如 `DEF_ADD(...) / DEF_ADD(...)`、`DEF(...) - ${明细字段}`),各自形成独立卫星查询。**旧口径"一个公式只能有一个分析函数"是错的** |
|
|
20
|
+
| DEF 家族维度区禁含 DEF_ADD/DEF_SUB | `DEF`/`DEF_ADD`/`DEF_SUB` 的第 2 参数(维度数组)里出现 `DEF_ADD`/`DEF_SUB` 报错(`DIMENSION_NO_DEF_SUB_OR_DEF_ADD`);`DEF` 维度区里嵌套 `DEF` 时,内层 DEF 维度不能含 `ADD_DIM`/`SUB_DIM`/`FIELD_IN` |
|
|
21
|
+
| DEF 家族指标参数须 agg(隐性禁嵌套) | DEF 家族第 1 参数必须是 agg;因 DEF 家族自身是 disAgg,这等价于禁止 DEF 家族互相嵌套于指标位(`DEF(DEF_ADD(...), [${d}])` 非法) |
|
|
22
|
+
| LOD 维度区禁含 INCLUDE/EXCLUDE | `{FIXED/INCLUDE/EXCLUDE ... : 聚合}` 的维度部分出现 `INCLUDE`/`EXCLUDE` 报错(`DIMENSION_NO_INCLUDE_EXCLUDE`) |
|
|
23
|
+
| LOD 表达式嵌套 | 最大 2 层 |
|
|
24
|
+
| `IF`、`DEF` 嵌套深度 | 由服务端配置控制(有默认上限) |
|
|
25
|
+
|
|
26
|
+
### 其他校验
|
|
27
|
+
|
|
28
|
+
| 规则 | 说明 |
|
|
29
|
+
|------|------|
|
|
30
|
+
| 带明细过滤的字段 | 带明细过滤(明细过滤器)的字段不允许出现在非聚合公式中;出现在聚合公式内(如 `SUM_AGG(${x})`)合法 |
|
|
31
|
+
| `DEF_ADD` / `DEF_SUB` 结果类型 | 含 `DEF_ADD` / `DEF_SUB` 的公式输出**维度类型**(文本 / 日期 / 时间戳 / 时间,即 `Type.String` / `Type.Date` / `Type.Timestamp` / `Type.Time`)时报错(错误码 61500034,"def_add/def_sub 不允许输出到维度");结果须为数值类型 |
|
|
32
|
+
| 表格计算输出文本类型不支持 | 公式整体性质为 tableCal 时,输出文本(String)会报错(错误码 61500033),**无论是否显式嵌套聚合**——判定只看「整体性质 tableCal + 输出类型 String」。例:`IF(RANK_ANLS(SUM_AGG(${x}), 0, "desc") <= 3, "是", "否")` 非法(整体 tableCal + 输出文本),改 `IF(... <= 3, 1, 0)`(输出数值)合法。如需输出文本标签,可用数值(1/0)配合组件层显示转换,或把排名字段直接拖入组件、用条件格式/过滤打标签 |
|
|
33
|
+
| 聚合窗口函数输出维度类型不支持 | 公式性质同时为 agg + window(即含 `WINDOW_*` 系列 / `RANK_AGG`)且输出维度类型(文本 / 日期 / 时间戳 / 时间)时报错(错误码 61500038,"聚合window不支持输出维度")。例:`CONCATENATE(WINDOW_SUM(SUM_AGG(${销售额}), [${城市}], [SUM_AGG(${销售额})]), "元")` 非法;纯 `WINDOW_SUM(...)` 输出数值合法 |
|
|
34
|
+
| 引擎可用性 | Spider 独有 / Direct 独有 / LOD 仅直连标准版(见"引擎差异速查") |
|
|
35
|
+
|
|
36
|
+
---
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# FineBI 公式
|
|
2
|
+
|
|
3
|
+
根据当前字段、引擎和分析区域解释或生成公式,不套用 Excel / SQL 的函数名与语法。专业规则按以下入口读取,不预先加载全部参考。
|
|
4
|
+
|
|
5
|
+
## 官方函数参考
|
|
6
|
+
|
|
7
|
+
从官方[函数学习路径](https://help.fanruan.com/finebi/doc-view-1709.html)及 FineBI 7.0「函数专题」目录整理。逐篇来源、主题覆盖、文档冲突处理见 [官方文档索引](formula-help-index.md)。官方示例中的设计器字段标签在本 Skill 中统一改写为 `${字段名}`;模板是待目标环境校验的表达式,不代表已在用户数据上执行。
|
|
8
|
+
|
|
9
|
+
先明确公式所在位置(新增公式列 / 组件计算字段)、主题类型和引擎,再确定输入类型、分组粒度、排序及分母口径。信息已在上下文中时直接复用;教学或离线写公式可给出标明假设的模板。连接到实际主题并准备落地时执行下方查询与校验。
|
|
10
|
+
|
|
11
|
+
## 目标主题查询
|
|
12
|
+
|
|
13
|
+
为实际主题生成或修改公式前,必须执行 `formula functions --subject-id <目标主题ID>`(可用 `--query` / `--name` 缩小范围),确认返回的 `context.subjectId` 和 `profiles`,按该主题面板选择函数和语法。未指定主题的通用目录及其他主题的查询结果不能作为当前主题的函数依据。
|
|
14
|
+
|
|
15
|
+
同一任务、同一连接和主题且 profile 未变化时可复用查询结果;切换连接或主题后重新查询,新增未查询过的函数时补查。本文参考和模板用于理解语义,不替代实例面板;面板未列出某函数不等于引擎绝对不支持,应优先选择面板提供的写法,不能仅凭通用示例补入。查询失败时先解决连接、权限或 provider 问题。
|
|
16
|
+
|
|
17
|
+
计算字段生成后,必须让同一份 JavaScript 通过目标主题的 `calculated-field validate` 再保存;修改公式或引用后重新校验。面板查询成功不代表表达式合法,原生校验通过也不代表业务口径正确。
|
|
18
|
+
|
|
19
|
+
## 按需读取
|
|
20
|
+
|
|
21
|
+
- 解析或生成公式:读取 [语法规范](formula-syntax.md);字段引用、字面量或运算符不明确时查 [基础语法](formula-basics.md)。
|
|
22
|
+
- calculated-field context/validate/add/update:先从 `context` 获取字段目录和 JavaScript 骨架;同一份 `CalculatedFieldModel` JavaScript 依次用于校验和新增或更新,并声明每次字段出现的来源。
|
|
23
|
+
- 聚合层级、嵌套或等价性:查 [语义模型](formula-semantics.md) 和 [合法性约束](formula-validation.md) 的相关规则。
|
|
24
|
+
- 函数选型与简例:查 [函数库](formula-functions.md);写具体调用前按类别核对参数的含义、类型、必填性、默认值和限制:[文本](formula-parameters-text.md)、[日期](formula-parameters-date.md)、[数值与逻辑](formula-parameters-math-logic.md)、[聚合与表格计算](formula-parameters-aggregate.md)、[DEF/LOD/窗口/引用](formula-parameters-analysis.md)。
|
|
25
|
+
- 使用位置、数据库限制、日期重载、CLEAN 过滤范围、窗口和引用函数:同时查 [官方使用边界](formula-help-boundaries.md) 的对应章节。
|
|
26
|
+
- 引擎差异、公式位置、空值及字段作用域:查 [使用场景](formula-contexts.md)。
|
|
27
|
+
- 自然语言生成公式:查 [生成指南](formula-generation.md) 的对应需求、函数族或模板;用合法性约束校验涉及的表达式。
|
|
28
|
+
- 清洗、拆分、日期转换和条件赋值:查 [文本与日期模板](formula-recipes-text-date.md)。
|
|
29
|
+
- 购买频次、同期群、跨行、移动平均、累计同比、动态成本和合计:查 [分析模板](formula-recipes-analysis.md)。
|
|
30
|
+
- 公式不合法、类型错误、Excel 迁移或自定义函数:查 [排错与扩展](formula-troubleshooting.md)。
|
|
31
|
+
- 名词含义:查 [术语表](formula-glossary.md)。
|
|
32
|
+
|
|
33
|
+
同一连续任务内复用未变化的已读内容;文件变化、进入未读能力,或上下文压缩后所需规则已不可用时,仅补读相关部分。复用参考文档不能代替实际字段、引擎和目标版本的核验。
|
|
34
|
+
|
|
35
|
+
## 引擎范围
|
|
36
|
+
|
|
37
|
+
区分 Spider(抽取)、Direct(直连)及自助/标准分析主题。标准主题跨粒度计算使用 LOD,不手写 DEF、WINDOW 或引用函数;LOD 不能代替所有跨行/错期需求。具体数据库、重载与位置限制查 [官方使用边界](formula-help-boundaries.md),可写候选以目标主题面板为准。
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# 语义交接契约
|
|
2
|
+
|
|
3
|
+
## 目的
|
|
4
|
+
|
|
5
|
+
本契约仅记录 `$finebi-cli-agent` 为 Widget/Dashboard JS 制品解析的业务语义。契约不包含 JS 源码;CLI 命令必须另行遵循通用执行流程,其中仅 `delete` 命令需要人工确认。
|
|
6
|
+
|
|
7
|
+
## 规划器请求
|
|
8
|
+
|
|
9
|
+
使用以下 JSON 结构。省略没有实际含义的可选属性;不得臆造占位 ID。
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"contractVersion": "1.0",
|
|
14
|
+
"scenario": "CREATE_DASHBOARD",
|
|
15
|
+
"sourceRequest": "在销售分析主题中创建销售总览仪表板。",
|
|
16
|
+
"subject": {
|
|
17
|
+
"id": "subject_001",
|
|
18
|
+
"name": "销售分析"
|
|
19
|
+
},
|
|
20
|
+
"datasets": [
|
|
21
|
+
{
|
|
22
|
+
"key": "dataset:sales_detail",
|
|
23
|
+
"id": "analysis_ds_001",
|
|
24
|
+
"name": "销售明细",
|
|
25
|
+
"sourceTableName": "销售明细",
|
|
26
|
+
"subjectId": "subject_001",
|
|
27
|
+
"usable": true,
|
|
28
|
+
"fields": [
|
|
29
|
+
{
|
|
30
|
+
"id": "field_region",
|
|
31
|
+
"name": "region",
|
|
32
|
+
"transferName": "地区",
|
|
33
|
+
"displayName": "地区",
|
|
34
|
+
"type": "STRING"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "field_amount",
|
|
38
|
+
"name": "sales_amount",
|
|
39
|
+
"transferName": "销售额",
|
|
40
|
+
"displayName": "销售额",
|
|
41
|
+
"type": "NUMBER"
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
"models": [],
|
|
47
|
+
"relationships": [],
|
|
48
|
+
"existingWidgets": [],
|
|
49
|
+
"requestedWidgets": [
|
|
50
|
+
{
|
|
51
|
+
"key": "widget:sales_by_region",
|
|
52
|
+
"name": "各地区销售额",
|
|
53
|
+
"intent": "比较各地区的销售额",
|
|
54
|
+
"chartType": "CLUSTERED_COLUMN",
|
|
55
|
+
"datasetKeys": ["dataset:sales_detail"],
|
|
56
|
+
"modelKeys": [],
|
|
57
|
+
"encodings": [
|
|
58
|
+
{
|
|
59
|
+
"role": "CATEGORY",
|
|
60
|
+
"datasetKey": "dataset:sales_detail",
|
|
61
|
+
"fieldId": "field_region",
|
|
62
|
+
"sourceTableName": "销售明细",
|
|
63
|
+
"fieldName": "region"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"role": "VALUE",
|
|
67
|
+
"datasetKey": "dataset:sales_detail",
|
|
68
|
+
"fieldId": "field_amount",
|
|
69
|
+
"sourceTableName": "销售明细",
|
|
70
|
+
"fieldName": "sales_amount",
|
|
71
|
+
"aggregation": "SUM",
|
|
72
|
+
"sort": "DESC"
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"filters": [],
|
|
76
|
+
"presentation": {}
|
|
77
|
+
}
|
|
78
|
+
],
|
|
79
|
+
"requestedDashboard": {
|
|
80
|
+
"key": "dashboard:sales_overview",
|
|
81
|
+
"name": "销售总览",
|
|
82
|
+
"intent": "集中查看核心销售表现",
|
|
83
|
+
"widgetRefs": [
|
|
84
|
+
{
|
|
85
|
+
"key": "widget:sales_by_region",
|
|
86
|
+
"source": "REQUESTED",
|
|
87
|
+
"name": "各地区销售额"
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"layout": {
|
|
91
|
+
"description": "一个组件铺满首屏"
|
|
92
|
+
},
|
|
93
|
+
"filters": [],
|
|
94
|
+
"presentation": {}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
模型指标集结构(仅在实际使用模型字段时加入):
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"key": "model:sales_metrics",
|
|
104
|
+
"id": "model_sales",
|
|
105
|
+
"name": "销售指标集",
|
|
106
|
+
"subjectId": "subject_001",
|
|
107
|
+
"evidence": "MODEL_INFO",
|
|
108
|
+
"fields": [
|
|
109
|
+
{"id": "metric_sales", "name": "销售额", "kind": "INDEX", "type": "NUMBER"},
|
|
110
|
+
{"id": "field_order_no", "name": "订单编号", "kind": "TABLE_FIELD", "datasetName": "订单明细", "type": "STRING"},
|
|
111
|
+
{"id": "calc_completion_rate", "name": "达成率", "kind": "CALCULATED_FIELD", "type": "NUMBER"}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
组件引用模型字段时,在 `modelKeys` 中登记对应 key,并让字段语义项携带
|
|
117
|
+
`modelKey + modelName + fieldName + kind`;`TABLE_FIELD` 还携带 `datasetName`,不要同时携带物理字段的 `datasetKey` 或 `sourceTableName`。
|
|
118
|
+
|
|
119
|
+
## 必需语义
|
|
120
|
+
|
|
121
|
+
- `contractVersion` 必须为 `1.0`。
|
|
122
|
+
- `scenario` 必须为 `CREATE_WIDGET` 或 `CREATE_DASHBOARD`。
|
|
123
|
+
- `sourceRequest` 保留用户的原始请求。
|
|
124
|
+
- `subject` 必须是一个已经确认存在的主题。
|
|
125
|
+
- `datasets` 仅包含已经确认存在且归属于 `subject.id` 的 `analysis-ds` 资源;仅纳入待创建组件或基于字段的仪表板过滤器实际使用的数据集和字段。若仪表板仅复用已有组件且没有此类过滤器,该数组可以为空。
|
|
126
|
+
- `datasets[].sourceTableName` 必须是 `analysis-ds info.name` 返回的分析表转义名/显示名。严格按 `analysis-ds info` 返回值保留每个选定字段的 `id`、原始 `name`、可选 `transferName`、`displayName` 和 `type`。
|
|
127
|
+
- `models` 仅包含属于 `subject.id` 且被本次制品实际使用的模型指标集。通过 `subject.info` 的 `resources.models` 或 `model.search` 确认模型,再用 `model.info` 确认指标、数据集字段和模型计算字段时记录 `evidence: MODEL_INFO`;运行时没有模型目录命令、但既有 `widget dsl` 明确回显 `model(...)` 时记录 `WIDGET_DSL`。不得把 `analysis-ds`、公共数据集或物理表搜索结果改写成模型证据。
|
|
128
|
+
- `models[].fields[]` 使用模型字段展示名 `name`,`kind` 只能是 `INDEX`、`TABLE_FIELD` 或 `CALCULATED_FIELD`。`TABLE_FIELD` 来自 `model info.datasets[].fields[]` 并保留所属 `datasetName`,`CALCULATED_FIELD` 来自 `model info.calculatedFields[]`。`MODEL_INFO` 证据必须保留 CLI 返回的模型 ID 和字段 ID;`WIDGET_DSL` 无法提供 ID 时可为 null,禁止臆造。模型根级维度和记录数不纳入该数组。
|
|
129
|
+
- `fields[].type` 必须是 CLI 返回的 `STRING`、`NUMBER`、`DATE`、`DATE_TIME`、`UNKNOWN` 或 `null`;不得臆造 `TEXT` 等类型。`UNKNOWN` 无法满足类型相关映射时进入 `BLOCKED`。
|
|
130
|
+
- `relationships` 仅包含通过 `relationship info` 确认存在、且被某个 `requestedWidgets[].datasetKeys`(或
|
|
131
|
+
`requestedDashboard` 基于字段的过滤器)跨数据集字段引用实际依赖的表关系;不得臆造尚不存在的关系。仅当所有已用数据集之间不存在跨数据集字段引用时,该数组才可以为空。
|
|
132
|
+
- `relationships[].leftDatasetKey`/`rightDatasetKey` 必须分别匹配某个 `datasets[].key`;`leftTableId`/`rightTableId`、
|
|
133
|
+
`leftFieldId`/`rightFieldId`、`type`、`status` 必须与 `relationship info` 返回的对应 `pair[].tableId`、
|
|
134
|
+
`pair[].fields[].id`、`relationships[].type`、`relationships[].status` 一致,使用 `relationship-command-design.md` 定义的
|
|
135
|
+
CLI key。`status` 非 `DEFAULT` 时必须先向用户说明风险,不得直接用于生成 DSL 关联。
|
|
136
|
+
- `existingWidgets` 包含已经确认存在的组件引用,并携带 `key`、`id`、`name` 和 `subjectId`。
|
|
137
|
+
- `requestedWidgets` 包含所有需要生成 JS 文件的组件。`key` 和 `name` 在本次请求内必须唯一。
|
|
138
|
+
- 对 `CREATE_WIDGET`,`requestedDashboard` 必须为 `null`;对 `CREATE_DASHBOARD`,该字段必填。
|
|
139
|
+
- `widgetRefs[].source` 必须为 `REQUESTED` 或 `EXISTING`。已有组件引用必须包含已确认的 `id`;待创建组件引用必须匹配一个 `requestedWidgets[].key`。
|
|
140
|
+
- `encodings`、`filters`、`layout` 和 `presentation` 表达业务意图,而不是 DSL 语法。仅包含实际推断或确认的决策。
|
|
141
|
+
- 每个包含字段的语义项必须恰好选择一种来源:物理字段携带 `datasetKey + sourceTableName + fieldName`,模型字段携带 `modelKey + modelName + fieldName + kind`,其中 `TABLE_FIELD` 还携带 `datasetName`。对应 key 必须存在于组件的 `datasetKeys` 或 `modelKeys`,并解析到顶层 `datasets` 或 `models` 的唯一字段;同一作用域内同名字段不能唯一解析时进入 `BLOCKED`。DSL 分别使用 `from(sourceTableName).dim/sum(fieldName)`、`model(modelName).metrics().sum(fieldName)`、`model(modelName).dataset(datasetName).dim/sum(fieldName)` 或 `model(modelName).calculated().dim/sum(fieldName)`;不得写数据集 ID、模型 ID 或字段 ID,也不得把同名物理字段与模型字段互换。
|
|
142
|
+
|
|
143
|
+
交接前,验证所有 ID、名称、字段归属、数据集归属、关系归属、组件归属和交叉引用。在解析器的全局可见组件范围内,每个 `EXISTING`
|
|
144
|
+
组件引用名称必须恰好匹配一项,并且每个 `REQUESTED` 组件引用名称在创建前必须没有匹配项。若影响生成制品的值缺失或匹配数量无效,则要求澄清或进入
|
|
145
|
+
`BLOCKED`,不得使用占位值或静默省略。
|
|
146
|
+
|
|
147
|
+
## 跨数据集关系
|
|
148
|
+
|
|
149
|
+
当某个 `requestedWidgets[]`(通过其 `encodings[].datasetKey`)或 `requestedDashboard` 基于字段的过滤器,引用了归属于不同
|
|
150
|
+
`datasets[].key` 的字段时,这些数据集背后的分析表之间必须存在已确认的关系,FineBI 才能正确关联对应数据。解析器必须:
|
|
151
|
+
|
|
152
|
+
1. 对每一对被跨数据集字段引用实际关联的分析表,调用 `relationship info --subject-id <subjectId>` 确认现有关系。
|
|
153
|
+
2. 关系已存在且 `status` 为 `DEFAULT` 时,把该关系写入 `relationships` 数组。
|
|
154
|
+
3. 关系不存在,或存在但 `status` 非 `DEFAULT`(例如 `MISS_FIELD`、`TYPE_NOT_MATCH`)时,不得静默继续;应向用户说明现状。需要新增或替换关系时,按
|
|
155
|
+
`command-workflows.md` §5.6 走独立的 `relationship add` 计划、复检和执行流程,无需人工确认;写入成功且只读回查通过后,才把该关系补充进
|
|
156
|
+
`relationships` 数组。
|
|
157
|
+
|
|
158
|
+
`relationships[]` 单条结构:
|
|
159
|
+
|
|
160
|
+
```json
|
|
161
|
+
{
|
|
162
|
+
"leftDatasetKey": "dataset:sales_detail",
|
|
163
|
+
"leftTableId": "fd07d579db78434faea320ff9a4a91c0",
|
|
164
|
+
"leftFieldId": "fd07d579db78434faea320ff9a4a91c0_driver",
|
|
165
|
+
"rightDatasetKey": "dataset:customer_info",
|
|
166
|
+
"rightTableId": "8becd865b01949a19c36ce05ffb730f3",
|
|
167
|
+
"rightFieldId": "8becd865b01949a19c36ce05ffb730f3_driver",
|
|
168
|
+
"type": "MANY_TO_MANY",
|
|
169
|
+
"status": "DEFAULT"
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
字段语义:
|
|
174
|
+
|
|
175
|
+
| 字段 | 说明 |
|
|
176
|
+
|--------------------------------------|----------------------------------------------------------------------------------------|
|
|
177
|
+
| `leftDatasetKey` / `rightDatasetKey` | 必须分别匹配某个 `datasets[].key`。 |
|
|
178
|
+
| `leftTableId` / `rightTableId` | 与 `relationship info` 返回的 `pair[].tableId` 一致,等于对应 `datasets[].id`。 |
|
|
179
|
+
| `leftFieldId` / `rightFieldId` | 与 `relationship info` 返回的 `pair[].fields[].id` 一致。 |
|
|
180
|
+
| `type` | `MANY_TO_MANY`、`MANY_TO_ONE`、`ONE_TO_MANY`、`ONE_TO_ONE` 之一,取自 `relationship info` 返回值。 |
|
|
181
|
+
| `status` | `UNKNOWN`、`DEFAULT`、`MISS_FIELD`、`TYPE_NOT_MATCH` 之一;非 `DEFAULT` 必须向用户说明风险后才能继续消费该关系。 |
|
|
182
|
+
|
|
183
|
+
## JS 制品映射
|
|
184
|
+
|
|
185
|
+
确认交接对象后,调用方、用户或可用的外部生成工作流必须提供一个 JSON 对象:
|
|
186
|
+
|
|
187
|
+
```json
|
|
188
|
+
{
|
|
189
|
+
"contractVersion": "1.0",
|
|
190
|
+
"files": {
|
|
191
|
+
"widget:sales_by_region": "C:\\work\\finebi-dsl\\sales-by-region.js",
|
|
192
|
+
"dashboard:sales_overview": "C:\\work\\finebi-dsl\\sales-overview.js"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
规则:
|
|
198
|
+
|
|
199
|
+
- `files` 必须包含每个 `requestedWidgets[].key`,以及存在时的 `requestedDashboard.key`。
|
|
200
|
+
- 每个值都必须是指向现有 `.js` 文件的绝对路径。
|
|
201
|
+
- 将每个值解析为文件系统的 canonical/real path。所得规范路径必须两两不同,因此两个 artifact key 不得通过不同拼写、相对路径片段或符号链接别名指向同一文件。
|
|
202
|
+
- 规划器仅消费路径。不得消费内联 DSL、从说明性文本推断文件,或改写已生成文件。本契约不要求或指定特定的生成器 Skill。
|
|
203
|
+
- 额外且未映射的文件不会生成命令。
|
|
204
|
+
|
|
205
|
+
## 前置资源边界
|
|
206
|
+
|
|
207
|
+
主题、自助数据集、字段或跨数据集关系缺失时,可以先通过通用命令流程创建所需前置资源,但不得把尚未创建的资源或占位 ID
|
|
208
|
+
写入本交接对象。搜索命中 `public-ds` 时,必须先以该公共数据集为来源在目标主题内创建 `analysis-ds`,并使用写响应中的实际 ID 完成 `analysis-ds.info` 和必要的 `preview` 回查;不得把公共数据集 ID 写入 `datasets`,也不得因已经命中公共数据集而继续查询数据连接。前置写操作必须单独规划并复检,创建成功且只读回查后,再生成本契约;仅当前置操作为 `delete` 时等待人工确认。
|
|
209
|
+
|
|
210
|
+
版本 1.0 的制品输入始终是上述 JSON 对象。不得隐式改成自然语言交接,也不得混用两种格式。
|