ORA-22922: nonexistent LOB value
Table of Contents
1 現象及錯誤信息
項目現場反饋報表查詢系統執行一個查詢並導出的功能,無法將查詢結果導出,報錯:文件太大,不能作為附件。而實際上數據量是很小的。
同時發來了執行的SQL語句。我連上環境執行,發現報的是ORA-22922錯誤。錯誤信息如下:
oerr ora 22922 22922, 00000, "nonexistent LOB value" // *Cause: The LOB value associated with the input locator does not exist. // The information in the locator does not refer to an existing LOB. // *Action: Repopulate the locator by issuing a select statement and retry // the operation.
按照官方的提示信息來看,是在根據一定條件查詢LOB時,沒有找到LOB對象。 sql 語句由於是涉及到了業務表和邏輯,這里不展示。
2 分析
該SQL從一個視圖中查詢數據。而從視圖本身來看是沒有LOG對象的。
select column_name,data_type from dba_tab_cols where owner='REP' AND TABLE_NAME='&view_name'; COLUMN_NAME DATA_TYPE -------------------- -------------------- CUSTOMER_NAME VARCHAR2 CUSTOMER_ID NUMBER CUSTOMER_CODE VARCHAR2 INVOICE_NO VARCHAR2 BOOK_PAY NUMBER CASH_PAY NUMBER AMOUNT NUMBER PAYMENT_NO VARCHAR2 NUM NUMBER PAY_TYPE VARCHAR2 CHG_ITEM_NAME VARCHAR2 PAYMENT_DATE DATE ORG_NAME VARCHAR2 OP_NAME VARCHAR2 ACTION_NAME VARCHAR2 OFFICE_ORG_ID NUMBER OPERATOR_ID NUMBER
繼續往下挖,這里面肯定是有LOB對象的。 發現該視圖是從另外一張視圖里查詢的,繼續挖, 最后發現一個視圖的創建語句如下:
select .. column_list ... from rep.view_sk_1 t left join ( select PAYMENT_NO, to_char(wm_concat(d.invoice_no)) invoice_no from ....
這個視圖里有 wm_concat 函數,該函數的返回值是LOB類型。 經測試,將該行注釋掉以后,可以正常查詢,至此可以肯定, 問題就是由該函數引起的。
wm_concat 函數是一個列轉行的函數,將一列的多行數據轉化為一行數據,比如
salary ------- 10000 9000 8500
經wm_concat 轉換 select wm_concat(salary) from employee where depno=20; 可以轉換成
salary ------- 10000,9000,8500
並且以lob類型返回 。 在視圖的創建語句中,也發現, 使用了to_char ,看來研發也注意到了這個問題,避免了使用LOB類型。 可是,他們並不知道的是, wm_concat 由於是Lob 類型,是不能進行group by ,distinct 以及union 共存的,因為會偶發ORA-22922錯誤 。 這里需要注意,是偶發,不是必然。這也算是oracle 的一個小bug吧。
在Oracle 11G 中,新推出了一個函數有相似的功能是listagg(column_name,'seprator') within group ( order by ..)
3 解決
將 to_char(wm_concat(d.invoice_no)) invoice_no 使用listagg 替換為 LISTAGG(d.invoice_no,',') WITHIN GROUP (ORDER BY PAYMENT_NO) INVOICE_NO 。 經測試,報錯不再發生 。替換后的視圖創建語句如下:
select .. column_list .. from rep.view_sk_1 t left join ( select PAYMENT_NO, LISTAGG(d.invoice_no,',') WITHIN GROUP (ORDER BY PAYMENT_NO) invoice_no from .....
4 知識總結
出現這個錯誤很多時候是使用了wmsys.wm_concat的同時使用了group ,distinct 或者union, 本來兩者沒有問題,問題在於:
- Oracle Database 10g Enterprise Edition Release 10.2.0.5.0以后的版本wmsys.wm_concat查詢出的是LOB類型
- oralce的SQL語句中若查詢了LOB字段是不能使用distinct,union,和group by等關鍵字的。
- 並且在12C 以后,Oracle官方軟件不再提供wm_concat函數,因此從兼容性上來看,也不建議使用wm_concat.
因此,以后在編寫PLSQL時,留意一下該問題即可。
Created: 2020-07-01 Wed 21:11