上周对接一个老系统,工单号存在一个字段里,格式是部门-年份-序号,比如WX-2024-0881。现在要取年份,我第一反应是用substr硬切,结果部门长度不固定,切出来全错,只能老实查分隔符的位置。
oracle里干这个就靠instr,专门返回某个字符第几次出现的位置。找到位置再配合substr切,基本能搞定九成的拆串需求。比写一堆like和正则省事多了。
instr四个参数一次讲透
写法是instr(原串,要找的串,起始位置,第几次出现)。比如instr(工单号,分隔符,1,2),就是从第1个字符开始找,找第2个分隔符在哪。起始位置写负数代表从尾巴往前找,取文件名后缀时特别好用。
举个例子,WX-2024-0881里找第2个横杠,返回的是8左右的位置。拿到位置后,substr往后切4位就是年份。找不到时instr返回0,记得判0,不然substr会切出空串,排查起来很烦。
配合substr拆串:三段式写法
- 取分隔符位置:用instr定位第一个和第二个分隔符
- 按位置切片:substr取中间段,注意起始加1避开分隔符
- 兜底空值:无分隔符返回0时给默认值,别直接入库
SELECT INSTR('WX-2024-0881','-',1,1) AS p1, INSTR('WX-2024-0881','-',1,2) AS p2, SUBSTR('WX-2024-0881', INSTR('WX-2024-0881','-',1,1)+1, 4) AS part FROM DUAL;这段在DUAL上能直接跑,p1是第一个横杠,p2是第二个,part就是2024。实际表里把字符串换成字段名就行。如果分隔符是下划线或者竖线,写法一样,竖线在正则里有特殊含义,但在instr里就是普通字符,不用转义,这点比regexp_instr省心。
数据量大时注意,instr套在where里会导致全表扫,百万级表会慢。可以加函数索引,或者清洗时把拆好的字段存成冗余列,查询直接走列,速度差一个量级。
取舍建议很简单。偶尔拆一次就instr加substr现切,频繁查就拆好存列。别为了一次好看写复杂正则,维护的人会谢你。