在字符串中搜索子字符串并除

时间:2019-02-09 19:55:16

标签: sql regex oracle oracle11g oracle10g

我有一个带有varchar2(5000 char)列的表,其中包含几个句子。在这样的句子中的某个地方显示了一个数字,然后是另一个数字。我想选择这些数字并将它们除。不确定如何在sqlplus oracle 11g中执行此操作。

我认为我应该使用类似SUBSTR, REGEXP_SUBSTR, INSTR的函数。不确定哪个最适合这份工作。

列如下:

blah bahwl balwo hxkswl blahxhsh alshbhe NUM 40003.26 in 4 pieces. etc
bwh bahwl bafado hxkswl alshbhe NUM 6006.16 in 9 pieces. etc
badh baadfl balwo hxkswl blahxhsh alshbhe NUM 200 in 30 pieces. etc
bfda bdafl hxkswl NUM 33 in 4 pieces. etc
blcfh bfdwl bfdlwo alshbhe NUM 54545.01 in 700 pieces. etc

所以我想直接在NUM之后搜索并选择一个数字,然后在“ in”和“ pieces”之间选择一个数字,然后将这些数字相除。

select .... 40003.26 / 4 
select .... 6006,16 / 9 
select ....  200 / 30 

任何帮助表示感谢

3 个答案:

答案 0 :(得分:1)

您可以按以下方式使用regexp_substr / regexp_replacelrtrim

with t1 as
 (select 'blah bahwl balwo hxkswl blahxhsh alshbhe NUM 40003.26 in 4 pieces. etc
             bwh bahwl bafado hxkswl alshbhe NUM 6006.16 in 9 pieces. etc
             badh baadfl balwo hxkswl blahxhsh alshbhe NUM 200 in 30 pieces. etc
             bfda bdafl hxkswl NUM 33 in 4 pieces. etc
             blcfh bfdwl bfdlwo alshbhe NUM 54545.01 in 700 pieces. etc' as str
    from dual),
t2 as
 (select regexp_substr(str, '(.*)pieces.*', 1, level) as str
    from t1
   cross join dual
  connect by level <= regexp_count(str, 'pieces')),
t3 as
 (select str,
         regexp_replace(str, '[^0-9]in[^0-9]', '/') str1,
         regexp_substr(str, '[^0-9]*') str2,
         regexp_substr(str, '[^0-9]*$') str3
    from t2)
select rtrim(ltrim(str1, str2), str3) as "Result String" from t3


Result String
-------------
40003.26/4
6006.16/9
200/30
33/4
54545.01/700

Demo

答案 1 :(得分:0)

此选项选择输入字符串的NUM blabla部分,与其中出现NUM的次数相同(这就是INTER CTE所做的事情)。最后的SELECT(向前13行)提取数值并将其除以产生结果。

SQL> with test (col) as
  2    (select 'blah bahwl balwo hxkswl blahxhsh alshbhe NUM 40003.26 in 4 pieces. etc
  3  bwh bahwl bafado hxkswl alshbhe NUM 6006.16 in 9 pieces. etc
  4  badh baadfl balwo hxkswl blahxhsh alshbhe NUM 200 in 30 pieces. etc
  5  bfda bdafl hxkswl NUM 33 in 4 pieces. etc
  6  blcfh bfdwl bfdlwo alshbhe NUM 54545.01 in 700 pieces. etc' from dual
  7    ),
  8  inter as
  9    (select regexp_substr(col, 'NUM \d+(\.\d+)? in \d+', 1, level) res
 10     from test
 11     connect by level <= regexp_count(col, 'NUM')
 12    )
 13  select res,
 14         regexp_substr(res, '\d+(\.\d+)?') c1,
 15         regexp_substr(res, '\d+$') c2,
 16         --
 17         round(to_number(regexp_substr(res, '\d+(\.\d+)?'), '99999999D99',
 18                         ' NLS_NUMERIC_CHARACTERS = ''.,''') /
 19               to_number(regexp_substr(res, '\d+$')), 2) result
 20  from inter;

RES                  C1         C2             RESULT
-------------------- ---------- ---------- ----------
NUM 40003.26 in 4    40003.26   4            10000,82
NUM 6006.16 in 9     6006.16    9              667,35
NUM 200 in 30        200        30               6,67
NUM 33 in 4          33         4                8,25
NUM 54545.01 in 700  54545.01   700             77,92

SQL>

答案 2 :(得分:0)

如果您可以保证,该全部(我的意思是全部)行将包含您所描述的片段,例如:{{ 1}},其中NUM ..... in ..... pieces是两个数字,第二个数字不为0(因此我们不除以0),那么您可以使用XMLQuery来实现,就像这样:

.....

即使您不熟悉XMLQuery,也不难理解在这种特殊情况下XMLQuery是如何工作的。您可能需要单独选择REGEXP_REPLACE的结果,以查看XMLQuery的实际输入。

但是,此解决方案将阻塞更大的数据集中的任何,如下所示,它们是with test_data as ( select 1 id, 'blah bahwl NUM 40003.26 in 4 pieces. etc' str from dual union all select 2 , 'bwh balshbh NUM 6006.16 in 9 pieces. etc' from dual union all select 3 , 'badh sh alshbh NUM 200 in 30 pieces. etc' from dual union all select 4 , 'bfda bdafl hxksw NUM 33 in 4 pieces. etc' from dual union all select 5 , 'bl lshbh NUM 54545.01 in 700 pieces. etc' from dual ) select id, xmlquery(regexp_replace(str, '^.*?NUM(.*?)in(.*?)pieces.*$', '\1 div \2') returning content).getNumberVal() as division_result from test_data ; ID DIVISION_RESULT ----- --------------- 1 10000.815000 2 667.351111 3 6.666667 4 8.250000 5 77.921443 子句。

如果可能出现此类异常,则必须告诉我们应如何处理每个异常。请注意,WITH根本没有所需的片段。 id = 6缺少第二个数字; id = 7的第二个数字等于0; id = 8的文字应有数字。

这说明了为什么也许如果必须处理此类问题,您应该考虑添加两列,如果您的Oracle版本足够高,则可能要添加虚拟列,以仅容纳所需的数字-这样处理可能的异常会变得很多更轻松。显然,这也将使您的数据模型更接近于当前模型公然违反的“第一范式”。

id = 9