MySQL报错Column xxxx in xxxx clause is ambiguous

虽然是一个常见的 SQL 报错缺陷,但是仍要记录一下解决的过程。

因为开始实习后好长时间不写学习记录了,这篇算是之后的学习记录再出发的一个起点!

错误出现

接口 500,本地 debug 轻松地发现了问题:是 Mapper 中的一条 SQL 有问题,Column 'short_name' in order clause is ambiguous

SQL并不复杂,数据库结构就不赘述了,四张表连接查询。直接看问题 SQL:

SELECT
	p.*,
	lt.NAME AS province_name,
	t.NAME country_name 
	FROM
		sm_basic_province p
		LEFT JOIN sm_basic_country bc ON p.country = bc.country_id
		LEFT JOIN sm_basic_lang_tag t ON bc.NAME = t.tag_id 
		AND t.lang = 1 
		AND t.tenant_id = 'keycai'
		LEFT JOIN sm_basic_lang_tag lt ON p.NAME = lt.tag_id 
		AND lt.lang = 1 
		AND lt.tenant_id = 'keycai' 
	WHERE
		p.tenant_id = 'keycai' 
		AND bc.tenant_id = 'keycai' 
ORDER BY CONVERT ( short_name USING gbk ) DESC

问题很明显、很常见,short_name 字段名不明确。

错误解决

常规方法 ORDER BY 之前的查询结果加括号:

(SELECT
	p.*,
	lt.NAME AS province_name,
	t.NAME country_name 
	FROM
		sm_basic_province p
		LEFT JOIN sm_basic_country bc ON p.country = bc.country_id
		LEFT JOIN sm_basic_lang_tag t ON bc.NAME = t.tag_id 
		AND t.lang = 1 
		AND t.tenant_id = 'keycai'
		LEFT JOIN sm_basic_lang_tag lt ON p.NAME = lt.tag_id 
		AND lt.lang = 1 
		AND lt.tenant_id = 'keycai' 
	WHERE
		p.tenant_id = 'keycai' 
		AND bc.tenant_id = 'keycai')
ORDER BY CONVERT ( short_name USING gbk ) DESC

错误依旧,SELECT * (…) t 生成中间表 t,再根据 t 表的 short_name 字段进行排序:

SELECT * FROM (SELECT
	p.*,
	lt.NAME AS province_name,
	t.NAME country_name 
	FROM
		sm_basic_province p
		LEFT JOIN sm_basic_country bc ON p.country = bc.country_id
		LEFT JOIN sm_basic_lang_tag t ON bc.NAME = t.tag_id 
		AND t.lang = 1 
		AND t.tenant_id = 'keycai'
		LEFT JOIN sm_basic_lang_tag lt ON p.NAME = lt.tag_id 
		AND lt.lang = 1 
		AND lt.tenant_id = 'keycai' 
	WHERE
		p.tenant_id = 'keycai' 
		AND bc.tenant_id = 'keycai') t
ORDER BY CONVERT ( short_name USING gbk ) DESC

至此,问题解决。

错误分析

可以去回看一下最开始出问题的 SQL,根据 SELECT 后面的字段,不该出现 short_name 不明确的问题。

虽然在 sm_basic_provincesm_basic_country 两张表中都存在 short_name 字段,但是只查询了 sm_basic_province 中的 short_name 字段。

删掉 CONVERT() 函数,尝试执行:

SELECT
	p.*,
	lt.NAME AS province_name,
	t.NAME country_name 
	FROM
		sm_basic_province p
		LEFT JOIN sm_basic_country bc ON p.country = bc.country_id
		LEFT JOIN sm_basic_lang_tag t ON bc.NAME = t.tag_id 
		AND t.lang = 1 
		AND t.tenant_id = 'keycai'
		LEFT JOIN sm_basic_lang_tag lt ON p.NAME = lt.tag_id 
		AND lt.lang = 1 
		AND lt.tenant_id = 'keycai' 
	WHERE
		p.tenant_id = 'keycai' 
		AND bc.tenant_id = 'keycai' 
ORDER BY short_name DESC

正确执行。

正常来讲一条 SQL 的执行顺序是:

FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY -> LIMIT
每步执行都会产生一个虚表,作为当前执行步骤的输出和下一步执行时的输入,只有当最后一步执行完后这个虚表才会作为这条被执行 SQL 的最终结果。

按照这个执行顺序,CONVERT() 执行的时候应该已经没有重复的列了,说明这个函数是在 SELECT 之前就执行了,因为这时候的虚表中存在相同名称的列,所以报了 ambiguous 错误

至此解决了问题,但是原理层面仅停留在猜测,并没有找到权威的材料证明,也没有想到什么好的验证方法。

如果有知道原因的大神,还望赐教!

本篇未完待续。。。。


菜鸟本菜,不吝赐教,感激不尽!

更多题解源码和学习笔记:github优快云M1ng

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值