发现最近老是写vue的东西,仔细一想,我是个java程序员呀。这样划水不对呀。所以最近研究了一下在oracle中可能出现的一些情况的对策;
其中,我发现有时候,我们在数据库中可能保存一些有规律的字符串,比如“123,321,4556,41324”类似这种,通过‘,’或者其他分隔符隔开的字符串值,但是我们业务需求是想要把这种字符串转换成[123,321,4556,41324]的数组格式,也就是查询出来的返回值是list<int>或者list<String>格式;
按照正常的思路,我们都会先查询出一个String的值,然后在java中使用split方法来实现,但是我们今天不走寻常路,直接要在数据库中查询出一个数组;
但是如何实现呢?oracle是没有split方法的,我首先想到的是自己实现一个split方法,然后在查询数据的时候直接调用方法就能实现了,但是这样不就跟先查询出来在split分割没啥区别了呢?不行,说好不走寻常路的;
然后我发现oralce中对字符串处理的方法中常用的方法有replace,translate,substr等
其中substr可能可以实现,那么我假设一下,我要使用SUBSTR(string,start, [length])方法实现切割字符串的话,那么我需要只要分隔符所在的index值,那么需要用indexof方法,但是oracle好像没有提供这个方法,找了一下,发现有个instr( string1, string2 [, start_position [, nth_appearance ] ] ) 方法,字符串1中字符串2在第start_position 次出现的index;nth_appearance是查找方向,1是正向,-1是反向,那么我可以用instr先获取到分隔符出现的位置,然后再使用substr函数,但是每次使用的时候都需要获取到第n和n+1个分隔符的位置来获取截取长度,用起来好像不太方便,在sql里面不太好写;
于是我有没有什么其他的招式可以更方便的实现,嘿,我还真找到一个比较方便的方法:
REGEXP_SUBSTR(string, pattern, position, occurrence, modifier)
使用正则匹配截取字符串的方法,这个方法用的比较少,但是这个方法比substr方法更方便的地方就在于它是直接使用分隔符分割所有字符串,所以不需要分隔符的index也不需要知道截取长度,就他了;
这个方法怎么用呢?举个栗子:
SELECT REGEXP_SUBSTR('123,321,4556,41324', '[^,]+') FROM DUAL;
->> 123
我们匹配正则‘,’号开始,多个逗号,由于正则不太熟,哈哈,后面两个参数先不用,那么我得到了字符串中分隔符隔开的第1个子字符串,后面两个参数是什么作用呢?其中第三个参数position是分割后的字符串起点的index,这里的index是从1开始的,第四个参数很重要,是分隔开之后的第几个字符串,也就相当于我们数组的下标,当然也是从1开始的;最后一个参数我觉得应该用的时候比较少,是用作忽略大小写的,默认是不忽略,需要忽略大小写的话就加上‘i’来标识;
这样之后,我们只需要用一个i++循环来获取第四个参数的值,就能得到我们所需的数组了
DECLARE
X NUMBER;
Y NUMBER;
BEGIN
X := 0;
WHILE X < 4 LOOP
X := X + 1;
SELECT REGEXP_SUBSTR('123,321,4556,41324', '[^,]+',1,X) INTO Y FROM DUAL;
DBMS_OUTPUT.PUT_LINE(Y);
END LOOP;
END;
->>123
->>321
->>4556
->>41324
结果这又变成了一个存储过程了,而且到底需要分割出几个字符串是事前不知道的,这样不行,想想有没有其他简单点的实现方法呢?
这是我突然想到了一个,之前我不是写过一个connect by吗?connect by的时候不是有一个level值吗?每一层递归的level正好拿来当做每一次数组下标使用,于是我简化出了如下方法:
SELECT REGEXP_SUBSTR('123,321,4556,41324', '[^,]+', 1, LEVEL)
FROM DUAL
CONNECT BY REGEXP_SUBSTR('123,321,4556,41324', '[^,]+', 1, LEVEL) IS NOT NULL;
在获取结果为null的时候终止递归,哈哈,完美实现了不走寻常路的结果;