iT邦幫忙

1

🐞 ORA-00932 與 CLOB 比對的排錯經驗

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20250924/20155103be8KbgPpuO.png
續前一篇【Oracle 全欄位搜尋技巧:我如何查出 GUID 藏在哪張表裡?】
👉 https://ithelp.ithome.com.tw/articles/10372967

當時我寫了一個 SQL,可以快速搜尋 GUID 是否存在於特定表的欄位。
但實際使用時,我踩到一個坑:Oracle 報錯
ORA-00932: inconsistent datatypes: expected - got CLOB
這篇就記錄一下我怎麼發現問題,以及最終的解決方法。


🔍 問題定位

Oracle 在不同版本中,對 CLOB 欄位使用 UPPER()=
這類字串函式或比較運算子,常常會報錯。這意味著我得找其他方法來比對字串。


✅ 解決方案一:使用 REGEXP_LIKE

REGEXP_LIKE 可以吃
CLOB,也能直接做大小寫不敏感比對。調整後的查詢如下:

SELECT 'ACC_ROLE' AS table_name, 'CRMAN' AS column_name, COUNT(*) AS match_count
FROM ACC_ROLE
WHERE REGEXP_LIKE(CRMAN, '^UPDOWN$', 'i')
HAVING COUNT(*) > 0
UNION ALL
SELECT 'ACC_ROLE', 'MFMAN', COUNT(*)
FROM ACC_ROLE
WHERE REGEXP_LIKE(MFMAN, '^UPDOWN$', 'i')
HAVING COUNT(*) > 0
UNION ALL
SELECT 'ACC_ROLE', 'ROLE_TYPE', COUNT(*)
FROM ACC_ROLE
WHERE REGEXP_LIKE(ROLE_TYPE, '^UPDOWN$', 'i')
HAVING COUNT(*) > 0;

後來我想改比對 UUID,也只要換掉字串即可:

REGEXP_LIKE(CRMAN, '^520D701C-2322-49C7-AEC0-8111FF933DA0$', 'i')

✅ 解決方案二:使用 DBMS_LOB.SUBSTR

若不想用正規表達式,也能透過 DBMS_LOB.SUBSTRCLOB 轉成 VARCHAR2
來比對:

WHERE UPPER(DBMS_LOB.SUBSTR(CRMAN, 4000, 1)) = 'UPDOWN'
  AND DBMS_LOB.GETLENGTH(CRMAN) = 6

這樣可以避免被截斷誤判,但仍有長度限制。


🛠️ VSCode 正則替換小技巧

因為 SQL 中出現很多類似的條件,我想用 VSCode 的正則替換一次搞定。

原始程式碼:

UPPER(CRMAN) = 'UPDOWN'

希望替換成:

REGEXP_LIKE(CRMAN, '^UPDOWN$', 'i')

搜尋用 Regex

UPPER\(\s*(?:\w+\.)?(\w+)\s*\)\s*=\s*'([^']+)'

替換模式

REGEXP_LIKE($1, '^$2$', 'i')

一開始我寫成 \1,結果替換出來變成字面字串,後來才發現 VSCode
的捕捉組要用 $1$2


⚖️ 對照表:兩種寫法比較

方法 優點 缺點
REGEXP_LIKE 可處理 CLOB,簡潔,支援大小寫不敏感 大數據下會全表掃描,效率較差
DBMS_LOB.SUBSTR 不需正規表達式,比對更精確(可控制長度) 需額外處理長度,程式較冗長

💡 適合詢問 GPT 的 Prompt

「在 Oracle 中,若 CLOB 欄位使用 UPPER() = '字串' 會報
ORA-00932,該如何安全比對字串?可否提供 REGEXP_LIKE
DBMS_LOB.SUBSTR 的範例?」


圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言