sql常见问题汇总:分割字段,并分行

--将一行中用特定字符分割的字段,分成多行


with t1 as
(
select '张三' c1,'胸外科,皮肤科,骨科1,骨科2,骨科3,骨科4,骨科5,骨科6,骨科7,骨科8,骨科9,骨科10,骨科11,骨科12,骨科13,骨科14,骨科15,骨科16,骨科17' c2,date'2000-11-19' c3  from dual
union all
select '李四','胸外科',date'2001-01-04'  from dual
union all
select '王五','妇产科,骨科',date'2001-01-08' from dual
)

select c1,
  substr(','||c2||',',instr(','||c2,',',1,b.rn)+1,
  instr(c2||',',',',1,b.rn)-instr(','||c2,',',1,b.rn)) c2,c3
from t1,
  (select rownum rn from t1
  connect BY ROWNUM<20 ) b
  where length(c2)-length(replace(c2,','))+1>=b.rn
order by c1,b.rn    


(select rownum rn from t1 connect BY ROWNUM<20)  b-- 是为了生成一个1-19的序列,相当于19行

length(c2)-length(replace(c2,','))+1>=b.rn  -- b.rn 是递增的, c2字段分割后的数组长度, t1的每一条记录和b表做乘积达到复制记录的目的,>=b.rn 是限制复制记录的条数为分割后的数组长度。


----

with t1 as
(
select '张三' c1,'胸外科,皮肤科,骨科1,骨科2,骨科3,骨科4,骨科5,骨科6,骨科7,骨科8,骨科9,骨科10,骨科11,骨科12,骨科13,骨科14,骨科15,骨科16,骨科17' c2,date'2000-11-19' c3  from dual
union all
select '李四','胸外科',date'2001-01-04'  from dual
union all
select '王五','妇产科,骨科',date'2001-01-08' from dual
)
select DISTINCT c1
       ,c3
       ,REPLACE( -- 去除多余的【,】
            regexp_substr(c2||',' ,'.*?'||'[,]' ,1 ,LEVEL)  -- 截取 ,【科室】,
            ,',') "科室"
from t1
        connect by level <= nvl(
                               length(regexp_replace(c2,'[^,]','')) + 1
                              ,1)
order by c1;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
regexp_substr:5个参数
第一个是输入的字符串
第二个是正则表达式  
第三个是标识从第几个字符开始正则表达式匹配。(默认为1)
第四个是标识第几个 匹配组。(默认为1)
第五个是是取值范围:
i:大小写不敏感;
c:大小写敏感;
n:点号 . 不匹配换行符号;
m:多行模式;

x:扩展模式,忽略正则表达式中的空白字符。



关于:.*?      正则表达式的贪婪匹配和惰性匹配

贪婪匹配(greedy):它会匹配尽可能多的字符。它首先看整个字符串,如果不匹配,对字符
串进行收缩;遇到可能匹配的文本,停止收缩,对文本进行扩展,当发现匹配的文本时,它
不着急将该匹配保存到匹配集合中,而是对文本继续扩展,直到无法继续匹配 或者 扩展完
整个字符串,然后将前面最后一个符合匹配的文本(也是最长的)保存起来到匹配集合中。所
以说它是贪婪的。 
惰性匹配(lazy):它会匹配尽可能少的字符,它从第一个字符开始找起,一旦符合条件,立
刻保存到匹配集合中,然后继续进行查找。所以说它是懒惰的。

默认使用贪婪匹配,在次数限定元字符后加?转为惰性匹配


另附几个元字符的意义:

'^' 匹配输入字符串的开始位置,在方括号表达式中使用,此时它表示不接受该字符集合。
'$' 匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 '\n' 或'\r'。
'.' 匹配除换行符 \n之外的任何单字符。
'?' 匹配前面的子表达式零次或一次。
'*' 匹配前面的子表达式零次或多次。
'+' 匹配前面的子表达式一次或多次。
'( )' 标记一个子表达式的开始和结束位置。
'[]' 标记一个中括号表达式。
'{m,n}' 一个精确地出现次数范围,m=<出现次数<=n,'{m}'表示出现m次,'{m,}'表示至少出现m次。
'|' 指明两项之间的一个选择。例子'^([a-z]+|[0-9]+)$'表示所有小写字母或数字组合成的字符串。
\num 匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。
正则表达式的一个很有用的特点是可以保存子表达式以后使用,被称为Backreferencing. 允许复杂的替换能力

你可能感兴趣的:(oracle)