前言
之前遇到了一次這樣的需求,當時沒有記錄,這一次又趕上了,簡單的記錄一下。
場景
表A中存放了集裝箱的信息,一個集裝箱一條記錄,表B中存放了對於集裝箱操作的指令,一條指令包括多個集裝箱箱號,通過分號;
切割(TCIU2347687;XUTR3546865
),現在的需求是,對於已經在指令表B中的集裝箱,在查詢表A時需要過濾掉。
- 很容易想到的是
not in
, 然而分號分割。 - 其次,
not like
,然而[Err] ORA-01427: 單行子查詢返回多個行
,表示like
后面只接受模糊查詢的單個值。
所以必須將分號分割的記錄,拆分成單獨的記錄。
變成:
實現
Oracle可使用regexp_substr函數
實現,實現上面切割的sql為:
select regexp_substr('TCIU2347687;XUTR3546865', '[^;]+', 1, level) JZXXH
from dual connect by level <= regexp_count('TCIU2347687;XUTR3546865', ';') + 1
其中regexp_substr
各個參數的含義:
TCIU2347687;XUTR3546865
表示需要分割匹配的串(我這里只是做了示例,真實情況下是表的字段)。[^;]+
典型的正則表達式,我這里分號切割,因此確定分割規則是多個不是分號的字符
,因此遇到分號便結束,完成一個串的獲取。1
開始位置,最左端(Oracle下標都是1開始)level
表示第幾個匹配上的。
為了直觀點搞清楚這個函數,比如下面的語句:
select REGEXP_SUBSTR('aaa;bbb','[^;]+',1,1) AS STR FROM dual;
結果就是aaa
, 如果把第二個1變成2,輸出就是bbb
。
好了,這部分意圖很明顯了,下面就是把它每一個切割串取出來,看到上面取level個
,而這個level
是個什么東西呢,在這個之前,先看regexp_count(string, c)
函數,這個函數其實很好理解,返回string中c的個數。
然后就是這個level,這是一個偽列,和RowNum相似,
SELECT LEVEL FROM DUAL CONNECT BY LEVEL <=2;
所以再回到最初的sql,也就很好理解了。
最后
- 本文內容個人拙見,若有出入,歡迎指正。
- 歡迎賞臉關注:家佳Talk