视图仅保存SELECT语句,不移动数据;“无缝合并”是逻辑拼接而非物理合并;UNION ALL拼接需字段严格一致并显式CAST;LEFT JOIN适用于补全快照而非合并;须处理字段语义、NULL含义及底层索引。

视图不能合并物理表,只能统一查询入口
SQL 视图本身不移动、不复制、不删除任何数据,它只是保存一条 SELECT 语句。所谓“无缝合并”,实际是让应用或报表在查一个视图时,自动从当前表和历史表中拉取数据并拼成结果集——不是真把两张表合到一起,而是逻辑上“看起来像一张表”。如果误以为 CREATE VIEW 就能完成归档迁移,会发现原表数据没少、磁盘空间没释放、历史表也没多出一行。
用 UNION ALL 拼接当前与历史数据(注意去重与排序)
最直接的合并方式是用 UNION ALL 把当前表和历史表的字段对齐后堆叠。必须用 UNION ALL 而不是 UNION,否则数据库会额外做去重,性能暴跌且可能误删合法重复记录(比如同一订单号在不同业务线出现两次)。
- 所有
SELECT子句的列数、顺序、类型必须严格一致;类型不兼容时需显式CAST(如CAST(created_at AS DATETIME)) - 时间字段要统一别名(如都叫
event_time),否则ORDER BY会报错 -
ORDER BY只能写在最后一个SELECT后,且只能引用列名或序号,不能跨子查询引用别名 - 示例:
CREATE VIEW unified_orders AS SELECT id, order_no, status, created_at AS event_time, 'current' AS source FROM current_orders WHERE status != 'archived' UNION ALL SELECT id, order_no, status, archived_at AS event_time, 'archive' AS source FROM order_archive;
LEFT JOIN 不适合“合并”,但适合“补全历史快照”
如果你真正想查的是“每个当前订单 + 它最新的归档状态”,那就不是合并,而是关联。这时不能用 UNION,而要用 LEFT JOIN 配合预构建的 latest_archive 视图。常见错误是直接 JOIN 历史表,导致一笔订单匹配出 5 条归档记录,结果行数爆炸。
- 先确保历史表有单调递增或可排序的时间字段(如
archived_at或自增archive_id) - 用窗口函数封装最新归档行:
ROW_NUMBER() OVER (PARTITION BY id ORDER BY archived_at DESC) -
JOIN时必须给同名字段加别名,否则SELECT *直接失败 - 务必用
LEFT JOIN,否则未归档订单会丢失
字段冲突、NULL 处理、性能陷阱必须手动兜底
视图里不会自动处理字段语义差异。比如当前表用 status VARCHAR(20) 存 “shipped”,历史表却存 “SHIPPED” 或 “delivered”,合并后分类统计就错。这些不是语法问题,而是数据契约断裂。
- 字符串标准化:在视图里统一
UPPER(status)或映射表转换 - NULL 值含义要明确:
archived_at IS NULL表示未归档,还是归档失败?视图里应加注释字段如is_archived - 索引无效:视图上建不了索引(除 Oracle 物化视图),加速得靠底层表的
(status, created_at)联合索引 - MySQL 5.7 不支持视图中引用变量或参数,时间范围写死会导致归档脚本每次执行范围漂移
真正的“无缝”不在 SQL 语法里,而在字段定义、状态枚举、时间基准三者是否全局对齐。漏掉任何一个,视图跑得再顺,查出来的数据也是错的。

















