Files
oracle-jump-query-public/references/bos-metadata.md
T

12 KiB
Raw Blame History

BOS 数据字典与系统地图

本文件由 SKILL.md 整理拆分而来,保留原说明内容。

数据字典(AD_TABLE / AD_COLUMN / AD_REFBYTABLE)

通用查询规则

处理 BOS 业务单据(如零售单、采购单、调拨单、销售单等)时,必须遵循以下查询路径:

用户提供表名称时的对象解析顺序

用户给出一个表名称,且没有明确要求绕过 BOS 元数据、直接按 Oracle 物理对象查询时,不要立即对该名称执行 describe 或数据查询。先确认它是 BOS 逻辑表、BOS 实际表,还是未在 BOS 注册的数据库对象。

  1. 先用用户给出的名称精确查询 AD_TABLE,同时返回英文名称 NAME、通常为中文的显示名称 DESCRIPTION 和 REALTABLE_ID。必要时再用 LIKE 扩大范围,不要把模糊命中的第一条直接当成目标。
SELECT t.ID,
       t.NAME,
       t.DESCRIPTION,
       t.REALTABLE_ID,
       rt.NAME AS REALTABLE_NAME,
       rt.DESCRIPTION AS REALTABLE_DESCRIPTION
FROM AD_TABLE t
LEFT JOIN AD_TABLE rt ON rt.ID = t.REALTABLE_ID
WHERE UPPER(t.NAME) = UPPER('<表名称>')
   OR t.DESCRIPTION = '<表名称>'
  1. 查到 AD_TABLE 记录后,先向用户说明其 DESCRIPTION 和 NAME。若 REALTABLE_ID 非空,它表示该 BOS table 实际查询的表,应沿 REALTABLE_ID -> AD_TABLE.ID 使用目标记录的 NAME 继续查询结构或数据。原始名称可能只是 BOS 系统中的虚拟表,在 Oracle 数据库中并不存在;不要因为找不到同名物理表就判定对象不存在。若目标记录仍有 REALTABLE_ID,继续解析到最终实际表,并防止循环引用。
  2. 查到 AD_TABLE 记录但 REALTABLE_ID 为空时,使用该记录的 NAME 作为物理表候选,再到数据库字典确认。
  3. AD_TABLE 完全查不到时,该对象仍可能是未在 BOS 元数据中维护的数据库表。先查数据库表;查不到后再查普通视图,最后查物化视图。使用 ALL_* 字典时应返回 OWNER,避免把其他 schema 的同名对象误当成当前业务对象。
SELECT OWNER, TABLE_NAME
FROM ALL_TABLES t
WHERE t.TABLE_NAME = UPPER('<表名称>')
  AND NOT EXISTS (
      SELECT 1
      FROM ALL_MVIEWS mv
      WHERE mv.OWNER = t.OWNER
        AND mv.MVIEW_NAME = t.TABLE_NAME
  )
ORDER BY CASE WHEN OWNER = SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') THEN 0 ELSE 1 END,
         OWNER
SELECT OWNER, VIEW_NAME
FROM ALL_VIEWS
WHERE VIEW_NAME = UPPER('<表名称>')
ORDER BY CASE WHEN OWNER = SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') THEN 0 ELSE 1 END,
         OWNER
SELECT OWNER, MVIEW_NAME
FROM ALL_MVIEWS
WHERE MVIEW_NAME = UPPER('<表名称>')
ORDER BY CASE WHEN OWNER = SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') THEN 0 ELSE 1 END,
         OWNER

只有 AD_TABLE、数据库表、普通视图和物化视图都未命中时,才说明当前可见范围内未找到该对象。查询到 BOS 虚拟表时,业务含义和字段配置仍以原 AD_TABLE 记录为入口,物理结构与数据查询则以 REALTABLE_ID 最终指向的实际表为准。

1. 术语 → 表名(AD_TABLE)

遇到不懂的业务术语(如"零售单提交"、"采购入库"),先查 AD_TABLE:

SELECT ID,
       NAME,
       TABLENAME,
       DESCRIPTION,
       MASK,
       PROC_SUBMIT,
       HAS_TRIG_BD,
       TRIG_BD,
       HAS_TRIG_AC,
       TRIG_AC,
       HAS_TRIG_AM,
       TRIG_AM
FROM AD_TABLE
WHERE NAME LIKE '%关键词%' OR DESCRIPTION LIKE '%关键词%'
  • NAME:表名(英文,如 M_RETAIL)
  • DESCRIPTION:业务说明(中文,如"零售单")
  • MASK:表支持的业务动作代码,可由多个字母组成:A=新增、M=修改、D=删除、Q=查询、U=取消提交、V=作废、S=提交。分析表单功能、按钮或流程时,应以该字段实际包含的代码判断该表声明支持的动作,不要仅凭表名推断。
  • PROC_SUBMIT:该单据的提交存储过程名称(非空即代表该表有提交逻辑)
  • HAS_TRIG_BD / TRIG_BD:HAS_TRIG_BD='Y' 时,TRIG_BD 是删除前触发的存储过程,简称 bd
  • HAS_TRIG_AC / TRIG_AC:HAS_TRIG_AC='Y' 时,TRIG_AC 是新增后触发的存储过程,简称 ac
  • HAS_TRIG_AM / TRIG_AM:HAS_TRIG_AM='Y' 时,TRIG_AM 是修改后触发的存储过程,简称 am

