UNION要求各SELECT字段数、顺序、类型严格一致,否则MySQL直接报错1222;默认去重且按首列升序排序,去重粒度为整行二进制比较,空格或NULL/空字符串差异会导致失效。

UNION 查询在 phpMyAdmin 中默认去重,但必须满足字段数、顺序、类型一致,否则直接报错 —— 这是多数人卡住的第一步。
phpMyAdmin 执行 UNION 时字段不匹配就报错
phpMyAdmin 只是 MySQL 的图形界面,底层仍走原生 SQL。一旦 UNION 的两个 SELECT 字段数量不同,或同位置字段类型强冲突(比如 VARCHAR 和 INT),MySQL 会立刻报错,phpMyAdmin 显示类似:
ERROR 1222 (21000): The used SELECT statements have a different number of columns
常见踩坑点:
- 漏写
AS统一别名,导致字段语义混乱(如SELECT id FROM a和SELECT user_id AS id FROM b才合法) - 用
*混搭显式字段:SELECT * FROM t1 UNION SELECT id,name FROM t2→ 必报错 - TEXT 和 VARCHAR(255) 在某些 MySQL 版本中会被判为“类型不兼容”,建议显式转成相同类型,如都用
CAST(col AS CHAR)
怎么确认 UNION 真的去重了?
UNION 去重是对整行生效,不是单字段。你在 phpMyAdmin 的 SQL 标签页里执行完,看结果行数是否少于两段查询行数之和,是最直接验证方式。
立即学习“PHP免费学习笔记(深入)”;
更稳妥的做法是加个辅助列暴露重复逻辑:
SELECT 'a' AS src, id, name FROM user_0<br>UNION<br>SELECT 'b' AS src, id, name FROM user_1;
如果某 id+name 组合在结果里只出现一次,说明去重成功;若看到同一 id 对应两个 src 值,则说明该行被去掉了其中一个 —— 这正是 UNION 的行为。
注意:UNION 默认还会按第一列升序排序,所以结果顺序不能反推是否去重,得靠行数或带源标识的测试。
想查“按某字段去重,留最新一条”怎么办?
UNION 本身做不到这个。它只认整行相等,不认业务逻辑。比如你从两个分表查用户数据,希望每个 user_id 只留 create_time 最大的那条,UNION + DISTINCT 完全无效。
必须换思路:
- 先
UNION ALL合并(避免去重干扰),再套一层子查询 +GROUP BY user_id+MAX(create_time) - 或者用窗口函数(MySQL 8.0+):
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY create_time DESC),然后外层WHERE rn = 1 - phpMyAdmin 不支持保存临时表,所以这类逻辑必须写成单条可执行 SQL,不能分步建表
UNION ALL 在 phpMyAdmin 里更快但结果不可信?
是的。UNION ALL 不去重、不排序,执行快,但结果里可能有大量重复行 —— 尤其当两个子查询本来就有交集时。很多人误以为“反正我后面 PHP 再去重”,但数据库层没控制好,容易把错误数据带出来。
关键判断点:
- 如果你能 100% 确保两段数据无交集(比如按时间/分片 ID 严格隔离),用
UNION ALL更安全高效 - 如果只是“大概率没重复”,请老实用
UNION,别省那点性能 - phpMyAdmin 的“影响行数”不显示去重掉多少行,只能靠人工比对原始查询结果
真正容易被忽略的是:UNION 的去重粒度是“整行二进制比较”,哪怕一个字段末尾多一个空格、NULL 和空字符串混用,都会导致去重失效。线上查问题时,先 TRIM() 和 IFNULL() 处理再 union,比事后调试强得多。



















