视图中用union all合并两系统客户表时,字段名、数量、顺序、类型必须严格对齐,否则报错;需显式指定列、补null、统一别名、转换类型,并加来源标识区分系统。

视图里用 UNION ALL 合并两个系统客户表时,字段必须严格对齐
直接写 SELECT * FROM sys_a_customers UNION ALL SELECT * FROM sys_b_customers 几乎一定会报错——两表字段名、数量、顺序、类型不一致。SQL 视图要求 UNION 或 UNION ALL 的每个子查询返回完全兼容的列结构。
实操建议:
- 先分别查出两表的字段名和类型:
DESCRIBE sys_a_customers和DESCRIBE sys_b_customers(MySQL)或用INFORMATION_SCHEMA.COLUMNS(标准 SQL) - 手动映射关键业务字段:比如
sys_a用cust_id,sys_b用customer_code,在视图中统一别名为customer_id - 缺失字段补
NULL或默认值:如sys_a没有source_system字段,就显式写'SYS_A' AS source_system - 字符串长度差异大时(如
VARCHAR(20)vsVARCHAR(100)),建议用更宽的类型显式转换,避免隐式截断
处理主键冲突:同一客户在两个系统中 ID 不同但实际是同一个人
视图本身不解决语义重复,只做数据拼接。如果 sys_a 的 cust_id = 'A001' 和 sys_b 的 customer_code = 'B007' 实际指向张三,视图会当成两条独立记录返回——这是常见误解点。
实操建议:
- 不要指望视图自动去重;如需合并逻辑,得先建一个映射表(如
customer_merge_map),再用LEFT JOIN关联进来 - 若仅用于报表展示且允许“疑似重复”,可在视图中加来源标识字段:
'SYS_A' AS system_source,方便下游识别 - 警惕
UNION(去重)的性能开销:它会触发排序+比较,数据量大时比UNION ALL慢数倍,而多数主数据合并场景本就不该依赖数据库去重
字段类型不兼容导致创建视图失败的具体表现
常见错误信息如:ERROR 1222 (21000): The used SELECT statements have a different number of columns 或 Operand should contain 1 column(s),本质都是列对齐失败。
典型不兼容场景:
-
sys_a.phone是VARCHAR(20),sys_b.mobile是BIGINT→ 必须显式转成字符串:CAST(mobile AS CHAR) -
sys_a.created_at是DATETIME,sys_b.create_time是TIMESTAMP→ 多数数据库可隐式兼容,但 PostgreSQL 会报错,需统一用TO_TIMESTAMP()或CAST(... AS TIMESTAMP) -
sys_a.status是枚举(ENUM('active','inactive')),sys_b.state是整数 → 必须映射:CASE state WHEN 1 THEN 'active' ELSE 'inactive' END AS status
要不要在视图里加 WHERE 条件过滤无效客户?
可以加,但要注意:视图定义中的 WHERE 是静态的,无法参数化。例如写死 WHERE status != 'deleted' 没问题;但想让调用方传入时间范围,就得用物化视图(Oracle/PG)或改用函数封装(PostgreSQL CREATE FUNCTION 返回 SETOF)。
实操建议:
- 基础清洗建议放在视图内:剔除空姓名、空手机号(
WHERE name IS NOT NULL AND TRIM(name) != '') - 避免在视图里写复杂子查询或关联其他大表,否则每次查询都执行,拖慢所有依赖该视图的应用
- 如果两个系统都有软删除标记(如
is_deleted = 0),视图里统一过滤比让每个业务 SQL 自己加更可靠
真正难的不是写这个视图,而是确认哪些字段算“同一含义”、哪些值需要标准化(比如地址里的“北京市”和“北京”)、以及下游系统是否能接受视图返回的混合来源数据——这些不在 SQL 语法里,但在上线前必须对齐。










