UNION操作排序规则非法混合错误排查:SQL语句问题咨询
解决UNION操作的排序规则冲突问题
这个错误Illegal mix of collations for operation 'UNION'本质是因为你用UNION合并的两个查询结果里,对应位置的列使用了不同的字符排序规则(collation)。UNION操作要求两个结果集的对应列不仅数据类型要一致,连字符排序规则也得完全匹配才行。
先看你的SQL语句:
SELECT a.paid, a.total, a.remain, a.date, a.patient_id FROM ( (SELECT paid, total, remain, date, patient_id FROM payment ) UNION (SELECT paid, total_need AS total, remain, date, patient_id FROM patient_vouchers ) ) a WHERE a.patient_id ='.$patient_id.' ORDER BY a.date ASC
具体来说,payment表和patient_vouchers表中,至少有一列(比如paid、total/total_need、remain、patient_id这类字符类型的列)的collation设置不一样——比如一个是utf8mb4_general_ci,另一个是utf8mb4_unicode_ci,甚至字符集本身就不同(比如一个是utf8,一个是utf8mb4),这就导致UNION无法正常合并结果。
两种快速解决方法:
方法1:强制指定统一的collation
在每个查询的对应字符列后面,用COLLATE关键字指定相同的排序规则(根据你的数据库实际字符集调整,这里以utf8mb4_general_ci为例):
SELECT a.paid, a.total, a.remain, a.date, a.patient_id FROM ( (SELECT paid COLLATE utf8mb4_general_ci, total COLLATE utf8mb4_general_ci, remain COLLATE utf8mb4_general_ci, date, patient_id COLLATE utf8mb4_general_ci FROM payment ) UNION (SELECT paid COLLATE utf8mb4_general_ci, total_need COLLATE utf8mb4_general_ci AS total, remain COLLATE utf8mb4_general_ci, date, patient_id COLLATE utf8mb4_general_ci FROM patient_vouchers ) ) a WHERE a.patient_id ='.$patient_id.' ORDER BY a.date ASC
注意:date是日期类型,不需要指定collation,只有字符类型的列需要处理。
方法2:修改表结构统一collation
如果业务允许,可以直接修改两个表中对应列的collation为同一个值,一劳永逸解决后续的冲突问题:
-- 修改payment表的冲突列 ALTER TABLE payment MODIFY COLUMN paid VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE payment MODIFY COLUMN total VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE payment MODIFY COLUMN remain VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE payment MODIFY COLUMN patient_id VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 修改patient_vouchers表的冲突列 ALTER TABLE patient_vouchers MODIFY COLUMN paid VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE patient_vouchers MODIFY COLUMN total_need VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE patient_vouchers MODIFY COLUMN remain VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ALTER TABLE patient_vouchers MODIFY COLUMN patient_id VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
你可以根据实际的列类型和长度调整上面的语句。
另外补充个小建议:如果你的需求不需要去重,应该用UNION ALL替代UNION,UNION会自动去重,性能比UNION ALL差不少,根据业务场景选择即可。
内容的提问来源于stack exchange,提问作者nashwa




