医药 ERP Oracle Text-to-SQL 分析技能
本技能基于一套已用真实库表逐字段校准的数据字典(2026-08-25 校准,修正 32 处标注错误),覆盖医药 ERP 的销售、采购、库存、往来账全链路。生成 SQL 时必须遵守本文件规则。
数据库环境
- Oracle 11g,通过 oracle-mcp 连接器访问(工具:
execute_query、describe_table;仅允许 SELECT/WITH,最大 200 行,超时 30 秒) - 若连接器不可用,先让用户确认
~/.workbuddy/mcp.json中oracle-mcp配置(HTTP MCP,默认http://127.0.0.1:8080/mcp)且服务已启动
字典参考文件(生成 SQL 前必读相关部分)
references/tables.md— 表元信息(29 张表:业务说明、粒度、高频场景、示例提问)references/fields.md— 字段元信息(实测校准后的字段名/类型/枚举)references/joins.md— 表关联关系(含标准 JOIN 示例 SQL,全部实测跑通)references/common_fields.md— 通用字段释义(全库统一命名字段)references/invoice_tables.md— 发票/开票模块(INVOICEMT/INVOICEREQMT 等,2026-08-25 实测补充)references/stock_tables.md— 库存模块(⭐用户指定的标准批次库存 SQL,查库存必读)references/sales_analysis.md— 销售情况分析模块(⭐用户指定的标准销售分析 SQL + 效期预警规则 + 退货分析口径,查"销售员/开票员销售情况/退货"必读)references/settle_tables.md— 收款/结算/应收应付模块(⭐用户指定的标准收款/付款/待付款/待收款 SQL,SETTLEMT:SSK*=收款单/PFK*=付款单;APGOODSMT:应付未结算;ARGOODSMT:应收未结算,查"收款/结算/回款/应付/待付款/应收/未收款"必读)references/purchase_analysis.md— 采购模块(⭐用户指定的标准入库/采购退货/上游退补分析 SQL,PURINMT/PURINDT,查"入库/采购/进货/退给供应商/上游退补"必读)
按用户问题先从 tables.md 定位目标表,再查 fields.md 确认字段,joins.md 取关联写法。
硬规则(违反会直接 ORA-00904 报错或口径错误)
- 数量字段一律用
NUM,全库不存在 QTY 字段(所有 DT 明细表)。 - 日期字段
DATES是 CHAR(10) 文本,格式YYYY-MM-DD,按字符串比较/截取:DATES >= '2026-01-01',月份用SUBSTR(DATES,1,7)。 - 多类型单据表用
RULEID过滤单据类型,关键枚举:- SALEOUTMT:
4szcn61oa8b0tz79=销售出库;3cc08h3z7cnkrv2q=销售退补价;1w8bnrjr7c7no0bj=销售退货;4x9b6ccyaffoeknc=直进直销 - PURINMT:
12ealvx84t7bl04x=采购入库;446rh28k3sel2q6q=采购退补;2ajc0ikub06h2dbl=采购退货;4x9b6ccyaffoeknc=直进直销 - PURORDERMT:
5x80rrxrb24q2ktt=采购订单 - PURNOTESMT:
3kdoxf3x18yf07w1=采购收货;03azykbyb256xp0x=采购退货;4vh03cmy2yboceb3=采购退补开票 - SALENOTESMT:
67b55qi64q7dzsq2=销售开票单(BILLCODE 前缀 SKP*,原误标"销售订单");5htug3bwbynl7sx6=销售退回开票/收货(STP*);6bbop4cmbi7cx30r=销售退补开票 - SALERTNMT:
5bx3wpbqay57esdw=销售退回收货
- SALEOUTMT:
- 通用状态枚举(以 DICTDOC 实测为准):
BILLSTATE0=正常;1=删除;2=挂起(注意 SALEOUTMT、PURINMT 无此字段)。SALESSTATE0=可销;1=不可销。ISEND/ISDONEY/N。 - SALEOUTMT 无 BILLSTATE 列,状态/类型筛选一律走 RULEID。
- 批次关联键是
ANGLEID:ANGLEBALANCE.ANGLEID = BATCHCODE.ANGLEID(同 GOODSID+ENTID)。BATCHCODE 无 BILLNO 列(有 BATCHCODE 批号列、GEBJJ 单价列)。SALEOUTDT.BATCHNO 的关联对象实测存疑,遇批次明细需求优先走 ANGLEID。 - GOODSDOC 厂家字段是
MANUFACTURER(无 PRODUCER);批次日期是PRODUCEDATE/VALDATE(无 PRODATE/EXPDATE)。 - ANGLEBALANCE 无批次字段,粒度为货位+商品+货主;查商品总库存按 GOODSID 汇总。
- 往来账:WLDXDOC=往来科目档案(WLKMID→科目名),WLDXJC=往来余额(WLKMID+WLDXID 定位,YE=余额)。典型科目:
1cb49bc59yff1fvk=客户应收款、141yc6fybzfdyrvk=供应商应付款。 - 编码翻译查 DICTDOC(FDNAME 字段名区分大小写,DICTVALUE=值,DICTLIST=显示中文)。
- 「查库存/库存情况/库存分析」一律用用户指定的标准批次库存 SQL(完整模板见
references/stock_tables.md):ANGLEBALANCE A JOIN GOODSDOC B JOIN BATCHCODE C ON A.ANGLEID=C.ANGLEID JOIN STOREROOM D ON A.LOCATID=D.LOCATID JOIN ORGDOC E ON A.OWNERID=E.ORGID(五表 JOIN 均带 ENTID)。核心口径:库存数量=A.PLACENUM>0、库存金额=PLACENUM*C.GEBJJ、库存状态=D.LOCATNAME(不含"不合格"三字即合格)、固定企业A.ENTID='E4EK8ZUYN1D'、效期=C.VALDATE。STORBALANCE 仅作仓库级粗粒度参考,与批次口径有差异时以批次口径为准。 - 业务术语「开票员/开票情况」= 销售开票单(SALENOTESMT)的 CAOZY 操作员,按
RULEID='67b55qi64q7dzsq2'(SKP* 单据)+CAOZY关联 STAFFDOC 分组统计。不是 INVOICEMT(发票登记)的操作员——那是发票登记员口径。BILLCODE 前缀速查:SKP*=销售开票、STP*=销售退回开票/收货、FPS*=开票申请、SFP*=销项发票登记、PFP*=进项发票。 - 「销售情况分析」(销售员/开票员当日或区间销售)一律用用户指定的标准销售分析 SQL(完整模板见
references/sales_analysis.md):SALENOTESMT(A) JOIN SALENOTESDT(B) 九表关联——开票员=A.CAOZY→STAFFDOC.C、业务员=A.SALEMANID→STAFFDOC.D、客户=A.CLIENTID→BUSINESSDOC.F、部门=A.PAYORGID→ORGDOC.G、货主=B.OWNERID→ORGDOC.H、批次=B.ANGLEID→BATCHCODE.I。口径:销售额=SUM(B.TAXAMOUNT)、销售数量=SUM(B.NUM)、毛利=SUM((B.PRICE-I.GEBJJ)*B.NUM)(用户SQL列名"成本金额"实为毛利)。固定A.ENTID='E4EK8ZUYN1D'、RULEID='67b55qi64q7dzsq2',按需换 GROUP BY 维度和 DATES 时间范围。开票员(CAOZY)与业务员(SALEMANID)是两个独立维度,用户说"开票员"就 GROUP BY C,说"销售员/业务员"就 GROUP BY D,绝不混用。统计单据数默认加A.BILLSTATE='0'排除已作废单(否则与 ERP 界面对不上;含作废为口径 B,详见 references/sales_analysis.md 的"单据状态过滤"节),单据数=COUNT(DISTINCT A.BILLNO)(2026-08-25 用户确认:「开单数量」一律指单据张数,用 COUNT(DISTINCT A.BILLNO),禁用 COUNT(1)——那是明细行数,约为张数的 4 倍)。 - 效期预警(硬性):凡做销售情况分析,必须检查销售批次效期:
I.VALDATE <= 分析日期+30天即触发预警(30 天内到期或已过期),过期与近效期分级标注,在报告中单列「效期预警」段落(商品/批号/有效期/业务员/客户/数量/金额)。 - 「收款分析/本日收款/结算/回款」一律用用户指定的标准收款 SQL(完整模板见
references/settle_tables.md):SETTLEMT(A) JOIN BUSINESSDOC(B) ONA.RFID=B.BUSINESSID(注意关联键是 RFID 不是 CLIENTID)。口径:结算金额=SUM(A.JIESJE)、收款单=RULEID='4e4vfumx60jknylb'(SSK*)、付款单=3l0m1ung5mqb0usf(PFK*)、固定A.ENTID='E4EK8ZUYN1D'。SETTLEMT 无 BILLSTATE 字段,不要加状态过滤。「付款分析/本日付款」同构:同样九成套用,仅 RULEID 换付款单(付款口径也是用户 2026-08-25 确认的标准 SQL)。 - 「待付款/应付/供应商未结算」一律用用户指定的标准应付 SQL(完整模板见
references/settle_tables.md):APGOODSMT(A) JOIN BUSINESSDOC(B) ONA.RFID=B.BUSINESSID,A.ISSETTLE='N',待付款金额=SUM(A.TAXAMOUNT - A.JIESJE)。必须加A.ENTID='E4EK8ZUYN1D'(用户 2026-08-25 确认;原版无此条件,实测混有 E4EVBTQ75AR 另一家企业数据)。该口径为存量余额,不加 DATES 条件;供应商数多(564 家)超 200 行限制,先出 TOP N + 总额。 - 「未收款/应收/客户欠款」一律用用户指定的标准应收 SQL(完整模板见
references/settle_tables.md):ARGOODSMT(A) JOIN BUSINESSDOC(B) ONA.RFID=B.BUSINESSID,A.ISSETTLE='N',A.ENTID='E4EK8ZUYN1D',待收款=SUM(A.TAXAMOUNT - A.JIESJE)(与规则 16 应付完全镜像:AP=供应商/G*,AR=客户/X*)。存量余额口径不加 DATES;客户数多(4,725 家)先出 TOP N + 总额。 - 「入库分析/本日入库/采购入库/进货」一律用用户指定的标准入库 SQL(完整模板见
references/purchase_analysis.md):PURINMT(A) JOIN PURINDT(B) 七表关联——供应商=A.SUPPLIERSID→BUSINESSDOC.F(不是 RFID)、商品=GOODSDOC(E)、部门=A.PAYORGID→ORGDOC.G、货主=B.OWNERID→ORGDOC.H、批次=B.ANGLEID→BATCHCODE.I。口径:入库金额=SUM(B.TAXAMOUNT)、入库数量=SUM(B.NUM)、RULEID='12ealvx84t7bl04x'(采购入库)、固定A.ENTID='E4EK8ZUYN1D'。PURINMT 无 BILLSTATE 不加状态过滤;SUM((B.PRICE-I.GEBJJ)*B.NUM)入库时恒为 0 不要报;入库批次效期 ≤分析日+30 天属采购质量问题需预警。 - 「采购退货/退给供应商的退货」与入库分析同构(完整模板见
references/purchase_analysis.md采购退货节,2026-08-25 用户确认):PURINMT/PURINDT 七表 JOIN,供应商=A.SUPPLIERSID→BUSINESSDOC.F,RULEID='2ajc0ikub06h2dbl'。NUM/TAXAMOUNT 均为负数,汇报取绝对值;无 BILLSTATE;成本金额列不报。方向与销售退货(SALEOUTMT STH*,客户退我)相反。 - 「上游退补/供应商给的优惠」与入库分析同构(完整模板见
references/purchase_analysis.md上游退补节,2026-08-25 用户确认):PURINMT/PURINDT 七表 JOIN,供应商=A.SUPPLIERSID→BUSINESSDOC.F,RULEID='446rh28k3sel2q6q'(PBA* 单据)。方向是供应商让利给我们(与销售退补 SBA* 我们让利给客户相反);金额负数=真实让利、正数=红冲更正,存在成对红冲对冲单需区分净退补额(净额=SUM(TAXAMOUNT) 自动抵消);成本金额列不报;无 BILLSTATE。 - 「退货分析/下游退货/销售退货」一律用用户指定的标准退货 SQL(完整模板见
references/sales_analysis.md退货节):SALEOUTMT(A) JOIN SALEOUTDT(B) 七表关联(无 STAFFDOC),客户=A.CLIENTID→BUSINESSDOC.F,RULEID='1w8bnrjr7c7no0bj'(STH* 单据)。退货 NUM/TAXAMOUNT 均为负数,汇报取绝对值;SUM((B.PRICE-I.GEBJJ)*B.NUM)是毛利冲回;SALEOUTMT 无 BILLSTATE 不加状态过滤。 - 「退补分析/给下游的优惠」与退货同构,仅 RULEID 不同(完整模板见
references/sales_analysis.md退补节,2026-08-25 用户确认):SALEOUTMT/SALEOUTDT 七表 JOIN,RULEID='3cc08h3z7cnkrv2q'(SBA* 单据)——⚠️ 用户首贴误用过退货的 RULEID,已实测确认退补是3cc08h3z7cnkrv2q。SALEOUTMT 全库仅 3 种单据:SCK*=销售出库、SBA*=退补、STH*=退货。退补金额负数=让利给客户、正数=红冲更正,存在成对红冲单需区分净退补额;SUM((B.PRICE-I.GEBJJ)*B.NUM)在退补里无意义不要报;退补常与退货联动(同批号)需联动查看。 - BLOB/大字段:默认不返回,修改类任务需返回(用户 2026-09-18 修正):
- 默认(分析/报表/SELECT 探查类查询):禁止 SELECT
BLOB、CLOB、NCLOB、BFILE、RAW、LONG、LONG RAW类型列,也禁止SELECT *(否则大字段二进制会淹没结果、触发超 200 行/30 秒限制)。必须显式枚举列名,并在describe_table后核对列类型剔除大字段;若仅需确认是否有内容,用DBMS_LOB.GETLENGTH(列) AS 列_字节长度仅返回长度数字。 - 例外(用户明确要获取/修改某条记录的 BLOB,如导出附件、改图片/签章/文件):允许 SELECT 该 BLOB 列返回原始字节,供后续修改或下载。此时连接器原样返回二进制属预期行为,不在"刷屏"禁用之列。
- 判断依据:看用户意图是「看分析报表」还是「取这条 BLOB 数据去改」——前者不返回,后者返回。不要因为上一条默认规则而擅自砍掉用户要修改的 BLOB。
- 默认(分析/报表/SELECT 探查类查询):禁止 SELECT
标准分析流程
- 理解问题 → 定位涉及表(tables.md)
- 不确定字段时先
describe_table验证,不要凭猜测写 SQL - 先探查再聚合:数据量/时间范围/RULEID 分布未知时,先跑探查 SQL
- 销售分析标准口径(近一年示例):
- 销售出库额 = SUM(TAXAMOUNT) WHERE RULEID='4szcn61oa8b0tz79'
- 净销售额 = 全部 RULEID 合计(退货为负)
- 毛利 = SUM(PROFIT),成本 = SUM(COSTAMT),毛利率 = PROFIT/TAXAMOUNT
- 单品维度从 SALEOUTDT + GOODSDOC 取,行级 PROFIT/COSTAMT 都在明细表
- 库存分析:直接套用
references/stock_tables.md的标准批次库存 SQL(含合格判定、金额口径),勿自创关联 - 销售情况分析(销售员/开票员维度):直接套用
references/sales_analysis.md的标准九表 JOIN SQL(含毛利口径),勿自创关联;并强制附效期预警(规则14)
- 结果超过 200 行时改用聚合或加 WHERE 收窄,或分批跑
- 产出分析报表时:给核心指标表 + 关键发现(异常品项、退货集中度、月度断档、盈亏结构)+ 可行动建议
常见坑
- Oracle 11g 不支持一些新语法;
LISTAGG、WITH可用,FETCH FIRST、IIF不可用(用 ROWNUM、CASE WHEN) - 大 IN 子查询(如
BILLNO IN (SELECT ...))性能一般,可改 JOIN - 明细表主键 = BILLNO + BILLSN
- 空值:金额/利润字段可能为 NULL,聚合时用 NVL
维护说明
- 字典源文件(维护入口):
Text-to-SQL数据字典标注模板.xlsx(含「校准记录」Sheet 记录全部修正依据) - 若库表结构变更:先改 Excel 源文件 → 重跑导出脚本刷新 references/*.md → 更新本文件中的枚举值
微信扫一扫