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 錯誤

至此解決了問題,但是原理層面僅停留在猜測,並沒有找到權威的材料證明,也沒有想到什麼好的驗證方法。

如果有知道原因的大神,還望賜教!

本篇未完待續。。。。


菜鳥本菜,不吝賜教,感激不盡!

更多題解源碼和學習筆記:githubCSDNM1ng

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章