← 返回 浏览器全选正文可复制到微信公众号;图片为公网链接。

ActionTran:数量对齐 + 规则必兑现 + Java/Groovy 同构

李福春 · 2026-07-21
图片 0 · Mermaid 0 · _shared/721-action-tran-rules

修订自 2026-07-20-action-tran-count-align-extract-design.md。补强:detect 命中的可自动改写规则必须真正改写;Java 与平台 Groovy 行为一致;以真实 meta / 样例做逐条校验。

项 路径
权威实现 20260719/gr/src/main/java/com/qvsu/actiontran/ActionTranRunApi.java
规则目录 20260719/gr/src/main/resources/rules/auto-rules.json(与 pgjr.md Action SQL 子集)
平台脚本 20260719/gr/examples/ActionTranRun.groovy(必须与 Java 同逻辑)
手册 20260719/pgjr.md

1. 成功标准

  1. 数量:meta(COC, DB+CUS, s_is_del=1) = scanned = upserted(空 body / 抽不出 SQL 仍 upsert,need_update=0)。
  2. 改写兑现:对「可自动改写」规则,若 from/unit 命中 detect,则 to 必须完成对应转换(不得仅进 match_rule 而正文不变)。
  3. 同构:同一输入下,Java applyRules / extractSql 与 Groovy 对应方法结果一致(单测 + 共享样例)。

2. GROUP_CONCAT 根因(已核实)

现象 原因
match_rule 有 GROUP_CONCAT,to 仍含 GROUP_CONCAT detect=GROUP_CONCAT\s*( 易命中;rewrite.pattern 要求 SEPARATOR '…' 且 ([^)]+?)
嵌套函数 GROUP_CONCAT(IFNULL(a,''), …) 在第一个 ) 处截断,整段不匹配
手册形态 GROUP_CONCAT(x ORDER BY y SEPARATOR ',') → STRING_AGG(x, ',' ORDER BY y);现替换会把 ORDER BY 留在错误位置
无 SEPARATOR MySQL 默认逗号;当前正则直接不改

修复:内置 rewriteGroupConcat(平衡括号解析,对齐 pgjr.md 规则 21),规则 21 的 JSON rewrite 改为 annotate(目录仍可 detect;真改写走结晶方法,与 FOUND_ROWS/LIKE 同类)。

覆盖:


3. 其它行为(沿用上版)


4. Java ↔ Groovy 同构

能力 Java Groovy
extractSql 线性扫描 ✓ 必须同算法
applyRules + 结晶(GROUP_CONCAT/FOUND_ROWS/LIKE/…) ✓ 必须同调用顺序
空 units upsert ✓ ✓
规则 JSON classpath auto-rules.json 内嵌 EMBEDDED_RULES_JSON 与 json 同内容(改规则时两端一起改)

权威源:Java。改完后 diff 关键路径 / 用同一组 fixture 断言两侧输出一致(Groovy 侧以脚本自检或文档化手工对照清单;工程内以 Java 单测锁行为,Groovy 同步粘贴)。


