如何从 Oracle 中的字符串中循环标记?

Posted

技术标签:

【中文标题】如何从 Oracle 中的字符串中循环标记?【英文标题】:How to loop over tokens from a string in Oracle? 【发布时间】:2020-12-03 15:25:36 【问题描述】:

假设我有一个字符串 - '9999,34244324324\n88888,131321323\n77777,8787223'

我希望将由\n 分隔的每一对中的每个逗号分隔数字插入到表格的两列中。

例如,如下所示:

9999 |34244324324
88888|131321323
77777|8787223

使用 REGEXP_SUBSTR,我可以将这些对组合在一起:

REGEXP_SUBSTR(str, '((\d+),(\d+)\n?)',1,i, null, j)

其中i 找到num,num 匹配项,j 是第一个或第二个数字的 1 或 2。

我可以想象循环这个 i 次,我可以从 REGXP_COUNT 得到,但这似乎重复同样的事情 n 次。实现这一目标的正确方法是什么?

很长一段时间后我正在做数据库脚本,所以虽然我之前做过,但我不记得确切了。所以我需要这方面的建议。

【问题讨论】:

【参考方案1】:
    以“\n”作为分隔符将整个字符串分割成行:
select *
from  xmltable(
      'tokenize(., "\\n")'
      passing '9999,34244324324\n88888,131321323\n77777,8787223' 
      columns
         s varchar2(100) path '.'
      )

结果:

S
---------------------
9999,34244324324
88888,131321323
77777,8787223
    用“,”作为分隔符将每一行拆分为子字符串: 2.1 使用regexp_substr:
select 
  s,
  regexp_substr(s,'^([^,]*),([^,]*)',1,1,'',1)  s1,
  regexp_substr(s,'^([^,]*),([^,]*)',1,1,'',2)  s2
from  xmltable(
      'tokenize(., "\\n")'
      passing '9999,34244324324\n88888,131321323\n77777,8787223' 
      columns
         s varchar2(100) path '.'
      )

结果:

S                    S1           S2
-------------------- ------------ ------------
9999,34244324324     9999         34244324324
88888,131321323      88888        131321323
77777,8787223        77777        8787223

或 2.2 使用相同的 xmltable:

select *
from  xmltable(
      'for $r in tokenize(., "\\n")
         return element R 
            attribute s1 tokenize($r, ",")[1], 
            attribute s2 tokenize($r, ",")[2]
         '
      passing '9999,34244324324\n88888,131321323\n77777,8787223' 
      columns
         s1 varchar2(10) path '@s1',
         s2 varchar2(10) path '@s2'
      )

【讨论】:

【参考方案2】:

这是一个纯粹的基于 regexp_substr 的解决方案。 “d”子查询纯粹是您的数据。 Oracle 不能很好地理解 \n,因此 chr(10) 会处理这个问题。行子查询将您的数据按换行符拆分为行。最后一个查询以逗号分隔字符串。您可以通过添加额外的 regexp_substr 实例并增加最后一个(位置)参数来扩展两列逗号分隔的数据。

WITH d AS
 (SELECT REPLACE('9999,34244324324\n88888,131321323\n77777,8787223',
                 '\n',
                 chr(10)) AS ata
    FROM dual),
lines AS
 (SELECT regexp_substr(d.ata,
                       '[^' || chr(10) || ']+',
                       1,
                       LEVEL) AS line
    FROM d
  CONNECT BY regexp_substr(d.ata,
                           '[^' || chr(10) || ']+',
                           1,
                           LEVEL) IS NOT NULL)
SELECT l.line,
       regexp_substr(l.line,
                     '[^,]+',
                     1,
                     1) AS c1,
       regexp_substr(l.line,
                     '[^,]+',
                     1,
                     2) AS c2
  FROM lines l;

生产:

line                c1      c2
----------------    -----   -----------
9999,34244324324    9999    34244324324
88888,131321323     88888   131321323
77777,8787223       77777   8787223

【讨论】:

以上是关于如何从 Oracle 中的字符串中循环标记?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Oracle 循环中的 select 语句中执行 alter 命令?

循环仅在添加跨度标记时显示数组中的最后一个字符串

在 ruby​​ 循环的结束标记中添加连字符是啥意思 <% -%>

如何从 Oracle 中的字符串中获取唯一字符?

用循环中的多个字符替换字符串中的一个字符 - ORACLE

ORACLE如何查询字符串的真正长度