前幾天開發的同事反饋一個問題,說前台系統報出了ORA錯誤,希望我們能看看是什么原因。
java.sql.SQLException: ORA-01427: single-row subquery returns more than one row
我一看到這個錯誤的第一反應就是應該是sql語句的問題,然后開發同事反饋這個程序已經用了蠻長時間了,現在突然報出了錯誤。
簡單溝通之后,我得到了對應的sql語句。
SELECT ID, PROJECTNAME, GRAPH, TYPE, PERSON, RECORDTIME, PROJECTURL , ICON, GO, COLOR, LOCATION, MANAGER ,
(SELECT NAME FROM app_iwork.WS_PRIVILEGE_NODE WHERE MENUID = pro.projectkey ) KEYNAME
FROM app_iwork.WS_TEST_PROJECT pro
WHERE TYPE = '495' ORDER BY LOCATION ASC ,ID DESC
從sql語句能夠猜出來錯誤應該是從子查詢里返回的。
(SELECT NAME FROM app_iwork.WS_PRIVILEGE_NODE WHERE MENUID = pro.projectkey )
我們來看看這個語句,按照ORA-01427的錯誤,應該是這個子查詢返回了多行值。
簡單來驗證一下,首先根據type='495'能夠得到下面的查詢結果
select projectkey from app_iwork.WS_TEST_PROJECT pro WHERE TYPE = '495'
PROJECTKEY
--------------------------------------------------
1557739
1516023
1577799
374871
1584374
取出任意一條,然后按照兩個表的關聯字段值查詢,可以看到輸出了3行數據。
SQL> SELECT NAME FROM app_iwork.WS_PRIVILEGE_NODE WHERE MENUID = 1557739;
NAME
--------------------------------------------------------------------------------
分析系統
分析系統
分析系統
所以這種情況的解決方案有幾種。
--推測子查詢中肯定有返回多行的情況,試着在子查詢中加入rownum<2,也就是限制返回一行數據。成功!或
SELECT ID, PROJECTNAME, GRAPH, TYPE, PERSON, RECORDTIME, PROJECTURL , ICON, GO, COLOR, LOCATION, MANAGER , n.name
FROM app_iwork.WS_TEST_PROJECT pro ,app_iwork.WS_PRIVILEGE_NODE n
WHERE MENUID = pro.projectkey and TYPE = '495' ORDER BY LOCATION ASC ,ID DESC
這種方式可以輸出結果而不會報錯,盡管存在冗余數據,但是也不推薦。
另外一種思路就是在子查詢中進行重復值的過濾,使用group by來完成。
SELECT ID, PROJECTNAME, GRAPH, TYPE, PERSON, RECORDTIME, PROJECTURL , ICON, GO, COLOR, LOCATION, MANAGER ,
(SELECT NAME FROM app_iwork.WS_PRIVILEGE_NODE WHERE MENUID = pro.projectkey group by name ) KEYNAME
FROM app_iwork.WS_TEST_PROJECT pro
WHERE TYPE = '495' ORDER BY LOCATION ASC ,ID DESC
還有一種思路就是和開發確認,刪除冗余的數據,這種方案不用修改代碼,還是相對來說可以實現的一種方式。
和開發同事簡單溝通,這個表中還是存在部分的臟數據,修改之后,問題就解決了。
如果對這個問題進一步改進,可以在確認這個表結構的基礎上,看看能夠添加相應的約束,這樣也能夠保證表中的數據不會存在冗余,避免后續出現此類的問題。