分析 BOS 业务表时,PROC_SUBMIT 和这些 TRIG_* 字段都属于业务逻辑入口。不要只看物理触发器或过程源码;先从 AD_TABLE 判断表单事件过程是否配置,再按过程名继续查源码、依赖和影响表。

2. 字段含义(AD_COLUMN)

不理解某个字段的业务含义时,查 AD_COLUMN:

SELECT DBNAME, NAME, DESCRIPTION, COLTYPE
FROM AD_COLUMN
WHERE AD_TABLE_ID = <AD_TABLE.ID>
ORDER BY ORDERNO

3. 主表 → 明细表(AD_REFBYTABLE)

对于单据类表,其明细表、付款表等子表必须通过 AD_REFBYTABLE 查找,不要靠猜测命名规则:

SELECT t1.NAME AS MAIN_TABLE,
       t2.NAME AS DETAIL_TABLE,
       c.DBNAME AS REF_COLUMN,
       r.ASSOCTYPE
FROM AD_REFBYTABLE r
LEFT JOIN AD_TABLE t1 ON r.AD_TABLE_ID = t1.ID
LEFT JOIN AD_TABLE t2 ON r.AD_REFBY_TABLE_ID = t2.ID
LEFT JOIN AD_COLUMN c ON r.AD_REFBY_COLUMN_ID = c.ID
WHERE t1.NAME = '<AD_TABLE.NAME>'
  • ASSOCTYPE:"n"=一对多明细,"1"=强关联/嵌入
  • 得到明细表名后,再通过 AD_COLUMN 查看各明细表的字段含义

核心表说明

表 说明
AD_TABLE 所有业务表的元数据注册表,每条记录对应一张业务表
AD_COLUMN 所有业务字段的元数据注册表,含字段名(DBNAME)、显示名(NAME)、描述(DESCRIPTION)、类型(COLTYPE)等
AD_REFBYTABLE 主表与明细表的关联关系,记录主表→明细表的外键引用

AD_REFBYTABLE 关联字段

字段 说明
AD_TABLE_ID 主表ID → 关联 AD_TABLE.ID
AD_REFBY_TABLE_ID 明细表ID → 关联 AD_TABLE.ID
AD_REFBY_COLUMN_ID 明细表中的外键列ID → 关联 AD_COLUMN.ID,通过 AD_COLUMN.DBNAME 获取实际列名
ASSOCTYPE 关联类型("1"=强关联/嵌入, "n"=一对多明细)

查询主表→明细表关系的 SQL 模板

SELECT t1.NAME AS MAIN_TABLE,
       t2.NAME AS DETAIL_TABLE,
       c.DBNAME AS REF_COLUMN,
       r.ASSOCTYPE
FROM AD_REFBYTABLE r
LEFT JOIN AD_TABLE t1 ON r.AD_TABLE_ID = t1.ID
LEFT JOIN AD_TABLE t2 ON r.AD_REFBY_TABLE_ID = t2.ID
LEFT JOIN AD_COLUMN c ON r.AD_REFBY_COLUMN_ID = c.ID
WHERE t1.NAME = 'M_RETAIL'

示例:M_RETAIL 的明细表

主表 明细表 外键列 关联类型
M_RETAIL M_RETAILITEM M_RETAIL_ID n
M_RETAIL M_RETAILPAYITEM M_RETAIL_ID n
M_RETAIL M_RETAIL_PRO_ITEM M_RETAIL_ID n
M_RETAIL M_RETAIL_RATEITEM M_RETAIL_ID n
M_RETAIL M_RETAIL_DISITEM M_RETAIL_ID n
M_RETAIL M_RETAIL_VOUCHERSITEM M_RETAIL_ID n
M_RETAIL M_RETAIL_BATCHITEM M_RETAIL_ID n

查询字段描述的 SQL 模板

SELECT DBNAME, NAME, DESCRIPTION, COLTYPE
FROM AD_COLUMN
WHERE AD_TABLE_ID = (SELECT ID FROM AD_TABLE WHERE NAME = 'M_RETAILITEM')
ORDER BY ORDERNO

BOS 系统地图分析(AD_TABLE_TEXT 经验)

BOSNDS3.AD_TABLE_TEXT 是 BOS 内部的表配置导出脚本生成器。分析该过程可以反推出 BOS 元数据体系:菜单、模块、业务表、字段、主子表、按钮动作、提交过程、权限目录和报表模板主要由数据字典表驱动。

当用户要求分析“BOS 系统菜单 / 模块目录 / 表结构地图 / 某个业务模块结构”时,优先按下面的元数据链路整理,不要只看物理表:

