# 生产查询限制与常用业务规则
> 本文件由 SKILL.md 整理拆分而来,保留原说明内容。
## 生产查询限制
直接查询业务表时,必须带明确过滤条件,不要直接查询整表。生产环境数据量很大,`SELECT * FROM
` 这类无条件查询可能返回大量数据、拖慢 Agent 或影响数据库。
生成或执行 `query` / `qperm` SQL 时遵守:
- 必须有 `WHERE` 条件,优先使用日期、单号、门店、客户、状态、主键等业务过滤条件。
- 必须加行数限制,例如 `ROWNUM <= 20`;需要分页时分批查询。
- 不要为了“先看看数据”执行无条件整表查询。
- 统计查询也要限定业务范围,例如日期区间、单据状态、门店范围。
- 如果用户没有给出过滤条件,先追问条件,或先用 `describe` / `AD_COLUMN` / `AD_TABLE` 查询结构和字段含义。
推荐示例:
```sql
SELECT *
FROM M_RETAIL
WHERE BILLDATE = 20260501
AND STATUS = '2'
AND ROWNUM <= 20
```
避免示例:
```sql
SELECT * FROM M_RETAIL
```
## 中文条件与字符集兼容
品小二环境存在已知字符集转换问题:通过 Skill 查询时,中文字符串直接写成 `LIKE '%中文%'`,或直接把中文写入 `=` 等值条件,可能返回 0 行,即使数据库中存在匹配记录。
查询品小二中的中文值时,优先使用 Oracle `UNISTR` 和 Unicode 转义,将 SQL 中的中文条件保持为 ASCII。例如“零售单”的 Unicode 编码为 `96F6 552E 5355`,应写成:
```sql
SELECT ID, NAME, DESCRIPTION
FROM AD_TABLE
WHERE DESCRIPTION LIKE '%' || UNISTR('\96F6\552E\5355') || '%'
AND ROWNUM <= 20
```
精确匹配同样适用,例如“品小二”可写成 `= UNISTR('\54C1\5C0F\4E8C')`。中文条件直接查询返回 0 行时,先改用 `UNISTR` 形式重试,再判断数据是否确实不存在。对其他 client,如果直接中文字面量已验证可用,不必强制改写;但在需要跨客户复用 SQL,或希望让 SQL 文本保持 ASCII、避免客户端/HTTP/命令行传输转换时,`UNISTR` 也是有帮助的通用兜底。该函数返回 Oracle national character set,面对超大表的 `VARCHAR2` 索引条件时仍应关注执行计划;无论使用哪种写法,仍须遵守生产查询的过滤条件和行数限制。
## 常用业务对象说明
当用户使用商品、款号、条码、SKU、库存等业务词时,默认按以下对象理解:
- “商品”“款号”通常指 `M_PRODUCT` 表。
- “条码”“SKU”通常指 `M_PRODUCT_ALIAS` 表。
- 查询条码/SKU 时,首查 `M_PRODUCT_ALIAS.NO` 字段。
- 款号和条码是一对多关系:一个 `M_PRODUCT` 可以对应多条 `M_PRODUCT_ALIAS`。
- 商品明细表中常见的三个商品维度字段:
- `M_PRODUCT_ID`:款号 / 商品,关联 `M_PRODUCT.ID`。
- `M_PRODUCTALIAS_ID`:条码 / SKU,关联 `M_PRODUCT_ALIAS.ID`。
- `M_ATTRIBUTESETINSTANCE_ID`:色码属性 ASI,关联 `M_ATTRIBUTESETINSTANCE.ID`。
- `M_ATTRIBUTESETINSTANCE` 用于记录商品色码属性:
- `VALUE1`:颜色名称。
- `VALUE1_CODE`:颜色编号。
- `VALUE1_ID`:颜色表 ID,关联 `M_COLOR.ID`。
- `VALUE2`:尺码名称。
- `VALUE2_CODE`:尺码编号。
- `VALUE2_ID`:尺码表 ID,关联 `M_SIZE.ID`。
- 如果涉及库存查询,通常查询 `V_FA_STORAGE` 视图。
- `V_FA_STORAGE` 数据量很大,必须同时带店仓条件和款号/条码条件,不允许只查整张库存视图。
库存查询过滤规则:
- 店仓条件应优先使用门店、仓库、店仓 ID 或店仓编码等字段,先通过 `describe` 或 `AD_COLUMN` 确认实际字段名。
- 款号条件走 `M_PRODUCT`;条码/SKU 条件走 `M_PRODUCT_ALIAS`。
- 颜色、尺码、色码属性条件优先走 `M_ATTRIBUTESETINSTANCE`,再分别通过 `VALUE1_ID` 关联 `M_COLOR`、通过 `VALUE2_ID` 关联 `M_SIZE`。
- 通过条码查库存时,应先用 `M_PRODUCT_ALIAS.NO` 找到对应商品,再关联或过滤 `V_FA_STORAGE`。
- 必须加 `ROWNUM` 或分页限制;如果用户没有提供店仓或款号/条码,先追问,不要直接查询库存视图。
示例思路:
```sql
-- 伪示例:实际字段名需先 describe / AD_COLUMN 确认
SELECT *
FROM V_FA_STORAGE s
WHERE s.C_STORE_ID = :store_id
AND s.M_PRODUCT_ID = :product_id
AND ROWNUM <= 20
```
## BOS 新建表最小结构(仅生成 DDL)
按照 BOS 系统规则,为新建表生成结构 SQL 时,至少包含下面八个基础字段和 `ID` 主键。业务字段在此基础上增加,不要只列业务字段而漏掉基础字段。`TableName` 是表名占位符,生成具体方案时替换为用户确认的表名。
```sql
CREATE TABLE TableName (
ID NUMBER(10) NOT NULL,
AD_CLIENT_ID NUMBER(10),
AD_ORG_ID NUMBER(10),
OWNERID NUMBER(10),
CREATIONDATE DATE,
MODIFIERID NUMBER(10),
MODIFIEDDATE DATE,
ISACTIVE CHAR(1) DEFAULT 'Y' NOT NULL,
PRIMARY KEY (ID)
);
```
- “必须包含字段”不等于“所有字段非空”:本模板只有 `ID` 和 `ISACTIVE` 明确 `NOT NULL`,其余六个字段允许为空。
- `ID`、`AD_CLIENT_ID`、`AD_ORG_ID`、`OWNERID`、`MODIFIERID` 使用 `NUMBER(10)`;`CREATIONDATE`、`MODIFIEDDATE` 使用 `DATE`;`ISACTIVE` 使用 `CHAR(1)`,默认值为 `'Y'`。
- 不要把新增业务记录时的 `AD_CLIENT_ID=37`、`AD_ORG_ID=27` 或主键取号规则自动写成建表 `DEFAULT`;本最小模板只为 `ISACTIVE` 指定默认值,日期字段也不自动增加 `DEFAULT SYSDATE`。
- 这是新建表结构规则,不表示可以自动修改既有表。Skill 仅生成 DDL 并明确“未执行”,由用户或 DBA 确认后人工执行;不通过 `query` / `qperm` 建表,也不隐式写入 BOS 元数据。
## BOS 新建业务单据表单默认配置
新增 BOS 表单时,先判断是否为业务单据。通常包含 `DOCNO` 的表单可按业务单据理解,并结合实际用途核实;新建业务单据表单通常应包含 `DOCNO`、`STATUS`、`ISACTIVE`、提交时间和提交人。这些业务字段在上面的八个基础字段及 `ID` 主键之上补充,其中 `ISACTIVE` 已属于基础字段,不重复创建。本节是业务单据的默认约定,不要求所有基础资料表都增加单号或提交字段。
字段及 BOS 元数据配置:
| 字段 | 业务含义 | 读写方式 | 下拉框选项名称 | 字段翻译器 | 读写打印规则 | 默认值 |
| --- | --- | --- | --- | --- | --- | --- |
| `DOCNO` | 单据编号 | 单据编号 | 不适用 | 按目标环境单据编号配置核实 | `0010111111` | 按维护的单据编号生成器取号 |
| `STATUS` | 单据状态 | 下拉框选项 | `STATUS` | `nds.web.alert.LimitValueAlerter` | `0010111111` | `1` |
| `ISACTIVE` | 可用 | 下拉框选项 | `YESNO` | `nds.web.alert.LimitValueAlerter` | `0010111111` | `Y` |
| 提交时间 | 提交时间,常用字段名 `STATUSTIME` | 按目标表单配置核实 | 不适用 | 按实际配置核实 | 按实际配置核实 | 新增草稿时不赋值,由提交动作维护 |
| 提交人 | 提交人,常用字段名 `STATUSERID` | 按目标表单配置核实 | 不适用 | 按实际配置核实 | 按实际配置核实 | 新增草稿时不赋值,由提交动作维护 |
- `DOCNO` 必须维护单据编号生成器:`AD_COLUMN` 中该字段的 `SEQUENCENAME` 保存取号 CODE,CODE 的定义在 `AD_SEQUENCE`,取号表达式为 `Get_SequenceNo('', AD_CLIENT_ID)`。生成器 CODE 按业务维护,不猜测具体名称,也不通过查询通道调用取号函数。
- `STATUS` 和 `ISACTIVE` 的字段翻译器配置位于 `AD_COLUMN`,值为 `nds.web.alert.LimitValueAlerter`。`ISACTIVE` 除选项名称为 `YESNO`、默认值为 `Y` 外,其余上述配置与 `STATUS` 相同;保留最小建表模板中的 `ISACTIVE CHAR(1) DEFAULT 'Y' NOT NULL`。
- 下拉框选项名称 `STATUS`、`YESNO` 是对应选项组名称,不是数据库实际值。生成具体元数据方案时,先定位目标环境的选项组,再用 `AD_COLUMN.AD_LIMITVALUE_GROUP_ID` 核实 `AD_LIMITVALUE` 的显示值与实际值,不猜测选项组 ID。读写方式为下拉框选项时,按目标环境核实 `OBTAINMANNER='select'` 等实际存储值。
- 所在表的读写规则默认是 `AD_TABLE.MASK='MDQSV'`,按该字符串维护:`M` 修改、`D` 删除、`Q` 查询、`S` 提交、`V` 作废。此默认值用于新建业务单据方案;分析既有表时仍以实际 `MASK` 为准。
- 表级读写规则 `MDQSV` 与字段级读写打印规则 `0010111111` 是不同配置。字段规则保留完整十位字符串及前导零,不转成整数,也不凭经验解释各位含义。
- 需要提交的业务单据必须包含提交时间和提交人,并核实 `AD_TABLE.PROC_SUBMIT` 对应提交逻辑。上述常用字段名、字段类型、关联方式和可空性需按目标环境或用户确认的方案确定;新增草稿只设 `STATUS='1'`,提交时由提交动作维护提交人和时间。
- 生成 BOS 元数据 SQL 时,先确认目标环境 `AD_COLUMN` 中“字段翻译器”“读写方式”“读写打印规则”“默认值”等配置项对应的实际列名,不凭中文标签猜测物理列名。建表 DDL 与表单元数据配置分别说明;这里仅记录默认规则并生成待人工确认的方案,不通过 Skill 查询通道创建表、维护生成器或写入 BOS 元数据。
## 业务单据商品明细的条码新增配置
业务单据的商品明细表有新增功能、需要通过商品新增输入框输入条码录入时,`AD_TABLE.CLASSNAME` 配置为 `nds.schema.AttributeDetailSupportTableImpl`。该实现类在 BOS 中表示商品明细支持这种条码新增输入方式;分析或生成商品明细方案时,应同时核实该明细表的新增功能和 `CLASSNAME`,不把它套用到所有明细表。
商品明细通常包含以下三个维度字段:
| 常用字段 | 业务含义 | 通常关联对象 | 默认配置说明 |
| --- | --- | --- | --- |
| `M_PRODUCT_ID` | 商品 ID / 款号 ID | `M_PRODUCT.ID` | 按目标表单实际配置核实 |
| `M_PRODUCTALIAS_ID` | 条码 ID / SKU ID,用户也可能简称 `m_productalias` | `M_PRODUCT_ALIAS.ID` | 生成 SQL 前确认实际字段名 |
| `M_ATTRIBUTESETINSTANCE_ID` | ASI ID / 色码属性 ID,简称 `asiid` | `M_ATTRIBUTESETINSTANCE.ID` | 字段读写规则一般为 `1100000000`,只在新增时可见 |
- `1100000000` 是 ASI 字段的读写规则,按完整十位字符串保存;业务含义为只在新增时可见,不直接沿用主单据 `DOCNO`、`STATUS`、`ISACTIVE` 的 `0010111111` 规则,也不自行推断其他位含义。
- 商品明细与主单据的关系先通过 `AD_REFBYTABLE` 核实,三个维度字段通过 `AD_COLUMN` 或实际表结构确认;条码字段常用名是 `M_PRODUCTALIAS_ID`,不能只凭用户简称生成不存在的 `M_PRODUCTALIAS` 列。
- 主单据默认 `MASK='MDQSV'` 不表示商品明细自动支持新增;明细的新增动作配置按其实际 `AD_TABLE.MASK` 核实,需要条码新增时再维护上述 `CLASSNAME` 和字段配置。
- 本节是 BOS 元数据和表单行为约定,仅用于分析或生成待人工确认的配置方案,不通过 Skill 查询通道写入 `AD_TABLE`、`AD_COLUMN` 或业务明细。
## 新增业务记录 SQL 生成规则
当用户要求分析或生成新增业务表记录的 SQL 示例时,仍然保持只读安全边界:skill 可以生成 SQL 和说明,但不能直接通过查询通道执行 INSERT、UPDATE、DELETE、MERGE、DDL 等写操作。
生成新增记录 SQL 时遵守以下默认规则:
- 主表或子表新增记录的主键 `ID` 使用 `get_sequences('<表名称>')` 取值。
- 如果目标表存在 `DOCNO` 字段,先查询 `AD_COLUMN` 中该字段是否配置 `SEQUENCENAME` 单据编号生成器。
- 取单号函数为 `Get_SequenceNo('', AD_CLIENT_ID)`。一般情况下,`CODE` 取该单据 `DOCNO` 字段对应的 `AD_COLUMN.SEQUENCENAME` 值,第二个参数取单据实际的 `AD_CLIENT_ID`;这是默认业务约定,特殊业务以目标环境的实际配置和过程逻辑为准。
- `CODE` 的定义在 `AD_SEQUENCE` 表中。`AD_COLUMN.SEQUENCENAME` 是单据字段配置的取号 CODE;要理解编号规则,继续到 `AD_SEQUENCE` 核实该 CODE 对应的定义。先确认目标环境的表结构和字段含义,不凭经验假定关联字段或编号格式。
- 如果 `DOCNO` 对应的 `SEQUENCENAME` 有值,则生成 `Get_SequenceNo('', <单据的 AD_CLIENT_ID>)` 作为单据编号表达式。仅当该单据的 `AD_CLIENT_ID` 确认为 `37` 时,第二个参数才写 `37`;子表使用继承父表的客户 ID。配置为空时不猜测 `CODE`,应继续核实取号逻辑。
- 取号函数可能推进编号状态,即使包装在 `SELECT` 中也不得通过 `query` / `qperm` 调用。这里只生成 SQL 示例,不实际取号。
- 如果目标表存在 `AD_CLIENT_ID` 字段,默认值使用 `37`。
- 如果目标表存在 `AD_ORG_ID` 字段,默认值使用 `27`。
- 子表的 `AD_CLIENT_ID` 和 `AD_ORG_ID` 默认取父表记录中对应字段值,不单独写固定值。
- 新增业务表单时,如果目标表存在 `STATUS`、`STATUSERID`、`STATUSTIME` 字段,通常只给 `STATUS` 赋默认值 `'1'`,不对 `STATUSERID`、`STATUSTIME` 赋值。
- `STATUS='1'` 表示草稿/未提交;提交人、提交时间等字段由提交动作或提交存储过程处理。
- 如果用户明确提到“提交”,通常不是直接把 `STATUS` 改成 `'2'`,而是应先查询 `AD_TABLE.PROC_SUBMIT`,按该表配置的提交存储过程理解提交逻辑。
- 生成提交 SQL 或说明提交流程时,如果已知 `userId`,调用 `AD_TABLE.PROC_SUBMIT` 前需要先更新主单据修改人和修改时间,再调用提交存储过程;修改人、修改时间字段名必须先通过 `AD_COLUMN` 或表结构确认,不要凭经验硬写字段名。
查询 `DOCNO` 编号生成器示例:
```sql
SELECT SEQUENCENAME
FROM AD_COLUMN
WHERE AD_TABLE_ID = (SELECT ID FROM AD_TABLE WHERE NAME = '<表名称>')
AND UPPER(DBNAME) = 'DOCNO'
AND ROWNUM <= 20
```
## 字段值域映射规则(AD_COLUMN / AD_LIMITVALUE)
当用户要求解释字段含义、生成查询条件、分析业务类型,或生成新增业务记录 SQL 示例时,如果目标字段在 `AD_COLUMN` 中的 `OBTAINMANNER` 值为 `select`,必须继续通过 `AD_LIMITVALUE_GROUP_ID` 查询 `AD_LIMITVALUE`,拿到显示值与数据库实际值的映射关系。
关键规则:
- `AD_COLUMN.OBTAINMANNER = 'select'` 表示该字段是受限值列表。
- `AD_COLUMN.AD_LIMITVALUE_GROUP_ID` 关联 `AD_LIMITVALUE.AD_LIMITVALUE_GROUP_ID`。
- 用户通常说的是显示值,例如“券核销”。
- SQL 查询条件和新增记录 SQL 必须使用数据库实际值,例如 `VOU_USED`。
- 不要把显示值直接写入业务表字段,除非 `AD_LIMITVALUE` 查询结果证明显示值就是实际值。
示例:`XH_ORDER_FTP.BILLTYPE` 字段,当显示值为“券核销”时,对应的数据库实际值是 `VOU_USED`。因此用户说“类型为券核销”时,应生成:
```sql
XH_ORDER_FTP.BILLTYPE = 'VOU_USED'
```
查询字段值域映射模板:
```sql
SELECT c.DBNAME,
c.NAME,
c.OBTAINMANNER,
c.AD_LIMITVALUE_GROUP_ID,
v.VALUE,
v.NAME AS DISPLAY_NAME
FROM AD_COLUMN c
LEFT JOIN AD_LIMITVALUE v ON v.AD_LIMITVALUE_GROUP_ID = c.AD_LIMITVALUE_GROUP_ID
WHERE c.AD_TABLE_ID = (SELECT ID FROM AD_TABLE WHERE NAME = '<表名称>')
AND UPPER(c.DBNAME) = UPPER('<字段名>')
ORDER BY v.ORDERNO, v.ID
```
使用时先查字段:
```sql
SELECT ID, DBNAME, NAME, DESCRIPTION, OBTAINMANNER, AD_LIMITVALUE_GROUP_ID
FROM AD_COLUMN
WHERE AD_TABLE_ID = (SELECT ID FROM AD_TABLE WHERE NAME = 'XH_ORDER_FTP')
AND UPPER(DBNAME) = 'BILLTYPE'
```
如果 `OBTAINMANNER='select'` 且 `AD_LIMITVALUE_GROUP_ID` 有值,再查:
```sql
SELECT VALUE, NAME AS DISPLAY_NAME
FROM AD_LIMITVALUE
WHERE AD_LIMITVALUE_GROUP_ID =
ORDER BY ORDERNO, ID
```