| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- namespace Admin.NET.Plugin.AiDOP.DataPlatform.S0Dim;
- /// <summary>
- /// dim 列的取值方式,决定 <see cref="S0DimSqlBuilder"/> 为该列生成哪种 SQL 表达式。
- /// 除 <see cref="TenantIdColumn"/> 外全部作用于 staging 的 <c>raw_data</c> JSON,
- /// 底层统一走 <see cref="MdpJsonSql"/>(已处理 JSON null → 字符串 'null'、ISO-T 时间、STRICT CAST)。
- /// </summary>
- public enum S0DimValueKind
- {
- /// <summary>取 staging 的物理列 <c>s.tenant_id</c>,不走 raw_data。租户身份的唯一来源。</summary>
- TenantIdColumn,
- /// <summary>可空字符串。</summary>
- Str,
- /// <summary>
- /// 可空整数(SIGNED)。
- ///
- /// <para>🔴 <b>源列若是 MySQL 的 <c>bit(1)</c>,绝不能用本 Kind</b>(2026-09-07 实测):
- /// 对账两侧都走 <c>IFNULL(CAST(expr AS CHAR), 哨兵)</c>,而
- /// <c>CAST(b'1' AS CHAR)</c> 返回的是**裸字节** <c>0x01</c>,
- /// dim 侧的 <c>CAST(1 AS CHAR)</c> 是字符 <c>'1'</c> = <c>0x31</c> —— 两者不等,
- /// 于是 <b>source_chk ≠ dim_chk,每一轮刷新都会被阻断对账打回</b>,
- /// 而数据本身其实是对的,排查时极易怀疑错方向。</para>
- ///
- /// <para>正确做法:<c>bit(1)</c> 用 <see cref="BoolTrue"/>(其 Norm 是双层
- /// <c>CAST(CAST(… AS UNSIGNED) AS CHAR)</c>,能把 bit 正规化成 <c>'1'</c>/<c>'0'</c>)。
- /// 但要先确认该列**不会为 NULL** —— <c>BoolTrue</c> 的可辨识性守卫要求原值
- /// ∈ <c>{1,0,true,false}</c>,NULL 会让整行被过滤、行数对账 FAIL。
- /// 两个条件都不满足时,本阶段的结论是**不物化该列**。</para>
- /// </summary>
- Int,
- /// <summary>可空 DECIMAL(Precision, Scale)。</summary>
- Dec,
- /// <summary>秒级 datetime(源侧微秒被截断,与对账口径一致)。</summary>
- DateTimeSec,
- /// <summary>
- /// 布尔判真,产出 1/0。
- /// ⚠️ <see cref="MdpJsonSql.BoolTrue"/> 会把 JSON null / 无法识别的值**静默判为 0**。
- /// 为杜绝静默失真,<see cref="S0DimSqlBuilder"/> 对本类型**强制追加可辨识性守卫**
- /// (原始值必须是 1/0/true/false 之一),不满足的行被过滤掉 →
- /// 触发 <c>dim_count < stg_count</c> → 对账 FAIL,问题被暴露而非被吞掉。
- /// </summary>
- BoolTrue
- }
|