AD_SUBSYSTEM
  -> AD_TABLECATEGORY
  -> AD_ACCORDION
  -> AD_TABLE
  -> AD_COLUMN
  -> AD_REFBYTABLE
  -> AD_ACTION
  -> DIRECTORY
  -> AD_CXTAB / AD_CXTAB_JPARA / AD_CXTAB_DIMENSION / AD_CXTAB_FACT

核心含义:

  • AD_SUBSYSTEM:子系统。
  • AD_TABLECATEGORY:表类别 / 模块分类。
  • AD_ACCORDION:折叠菜单 / 菜单分组。
  • AD_TABLE:业务表注册表,含 DESCRIPTION、MASK(读写业务动作)、PROC_SUBMIT、HAS_TRIG_BD/TRIG_BD、HAS_TRIG_AC/TRIG_AC、HAS_TRIG_AM/TRIG_AM、DIRECTORY_ID、AD_TABLECATEGORY_ID、AD_ACCORDION_ID 等。
  • AD_COLUMN:字段元数据,含字段名、显示名、业务描述、控件类型、引用列、默认值、限定值组等。
  • AD_REFBYTABLE:主表到明细表、子表的关系。
  • AD_ACTION:表动作、按钮、URL、存储过程脚本入口。
  • DIRECTORY:数据权限目录挂载点。
  • AD_CXTAB 相关表:公开查询 / 报表模板及其参数、维度、指标。

常用系统地图 SQL:

SELECT ss.NAME AS SUBSYSTEM,
       tc.NAME AS TABLE_CATEGORY,
       ac.NAME AS ACCORDION,
       t.ID AS AD_TABLE_ID,
       t.NAME AS TABLE_NAME,
       t.DESCRIPTION,
       t.MASK,
       t.PROC_SUBMIT,
       t.HAS_TRIG_BD,
       t.TRIG_BD,
       t.HAS_TRIG_AC,
       t.TRIG_AC,
       t.HAS_TRIG_AM,
       t.TRIG_AM,
       d.NAME AS DIRECTORY_NAME
FROM AD_TABLE t
LEFT JOIN AD_TABLECATEGORY tc ON tc.ID = t.AD_TABLECATEGORY_ID
LEFT JOIN AD_SUBSYSTEM ss ON ss.ID = tc.AD_SUBSYSTEM_ID
LEFT JOIN AD_ACCORDION ac ON ac.ID = t.AD_ACCORDION_ID
LEFT JOIN DIRECTORY d ON d.ID = t.DIRECTORY_ID
WHERE t.NAME LIKE '%关键词%' OR t.DESCRIPTION LIKE '%关键词%'
ORDER BY ss.NAME, tc.ORDERNO, ac.ORDERNO, t.ORDERNO, t.NAME

分析单个业务表时,至少同时检查:

  • AD_TABLE:表归属、提交过程、表单事件过程(bd/ac/am)、权限目录。
  • AD_COLUMN:字段业务含义和值域。
  • AD_REFBYTABLE:明细表和外键列。
  • AD_ACTION:按钮和动作脚本。
  • ALL_TRIGGERS / USER_OBJECTS:触发器、同名前缀过程或函数。

注意:这套元数据能还原 BOS 业务结构,不等于完整物理数据库模型。复杂过程内部逻辑、动态 SQL、触发器副作用和前端特殊页面仍需要结合源码继续分析。

数据权限系统

GET_USERSPERMSQL 函数

数据库内置 get_userspermsql 函数,用于获取用户的数据权限过滤条件。

函数签名:

FUNCTION get_userspermsql(
    p_users_id NUMBER,   -- 用户ID (USERS.ID)
    p_tableid  NUMBER,   -- 表ID (AD_TABLE.ID)
    p_col      VARCHAR2  -- 字段名 (AD_COLUMN.DBNAME),可为NULL
) RETURN CLOB           -- 返回权限过滤SQL

返回值:

  • 空字符串:全权限(无需过滤)
  • SQL条件:如 C_STORE_ID IN (...),需拼接到 WHERE 子句

权限模型:

用户 → GROUPUSER → 用户组 → GROUPPERM → 安全目录 → 权限SQL
                              ↓
                          AD_TABLE.DIRECTORY_ID

使用权限过滤查询

1. 查询用户权限:

python oracle_skill.py perm 940 12983

返回:

{
  "user_id": "940",
  "table_id": "12983",
  "perm_sql": "M_OTHER_INOUT.C_STORE_ID IN(...)",
  "has_restriction": true
}

2. 带权限过滤的查询:

python oracle_skill.py qperm 940 12983 "SELECT * FROM M_OTHER_INOUT WHERE BILLDATE=20260501"

自动拼接权限条件后执行:

SELECT * FROM M_OTHER_INOUT 
WHERE BILLDATE=20260501 
AND M_OTHER_INOUT.C_STORE_ID IN(...)

常用表ID参考

表名 AD_TABLE.ID 说明
M_RETAIL 12964 零售单主表
M_RETAILITEM 12965 零售明细
M_OTHER_INOUT 12983 其他出入库
C_STORE_CHKDAY 18182 门店盘点日