我的情况是我的数据如下所示:
第18章第10单元第16节
答案 0 :(得分:4)
我会使用REGEXP_SUBSTR
(documentation)和正确的正则表达式。例如:
select regexp_substr('Chapter 18 Unit 10 Sect 16', 'Chapter \d*') from dual;
--Will return: Chapter 18
select regexp_substr('Chapter 18 Unit 10 Sect 16', 'Unit \d*') from dual;
--Will return: Unit 10
select regexp_substr('Chapter 18 Unit 10 Sect 16', 'Sect \d*') from dual;
--Will return: Sect 16
当然,如果您在表中存储Chapter xx Unit yy Sect zz
个字符串,那么您只需使用此类查询即可获得多个结果:
select regexp_substr(info_column, 'Chapter \d*') from mytable;
您可以将\d
替换为[0-9]
或[[:digit:]]
<强> SQLfiddle 强>
答案 1 :(得分:2)
我会使用旧的SUBSTR而不是REGEXP。由于REGEXP将占用过多的CPU资源。
您的要求非常简单。
对于数据Chapter 18 Unit 10 Sect 16
,如果您希望第18章作为输出:
执行:
Select substr(column, 1, 10) from table
同样,你可以为其他输出做。
编辑:伙计们,你们当中有些人可能会想,为什么我要强调好旧的SUBSTR而不是REGEXP。只需将跟踪打开,然后查看跟踪输出。我同意,对于较新的版本,Oracle已经对REGEXP做了很多改进。但是,到目前为止,我还没有看到一个令我满意的案例。我可能错了,所以,如果有人有测试用例,我真的很想看到它。这对我们所有人来说都是一个很好的学习。
更新以显示上述关于REGULAR EXPRESSION的测试用例比SUBSTR + INSTR更快,是错误的!
常规表达:
SQL> DECLARE
2 l_start NUMBER := dbms_utility.get_cpu_time;
3 BEGIN
4 FOR i IN (WITH t
5 AS (SELECT 'Chapter '
6 || LEVEL
7 || ' Unit '
8 || LEVEL
9 || ' Sect '
10 || LEVEL d
11 FROM dual
12 CONNECT BY ROWNUM < 100000)
13 SELECT Regexp_substr(d, 'Chapter [0-9]*') chapter,
14 Regexp_substr(d, 'Unit [0-9]*') unit,
15 Regexp_substr(d, 'Sect [0-9]*') sect
16 FROM t) LOOP
17 NULL;
18 END LOOP;
19
20 dbms_output.Put_line('time taken by REGULAR EXPRESSION : '
21 || ( dbms_utility.get_cpu_time - l_start )
22 || ' hsec');
23 END;
24
25 /
time taken by REGULAR EXPRESSION : 61 hsec
PL/SQL procedure successfully completed.
SUBSTR + INSTR:
SQL> DECLARE
2 l_start NUMBER := dbms_utility.get_cpu_time;
3 BEGIN
4 FOR i IN (WITH t
5 AS (SELECT 'Chapter '
6 || LEVEL
7 || ' Unit '
8 || LEVEL
9 || ' Sect '
10 || LEVEL d
11 FROM dual
12 CONNECT BY ROWNUM < 100000)
13 SELECT Substr(d, 1, Instr(d, ' ', 1, 2) - 1)
14 chapter,
15 Substr(d, Instr(d, ' ', 1, 2),
16 Instr(d, ' ', 1, 4) - Instr(d,
17 ' ', 1, 2))
18 unit,
19 Substr(d, Instr(d, ' ', 1, 4), Length(d) - Instr(d, ' ', 1,
20 4)
21 + 1)
22 sect
23 FROM t) LOOP
24 NULL;
25 END LOOP;
26
27 dbms_output.Put_line('time taken by SUBSTR + INSTR : '
28 || ( dbms_utility.get_cpu_time - l_start )
29 || ' hsec');
30 END;
31
32 /
time taken by SUBSTR + INSTR : 28 hsec
PL/SQL procedure successfully completed.
因此,可以清楚地看到SUBSTR + INSTR所花费的时间不到常规表达的一半。
答案 2 :(得分:0)
我的版本,在数据长度未修复时很有用。这可能是泛型
regexp_substr
的最后一个参数实际上返回了相应的案例结果!
SELECT level as case ,
regexp_substr('Chapter 180 Unit 10 Sect 16 World 100', '\w* \d*( )*',1,level) as result
FROM dual
CONNECT BY level <= CEIL(regexp_count('Chapter 180 Unit 10 Sect 16 World 100',' ')/2)
<强>结果:强>
CASE RESULT
---------- ------------------------
1 Chapter 180
2 Unit 10
3 Sect 16
4 World 100
答案 3 :(得分:0)
使用substr:
declare
l_start number := DBMS_UTILITY.get_cpu_time;
begin
for i in (
with t as (
select 'Chapter ' || level || ' Unit ' || level || ' Sect ' || level d from dual connect by rownum < 100000
)
select substr(d, 1, instr(d, ' ', 1, 2) - 1) chapter
, substr(d,
instr(d, ' ', 1, 2),
instr(d, ' ', 1, 4) - instr(d, ' ', 1, 2)
) unit
, substr(d,
instr(d, ' ', 1, 4),
length(d) - instr(d, ' ', 1, 4) + 1
) sect
from t
)
loop
null;
end loop;
DBMS_OUTPUT.put_line((DBMS_UTILITY.get_cpu_time - l_start) || ' hsec');
end;
126 hsec
使用regexp:
declare
l_start number := DBMS_UTILITY.get_cpu_time;
begin
for i in (
with t as (
select 'Chapter ' || level || ' Unit ' || level || ' Sect ' || level d from dual connect by rownum < 100000
)
select regexp_substr(d, 'Chapter [0-9]*') chapter
, regexp_substr(d, 'Unit [0-9]*') unit
, regexp_substr(d, 'Sect [0-9]*') sect
from t
)
loop
null;
end loop;
DBMS_OUTPUT.put_line((DBMS_UTILITY.get_cpu_time - l_start) || ' hsec');
end;
190 hsec
所以使用regexp的解决方案速度较慢,但它更具可读性,如果我是你,我会使用regexp。