5. 校验(业务准确性)

  1. 单测:pgjr.md 规则 21 样例 + 嵌套 IFNULL + 无 SEPARATOR + DISTINCT。
  2. 脚本 scripts/validate_rule_rewrites.py(MySQL 可用时):扫 qvsu_meta_action,对每条 body 调用与 Java 同构的检查逻辑,或跑完 /run 后查 qvsu_action_tran:
    from 含 GROUP_CONCAT( 且非纯注释 → to 不得再含未改写的 GROUP_CONCAT((允许注释残留则先剥注释再判)。
  3. 数量:compare_meta_tran.py → match: YES。

6. 改动文件

不做:改 apply 回写;扩到 DDL 规则。


7. 规则改写对照(COC 实库 2410 条)

在线页:https://public.joysky.cloud/721-action-tran-rules/

唯一 key:{app_name_en}|{plugin_type}|{action_name_en},对应表 qvsu_action_tran 唯一约束 uk_app_plugin_action。关联验证示例:

sql SELECT * FROM qvsu_action_tran WHERE app_name_en='COC' AND plugin_type='DB' AND action_name_en='Mysql7';

生成:python scripts/extract_real_rule_examples.py --out …

7.1 规则 ↔ 实库脚本唯一 key 总表

unique_key = {app_name_en}|{plugin_type}|{action_name_en}(= uk_app_plugin_action)

规则ID 类别 标题 rewrite unique_key need_update
1 标识符与字面量 标识符引用 regex COC|CUS|Groovy54 1
2 标识符与字面量 字符串引号 regex COC|CUS|Groovy61 1
3 标识符与字面量 大小写比较 annotate COC|DB|Mysql1228Copy3Copy1Copy1Copy1 1
4 标识符与字面量 LIKE / ILIKE crystallize+regex COC|DB|Mysql1228Copy3Copy1Copy1Copy1 1
5 标识符与字面量 注释 regex COC|DB|MysqlPlus41 1
6 标识符与字面量 布尔比较 annotate COC|DB|Mysql888_20687 1
7 标识符与字面量 空串与 NULL regex COC|CUS|Groovy61 1
8 标识符与字面量 库名.表名 regex (本批未命中)
9 标识符与字面量 零日期 regex COC|DB|Mysql893_5b7fa 1
10 分页与排序 LIMIT offset,count regex COC|DB|Mysql555 0
11 分页与排序 FETCH FIRST annotate (本批未命中)
12 分页与排序 随机排序 regex (本批未命中)
13 分页与排序 FORCE INDEX remove (本批未命中)
14 条件与逻辑函数 IFNULL regex COC|CUS|Groovy61 1
15 条件与逻辑函数 IF() template COC|DB|Mysql1290 1
16 条件与逻辑函数 CASE annotate COC|DB|Mysql1290 1
17 条件与逻辑函数 空安全等于 regex (本批未命中)
18 条件与逻辑函数 XOR regex (本批未命中)
19 条件与逻辑函数 布尔转 0/1 annotate COC|DB|Mysql1223Copy2Copy1Copy1Copy1Copy1 1
20 字符串函数 CONCAT / 与 NULL annotate
21 字符串函数 GROUP_CONCAT crystallize+annotate COC|DB|Mysql1378Copy1Copy1 1
22 字符串函数 FIND_IN_SET regex (本批未命中)
23 字符串函数 SUBSTRING_INDEX regex (本批未命中)
24 字符串函数 LOCATE regex (本批未命中)
25 字符串函数 LENGTH / CHAR_LENGTH annotate COC|DB|Mysql1179 0
26 字符串函数 正则 regex (本批未命中)
27 字符串函数 CAST UNSIGNED regex (本批未命中)
28 字符串函数 CONVERT → CAST regex (本批未命中)
29 字符串函数 UUID regex (本批未命中)
30 日期时间函数 NOW regex (本批未命中)
31 日期时间函数 DATE_FORMAT regex COC|DB|Mysql1223Copy2Copy1Copy1Copy1 1
32 日期时间函数 STR_TO_DATE regex COC|DB|Mysql220Copy1Copy1 0
33 日期时间函数 UNIX_TIMESTAMP regex (本批未命中)
34 日期时间函数 FROM_UNIXTIME regex (本批未命中)
35 日期时间函数 DATE_ADD regex COC|DB|Mysql1290 1
36 日期时间函数 DATEDIFF regex (本批未命中)
37 日期时间函数 DATE() regex COC|DB|Mysql95_bc2ecCopy1Copy1Copy1Copy1Copy1Copy1 0
38 日期时间函数 YEAR/MONTH regex COC|DB|Mysql1290Copy1Copy1Copy1Copy1Copy1Copy1 1
39 日期时间函数 CURDATE regex (本批未命中)
40 JSON JSON path annotate COC|DB|Mysql1101 1
41 DML ON DUPLICATE KEY annotate COC|DB|MysqlPlus41 1
42 DML new_row 别名 regex (本批未命中)
43 DML INSERT IGNORE annotate COC|DB|Mysql1114 0
44 DML REPLACE INTO annotate (本批未命中)
45 DML UPDATE JOIN annotate COC|DB|receptionMedicalDiseaseEntryU 0
46 DML DELETE JOIN annotate (本批未命中)
47 DML 多表 DELETE annotate (本批未命中)
48 DML 取自增 ID annotate (本批未命中)
49 查询语义与事务 松散 GROUP BY annotate COC|DB|Mysql1290Copy1Copy1Copy1Copy1 1
50 查询语义与事务 隐式类型转换 regex (本批未命中)
51 查询语义与事务 除法 annotate COC|DB|Mysql1371 1
52 查询语义与事务 ROUND 需 numeric regex COC|DB|Mysql1007 1
53 查询语义与事务 事务中止 25P02 annotate (本批未命中)
54 查询语义与事务 smallint = boolean annotate COC|DB|Mysql1056 0
C1 结晶 SQL_CALC_FOUND_ROWS / FOUND_ROWS crystallize (本批未命中)
C2 结晶 JSON_OBJECTAGG crystallize (本批未命中)

有样例 29 / 未命中 27(COC 2410 条覆盖)。

7.2 按规则的改前 / 改后截取

规则 1 · 标识符引用(regex)

改前(截取)

…re.toolkit.StringUtils.sqlArgsFill("INSERT INTO `mn_daily_order` " +
                    "(`order_id`, `client_id`,`account_id`, `treatment_type`, `order_all_money`, `order_actual_money`, `order_collection_money`, " +
                    "`order_time`, `status`, `salesman`, `optometrist`, `make_single`, `order_remark`, `tracking_number`, " +
                    "`col…

改后(截取)

…re.toolkit.StringUtils.sqlArgsFill("INSERT INTO mn_daily_order " +
                    "(`order_id`, `client_id`,`account_id`, `treatment_type`, `order_all_money`, `order_actual_money`, `order_collection_money`, " +
                    "`order_time`, `status`, `salesman`, `optometrist`, `make_single`, `order_remark`, `…

规则 2 · 字符串引号(regex)

改前(截取)

…static final String UPLOAD_INIT_DATA_JSON_URL = "/qvsu/files/json/initData/";
    private FileServerInfo fileServerInfo = SpringUtils.getBean(FileServerInfo.class);
//    private FileServerService fileServerService = SpringUtils.getBean(FileServerService.class);
//    private AmazonS3 amazonS3 = SpringUtils.getBean(AmazonS3.class)
    Object groovy(HashMap<String, Object> actionMap, HashMap<St…

改后(截取)

…appVersion ,pro,file_visit_url as fileVisitUrl,COALESCE(use_file_visit,'0') as useFileVisit  from qvsu_run_app " +
                "where s_is_del=1 and app_name_en ={0}  order by  appVersion+0  DESC  limit 1", appNameEn);
        if (map == null || map.size() == 0) {
            return Collections.EMPTY_MAP
        }…

规则 3 · 大小写比较(annotate)

改前(截取)

…ime = '2026-03-31 23:59:59'
    AND t.task_name ILIKE '%二档%'
        AND t.executive_arm IN ({{deptD.text}}) ;

改后(截取)

…ue AS 完成值,
    CONCAT(ROUND(CAST(CAST(CAST(CAST(CAST(t.progress AS numeric AS numeric AS numeric AS numeric AS numeric))))), 2), '%') AS 完成率
FROM mn_task t
LEFT JOIN opt_dept d 
    ON t.executive_arm = d.dept_id 
    AND d.s_is_del = 1
WHERE 
    t.s_is_del = 1 
    AND t.execution_start_time = '2026-01-01 00:00:00'…

规则 4 · LIKE / ILIKE(crystallize+regex)

本批未命中,无 unique_key。

规则 5 · 注释(regex)

改前(截取)

…--{item.commodity_name},--{item.suppliers_name},#{item.suppliers_commodity_name},#{item.suppliers_commodity_id})
</foreach>
ON DUPLICATE KEY UPDATE
s_is_del=1

改后(截取)

…--{item.commodity_name},--{item.suppliers_name},--{item.suppliers_commodity_name},#{item.suppliers_commodity_id})
</foreach>
ON DUPLICATE KEY UPDATE
s_is_del=1

规则 6 · 布尔比较(annotate)

改前(截取)

…mdr1.dept_id = od1.dept_id
         WHERE mue1.is_old_user = 1
           AND mdr1.state IN (2, 4)
           AND (od1.dept_id = ANY(string_to_array('{{deptD.text}}', ','))) ),
        0
    ) AS old_customer_reservation_count,
    -- 老客户挂号人数
    COALESCE(
        (SELECT COUNT(mdr2.user_id) 
         FROM mn_daily_registered mdr2
         JOIN mn_user_extend mue2 ON mdr2.user_id…

改后(截取)

…ELSE CONCAT(ROUND(CAST(CAST(CAST(CAST(CAST((
                SELECT COUNT(mue5.user_id AS numeric AS numeric AS numeric AS numeric AS numeric)))))) 
                FROM mn_user_extend mue5
                JOIN mn_daily_order mdo5 ON mue5.user_id = mdo5.client_id
                JOIN opt_dept od5 ON mdo5.outp…

规则 7 · 空串与 NULL(regex)

改前(截取)

…appVersion ,pro,file_visit_url as fileVisitUrl,IFNULL (use_file_visit,'0') as useFileVisit  from qvsu_run_app " +
                "where s_is_del=1 and app_name_en ={0}  order by  appVersion+0  DESC  limit 1", appNameEn);
        if (map == null || map.size() == 0) {
            return Collections.EMPTY_MAP
        }
        String resSql = com.baomidou.mybatisplus.core.to…

改后(截取)

…appVersion ,pro,file_visit_url as fileVisitUrl,COALESCE(use_file_visit,'0') as useFileVisit  from qvsu_run_app " +
                "where s_is_del=1 and app_name_en ={0}  order by  appVersion+0  DESC  limit 1", appNameEn);
        if (map == null || map.size() == 0) {
            return Collections.EMPTY_MAP
        }…

规则 8 · 库名.表名(regex)

本批未命中,无 unique_key。

规则 9 · 零日期(regex)

改前(截取)

…AND (mue.first_cc_time > '{{time.value[0]||'0000-00-00'}}' - INTERVAL 30 DAY OR mue.first_cc_time IS NULL)
    AND (
             (DATE(mdo.order_time) between COALESCE( '{{time.value[0]||'0000-00-00'}}', '0000-00-00')  and COALESCE( '{{time.value[1]||'9999-12-31'}}', '9999-12-31'))
        OR
             (DATE(mdo.order_time) between COALESCE( '{{time.value[0]||'0000-00-00'}}', '0000-00-…

改后(截取)

…'
        ELSE CONCAT(ROUND(CAST(CAST(CAST(CAST(CAST(SUM(CASE WHEN EXTRACT(YEAR FROM mdo.order_time AS numeric AS numeric AS numeric AS numeric AS numeric)))))) = EXTRACT(YEAR FROM CURRENT_DATE) THEN mdo.order_actual_money ELSE 0 END) / 
            (SELECT SUM(order_actual_money) FROM mn_daily_order WHERE status = '3'…

规则 10 · LIMIT offset,count(regex)

本批未命中,无 unique_key。

规则 11 · FETCH FIRST(annotate)

本批未命中,无 unique_key。

规则 12 · 随机排序(regex)

本批未命中,无 unique_key。

规则 13 · FORCE INDEX(remove)

本批未命中,无 unique_key。

规则 14 · IFNULL(regex)

改前(截取)

…appVersion ,pro,file_visit_url as fileVisitUrl,IFNULL (use_file_visit,'0') as useFileVisit  from qvsu_run_app " +
                "where s_is_del=1 and app_name_en ={0}  order by  appVersion+0  DESC  limit 1", appNameEn);
        if (map == null || map.size() == 0) {
            return Collections.EMPTY_MAP
        }
        String resSql = com.baomidou.mybatisplus.core.to…

改后(截取)

…appVersion ,pro,file_visit_url as fileVisitUrl,COALESCE(use_file_visit,'0') as useFileVisit  from qvsu_run_app " +
                "where s_is_del=1 and app_name_en ={0}  order by  appVersion+0  DESC  limit 1", appNameEn);
        if (map == null || map.size() == 0) {
            return Collections.EMPTY_MAP
        }…

规则 15 · IF()(template)

本批未命中,无 unique_key。

规则 16 · CASE(annotate)

改前(截取)

…S 本周开始时间,
  MAX(dr.end_time) AS 本周结束时间,
  COUNT(CASE WHEN status = '1' THEN follow_id END) AS 已完成随访数,
  COUNT(CASE WHEN status IN ('0','1','3') THEN follow_id END) AS 应回访总数,
  CONCAT(ROUND(CAST(CAST(CAST(CAST(COUNT(CASE WHEN status = '1' THEN follow_id END AS numeric AS numeric AS numeric AS numeric)))))
    /
    NULLIF(COUNT(CASE WHEN status IN ('0','1','3') THEN foll…

改后(截取)

…) AS 应回访总数,
  CONCAT(ROUND(CAST(CAST(CAST(CAST(CAST(COUNT(CASE WHEN status = '1' THEN follow_id END AS numeric AS numeric AS numeric AS numeric AS numeric))))))
    /
    NULLIF(COUNT(CASE WHEN status IN ('0','1','3') THEN follow_id END), 0)
  * 100, 2), '') AS 随访完成率
FROM mn_member_follow_tickets
CROSS JOIN date_ranges…

规则 17 · 空安全等于(regex)

本批未命中,无 unique_key。

规则 18 · XOR(regex)

本批未命中,无 unique_key。

规则 19 · 布尔转 0/1(annotate)

改前(截取)

…meric AS numeric AS numeric AS numeric))))) = 1 THEN 1 END), 0), 0) AS 一月,
  ROUND(CAST(CAST(CAST(CAST(COALESCE(SUM(CASE WHEN MONTH(u.filing_time AS numeric AS numeric AS numeric AS numeric))))) = 2 THEN 1 END), 0), 0) AS 二月,
  ROUND(CAST(CAST(CAST(CAST(COALESCE(SUM(CASE WHEN MONTH(u.filing_time AS numeric AS numeric AS numeric AS numeric))))) = 3 THEN 1 END), 0), 0) AS 三…

改后(截取)

SELECT
  ROUND(CAST(CAST(CAST(CAST(CAST(COALESCE(SUM(CASE WHEN MONTH(u.filing_time AS numeric AS numeric AS numeric AS numeric AS numeric)))))) = 1 THEN 1 END), 0), 0) AS 一月,
  ROUND(CAST(CAST(CAST(CAST(CAST(COALESCE(SUM(CASE WHEN MONTH(u.filing_time AS numeric AS numeric AS numeric AS numeric AS numeric)))))) = 2 THEN…

规则 20 · CONCAT / || 与 NULL(annotate)

改前(截取)

…TE mn_project_management
SET project_progress = CONCAT(
    ROUND(CAST(CAST(CAST(CAST((project_endSteps / progress_total AS numeric AS numeric AS numeric AS numeric))))) * 100, 
        2
    ), 
    '%'
)
WHERE s_is_del = '1'
AND mn_project_management.project_no = {{Table2.triggeredRow.project_no}}

改后(截取)

…rogress = CONCAT(
    ROUND(CAST(CAST(CAST(CAST(CAST((project_endSteps / progress_total AS numeric AS numeric AS numeric AS numeric AS numeric)))))) * 100, 
        2
    ), 
    '%'
)
WHERE s_is_del = '1'
AND mn_project_management.project_no = {{Table2.triggeredRow.project_no}}

规则 21 · GROUP_CONCAT(crystallize+annotate)

改前(截取)

SELECT 
    (SELECT CONCAT(''', GROUP_CONCAT(name SEPARATOR '', ''), ''')
     FROM (
         SELECT '客户转介绍' AS name UNION ALL
         SELECT '线上拓展' UNION ALL
         SELECT '线下拓展' UNION ALL
         SELECT '自然门诊' UNION ALL
         SELECT '内部引流'
         UNION ALL
         SELECT dict_data_name AS name
         FROM opt_dict_data
         WHERE dict_type_no =…

改后(截取)

SELECT 
    (SELECT CONCAT(''', STRING_AGG(name SEPARATOR '', '', ','), ''')
     FROM (
         SELECT '客户转介绍' AS name UNION ALL
         SELECT '线上拓展' UNION ALL
         SELECT '线下拓展' UNION ALL
         SELECT '自然门诊' UNION ALL
         SELECT '内部引流'
         UNION ALL
         SELECT dict_data_name AS name…

规则 22 · FIND_IN_SET(regex)

本批未命中,无 unique_key。

规则 23 · SUBSTRING_INDEX(regex)

本批未命中,无 unique_key。

规则 24 · LOCATE(regex)

本批未命中,无 unique_key。

规则 25 · LENGTH / CHAR_LENGTH(annotate)

改前(截取)

…WHERE s_is_del = 1
ORDER BY 
  CASE 
    WHEN LENGTH(category_code) = 1 THEN 1  -- 一级分类
    WHEN LENGTH(category_code) = 2 THEN 2  -- 二级分类
    WHEN LENGTH(category_code) = 4 THEN 3  -- 三级分类
  END ASC, 
  category_code ASC;

-- 按照商品分类SQL的格式(按特定类别置顶排序)
SELECT category_code, category_name, parent_id
FROM mn_asset_category 
WHERE s_is_del = 1
ORDER BY 
  CASE 
    WHEN categ…

改后(截取)

…WHERE s_is_del = 1
ORDER BY 
  CASE 
    WHEN LENGTH(category_code) = 1 THEN 1  -- 一级分类
    WHEN LENGTH(category_code) = 2 THEN 2  -- 二级分类
    WHEN LENGTH(category_code) = 4 THEN 3  -- 三级分类
  END ASC, 
  category_code ASC;

-- 按照商品分类SQL的格式(按特定类别置顶排序)
SELECT category_code, category_name, parent_id
FROM mn_asset_category 
WHERE s_is_del = 1
ORDER BY 
  CASE 
    WHEN categ…

(annotate 或未改写:from=to)

规则 26 · 正则(regex)

本批未命中,无 unique_key。

规则 27 · CAST UNSIGNED(regex)

本批未命中,无 unique_key。

规则 28 · CONVERT → CAST(regex)

本批未命中,无 unique_key。

规则 29 · UUID(regex)

本批未命中,无 unique_key。

规则 30 · NOW(regex)

本批未命中,无 unique_key。

规则 31 · DATE_FORMAT(regex)

改前(截取)

…nt_visit_detail
    WHERE
        order_time >= DATE_FORMAT(DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR), '%Y-01-01')
        AND order_time < DATE_FORMAT(CURRENT_DATE, '%Y-01-01')
        AND status IN ('3', '4', '5')
        AND actual_pay_money IS NOT NULL
        AND user_id IS NOT NULL
        AND level2_category IN ('385', '26', '24', '22', '200', '139', '1000', '656', '370',…

改后(截取)

SELECT
  ROUND(CAST(CAST(CAST(CAST(CAST(COALESCE(SUM(CASE WHEN mth = 1 THEN net_amount END AS numeric AS numeric AS numeric AS numeric AS numeric)))))), 0)
    / NULLIF(COUNT(DISTINCT CASE WHEN mth = 1 THEN user_id END), 0),
    2
  ) AS 一月,
  ROUND(CAST(CAST(CAST(CAST(CAST(COALESCE(SUM(CASE WHEN mth = 2 THEN net_amoun…

规则 32 · STR_TO_DATE(regex)

本批未命中,无 unique_key。

规则 33 · UNIX_TIMESTAMP(regex)

本批未命中,无 unique_key。

规则 34 · FROM_UNIXTIME(regex)

本批未命中,无 unique_key。

规则 35 · DATE_ADD(regex)

改前(截取)

…TE) DAY) AS DATETIME) AS start_time,
    CONCAT(DATE_ADD(DATE_SUB(CURRENT_DATE, INTERVAL WEEKDAY(CURRENT_DATE) DAY), INTERVAL 6 DAY), ' 23:59:59') AS end_time
)
SELECT
  MAX(dr.start_time) AS 本周开始时间,
  MAX(dr.end_time) AS 本周结束时间,
  COUNT(CASE WHEN status = '1' THEN follow_id END) AS 已完成随访数,
  COUNT(CASE WHEN status IN ('0','1','3') THEN follow_id END) AS 应回访总数,
  CONCAT(ROUN…

改后(截取)

…) AS 应回访总数,
  CONCAT(ROUND(CAST(CAST(CAST(CAST(CAST(COUNT(CASE WHEN status = '1' THEN follow_id END AS numeric AS numeric AS numeric AS numeric AS numeric))))))
    /
    NULLIF(COUNT(CASE WHEN status IN ('0','1','3') THEN follow_id END), 0)
  * 100, 2), '') AS 随访完成率
FROM mn_member_follow_tickets
CROSS JOIN date_ranges…

规则 36 · DATEDIFF(regex)

本批未命中,无 unique_key。

规则 37 · DATE()(regex)

本批未命中,无 unique_key。

规则 38 · YEAR/MONTH(regex)

改前(截取)

…12
),
monthly_register AS (
    SELECT
        MONTH(registered_time) AS month_num,
        COUNT(DISTINCT user_id) AS total_num
    FROM mn_daily_registered
    WHERE
        stores IN ({{deptD.text}})
        AND s_is_del = 1
        AND status IN ('1','3')
        AND EXTRACT(YEAR FROM registered_time) = EXTRACT(YEAR FROM CURRENT_DATE)
    GROUP BY MONTH(registered_ti…

改后(截取)

…CONCAT(
        ROUND(CAST(CAST(CAST(CAST(CAST(COALESCE(a.arrived_num AS numeric AS numeric AS numeric AS numeric AS numeric))))), 0) / NULLIF(COALESCE(r.total_num, 0), 0) * 100,
            2
        ),
        ''
    ) AS 月小程序到诊率
FROM months m
LEFT JOIN monthly_register r ON m.month_num = r.month_num
LEFT JOIN m…

规则 39 · CURDATE(regex)

本批未命中,无 unique_key。

规则 40 · JSON path(annotate)

改前(截取)

…lass = 'A' 
                   AND JSON_UNQUOTE(JSON_EXTRACT(c.change_history, '$[last].old_class')) != 'A' 
                   AND JSON_UNQUOTE(JSON_EXTRACT(c.change_history, '$[last].change_reason')) ILIKE '升级%' 
              THEN 1 END) AS A_upgrade_count,

        -- A类降级:当前不是A,最近一次变更从A降级
        COUNT(CASE WHEN c.current_class != 'A' 
                   AND JSON_U…

改后(截取)

…B_count AS C转B数量,
    ROUND(CAST(CAST(CAST(CAST(CAST(cs.C_to_B_count * 100.0 / NULLIF(cc.C_count AS numeric AS numeric AS numeric AS numeric AS numeric))))), 0), 2) AS 一级转化率,
    cs.B_to_A_count AS B转A数量,
    ROUND(CAST(CAST(CAST(CAST(CAST(cs.B_to_A_count * 100.0 / NULLIF(cc.B_count AS numeric AS numeric AS numeric AS…

规则 41 · ON DUPLICATE KEY(annotate)

改前(截取)

…ame},#{item.suppliers_commodity_id})
</foreach>
ON DUPLICATE KEY UPDATE
s_is_del=1

改后(截取)

…--{item.commodity_name},--{item.suppliers_name},--{item.suppliers_commodity_name},#{item.suppliers_commodity_id})
</foreach>
ON DUPLICATE KEY UPDATE
s_is_del=1

规则 42 · new_row 别名(regex)

本批未命中,无 unique_key。

规则 43 · INSERT IGNORE(annotate)

改前(截取)

INSERT IGNORE INTO mn_fixed_assets_in (
  in_order_no,
  in_type,
  in_date,
  in_department_name,
  in_department_id,
  handler_department,
  handler,
  handler_id,
  s_create_time,
  s_create_by,
  remark,
  total_quantity,
  total_amount,
  purchaser,
  purchase_date
)
VALUES
(
  '{{global.store.CURRENT_TRANSFER_ORDER_NO}}',
  '…

改后(截取)

INSERT IGNORE INTO mn_fixed_assets_in (
  in_order_no,
  in_type,
  in_date,
  in_department_name,
  in_department_id,
  handler_department,
  handler,
  handler_id,
  s_create_time,
  s_create_by,
  remark,
  total_quantity,
  total_amount,
  purchaser,
  purchase_date
)
VALUES
(
  '{{global.store.CURRENT_TRANSFER_ORDER_NO}}',
  '…

(annotate 或未改写:from=to)

规则 44 · REPLACE INTO(annotate)

本批未命中,无 unique_key。

规则 45 · UPDATE JOIN(annotate)

改前(截取)

update mn_basis_disease_entry set disease_code={{uDiseaseCode.selectedOptionValues.join(',')}},entry_name={{uEntryName.text}} where entry_code={{Table1.triggeredRow.entry_code}}

改后(截取)

update mn_basis_disease_entry set disease_code={{uDiseaseCode.selectedOptionValues.join(',')}},entry_name={{uEntryName.text}} where entry_code={{Table1.triggeredRow.entry_code}}

(annotate 或未改写:from=to)

规则 46 · DELETE JOIN(annotate)

本批未命中,无 unique_key。

规则 47 · 多表 DELETE(annotate)

本批未命中,无 unique_key。

规则 48 · 取自增 ID(annotate)

本批未命中,无 unique_key。

规则 49 · 松散 GROUP BY(annotate)

改前(截取)

….s_is_del = 1
      AND u.customer_type = 4
    GROUP BY u.user_id
),
lost_customer AS (
    SELECT
        COUNT(DISTINCT user_id) AS lost_num
    FROM customer_last_register
    CROSS JOIN date_ranges dr
    WHERE last_reg_time < dr.two_years_ago
       OR last_reg_time IS NULL
)

SELECT
    dr.two_years_ago AS 流失判定临界时间(精确),
    t.total_num AS 总老客户数,
    l.lost_num AS 流失老…

改后(截取)

…,
    CONCAT(
        ROUND(CAST(CAST(CAST(CAST(CAST(l.lost_num / NULLIF(t.total_num AS numeric AS numeric AS numeric AS numeric AS numeric))))), 0) * 100, 2),
        ''
    ) AS 客户流失率
FROM total_old_customer t
CROSS JOIN lost_customer l
CROSS JOIN date_ranges dr;

规则 50 · 隐式类型转换(regex)

本批未命中,无 unique_key。

规则 51 · 除法(annotate)

改前(截取)

…type_id = mc.commodity_type_id
),
-- 本期挂号人数:到店(1/3)、成交(3/5)
curr_register AS (
    SELECT
        COUNT(DISTINCT CASE WHEN t1.status IN ('1' THEN '3') ELSE  t1.user_id, NULL END) AS arrive_people,
        COUNT(DISTINCT CASE WHEN t1.status IN ('3' THEN '5') ELSE  t1.user_id, NULL END) AS deal_people
    FROM params p
    JOIN mn_daily_registered t1 
        ON t1.s_is…

改后(截取)

…(
    SELECT 
        ROUND(CAST(CAST(CAST(CAST(CAST(revenue / NULLIF(unique_users AS numeric AS numeric AS numeric AS numeric AS numeric))))), 0), 2) AS 本期客单价,
        ROUND(CAST(CAST(CAST(CAST(CAST(revenue_yoy / NULLIF(unique_users_yoy AS numeric AS numeric AS numeric AS numeric AS numeric))))), 0), 2) AS 去年同期客单价…

规则 52 · ROUND 需 numeric(regex)

改前(截取)

…t_management
SET project_progress = CONCAT(
    ROUND(CAST(CAST(CAST(CAST((project_endSteps / progress_total AS numeric AS numeric AS numeric AS numeric))))) * 100, 
        2
    ), 
    '%'
)
WHERE s_is_del = '1'
AND mn_project_management.project_no = {{Table2.triggeredRow.project_no}}

改后(截取)

…rogress = CONCAT(
    ROUND(CAST(CAST(CAST(CAST(CAST((project_endSteps / progress_total AS numeric AS numeric AS numeric AS numeric AS numeric)))))) * 100, 
        2
    ), 
    '%'
)
WHERE s_is_del = '1'
AND mn_project_management.project_no = {{Table2.triggeredRow.project_no}}

规则 53 · 事务中止 25P02(annotate)

本批未命中,无 unique_key。

规则 54 · smallint = boolean(annotate)

改前(截取)

…st/design/COC/actions/queries/Mysql1055?editName=true&showTemplate=true&from=datasources

改后(截取)

…st/design/COC/actions/queries/Mysql1055?editName=true&showTemplate=true&from=datasources

(annotate 或未改写:from=to)

规则 C1 · SQL_CALC_FOUND_ROWS / FOUND_ROWS(crystallize)

本批未命中,无 unique_key。

规则 C2 · JSON_OBJECTAGG(crystallize)

本批未命中,无 unique_key。

复制提示:选中上方正文(含表格与图片)→ 复制 → 粘贴到微信公众号编辑器。 图片为公网链接,部署到 public.joysky.cloud 后可正常显示。