使用 Oracle Query 显示所有匹配的记录

Posted

技术标签:

【中文标题】使用 Oracle Query 显示所有匹配的记录【英文标题】:Display all matched records using Oracle Query 【发布时间】:2021-10-04 12:10:45 【问题描述】:

我在 Oracle 中使用 Connect by Level 查询以显示所有匹配的记录 regexp_substr 但它没有显示全部,我需要将 Connect by Level 从 +1 更改为 +8 以获得所有结果。如果未来的比赛比这更多怎么办?我想在不将 +1 更改为 +10 或 +20 等的情况下捕获多少匹配项。有没有最简单和最快的方法?

这是我的查询:

SELECT     DATA_SOURCE,REGEXP_SUBSTR(DATA_SOURCE,'A-\S+|ABC\S+',1, LEVEL) AS REF_NUM
FROM
(
SELECT '
Z-TEST
Y-TEST
A-123456789
ABC123456790
Y-TRY
A-123456791
ABC123456792
ABC123456793
Y-TRY
Y-TRY
Z-TEST
Y-TEST
Z-TEST
Y-TEST
A-123456794
ABC123456795
ABC123456796
Y-TRY
Z-TEST
Y-TEST
Z-TEST
Y-TEST
A-123456797
ABC123456798
' DATA_SOURCE
FROM DUAL
)
CONNECT BY LEVEL <= LENGTH(REGEXP_COUNT(DATA_SOURCE,'A-\S+|ABC\S+'))+1

Result: 
A-123456789
ABC123456790
A-123456791

Desired Result:
REF_NUM
A-123456789
ABC123456790
A-123456791
ABC123456792
ABC123456793
A-123456794
ABC123456795
ABC123456796
A-123456797
ABC123456798

【问题讨论】:

你为什么要比较计数的长度?如果输出中有 8 个结果,则计数为 8。8 的长度为 1。(“长度”表示数字中有多少位 - 在本例中为一位。)为什么要将任何内容与 1 进行比较,而不是 8? 除此之外,你确定你的正则表达式是正确的吗?如果输入包含字符串DMA-123,它也会返回A-123,这是你需要的吗? 嗨@mathguy,你是对的,应该修改正则表达式,我只需要那些第一个字符串'^A-|^ABC',1,1,'m' 我在Connect中尝试了多行函数按级别不起作用!有什么建议吗? 【参考方案1】:

你的 connect by 子句应该是

CONNECT BY LEVEL <= REGEXP_COUNT(DATA_SOURCE,'A-\S+|ABC\S+', 1)

而不是

CONNECT BY LEVEL <= LENGTH(REGEXP_COUNT(DATA_SOURCE,'A-\S+|ABC\S+'))+1

但如果您想将此解决方案应用于具有更多行的表,则需要添加以下内容:

CONNECT BY LEVEL <= REGEXP_COUNT(DATA_SOURCE,'A-\S+|ABC\S+', 1)
AND PRIOR DATA_SOURCE = DATA_SOURCE
AND PRIOR SYS_GUID() IS NOT NULL

到您的 connect by 子句。

所以你的查询最终应该是这样的:

SELECT     --DATA_SOURCE, 
  REGEXP_SUBSTR(DATA_SOURCE,'A-\S+|ABC\S+',1, LEVEL) AS REF_NUM
FROM
(
SELECT '
Z-TEST
Y-TEST
A-123456789
ABC123456790
Y-TRY
A-123456791
ABC123456792
ABC123456793
Y-TRY
Y-TRY
Z-TEST
Y-TEST
Z-TEST
Y-TEST
A-123456794
ABC123456795
ABC123456796
Y-TRY
Z-TEST
Y-TEST
Z-TEST
Y-TEST
A-123456797
ABC123456798
' DATA_SOURCE
FROM DUAL
)
CONNECT BY LEVEL <= REGEXP_COUNT(DATA_SOURCE,'A-\S+|ABC\S+', 1)
AND PRIOR DATA_SOURCE = DATA_SOURCE
AND PRIOR SYS_GUID() IS NOT NULL
;

demo

For further explanation

【讨论】:

嗨@MDBIA,即使您的查询有多个匹配项,结果也只有一个...... 我不确定我是否得到了你的帮助,但我在我的答案中添加了一个演示链接。你可以在那里测试它。 嗨@MDBIA 我看到了演示,是的,它按我想要的方式工作,我会检查实际查询并告诉你。 嗨@ClintMohamed,我更新了我的答案以涵盖多行案例。希望这会有所帮助。 嗨@MDBIA,非常感谢。【参考方案2】:

将按条件连接更改为例如CHR(13) 出现次数(第 35 行),然后选择存在 ref_num 的行(第 38 行)。像这样的:

SQL> WITH
  2     temp
  3     AS
  4        (    SELECT DATA_SOURCE,
  5                    REGEXP_SUBSTR (DATA_SOURCE,
  6                                   'A-\S+|ABC\S+',
  7                                   1,
  8                                   LEVEL) AS REF_NUM
  9               FROM (SELECT '
 10  Z-TEST
 11  Y-TEST
 12  A-123456789
 13  ABC123456790
 14  Y-TRY
 15  A-123456791
 16  ABC123456792
 17  ABC123456793
 18  Y-TRY
 19  Y-TRY
 20  Z-TEST
 21  Y-TEST
 22  Z-TEST
 23  Y-TEST
 24  A-123456794
 25  ABC123456795
 26  ABC123456796
 27  Y-TRY
 28  Z-TEST
 29  Y-TEST
 30  Z-TEST
 31  Y-TEST
 32  A-123456797
 33  ABC123456798
 34  ' DATA_SOURCE FROM DUAL)
 35         CONNECT BY LEVEL <= REGEXP_COUNT (data_source, CHR (10)))

 36  SELECT ref_num
 37    FROM temp
 38   WHERE ref_num IS NOT NULL;

REF_NUM
--------------------
A-123456789
ABC123456790
A-123456791
ABC123456792
ABC123456793
A-123456794
ABC123456795
ABC123456796
A-123456797
ABC123456798

10 rows selected.

SQL>

[EDIT] 如果您实际上是一次解析表格内容(不是一个 huge 字符串),那么看看这样的示例是否有帮助。我将您的示例数据分成两行并添加了ID 列(只是为了更轻松地查看结果)。

SQL> with your_table (id, data_source) as
  2  (select 1, '
  3  Z-TEST
  4  Y-TEST
  5  A-123456789
  6  ABC123456790
  7  Y-TRY
  8  A-123456791
  9  ABC123456792
 10  ABC123456793
 11  Y-TRY
 12  Y-TRY
 13  ' from dual
 14  union all
 15  select 2, '
 16  Z-TEST
 17  Y-TEST
 18  Z-TEST
 19  Y-TEST
 20  A-123456794
 21  ABC123456795
 22  ABC123456796
 23  Y-TRY
 24  Z-TEST
 25  Y-TEST
 26  Z-TEST
 27  Y-TEST
 28  A-123456797
 29  ABC123456798
 30  ' from dual
 31  )

 32  select id,
 33    regexp_substr (data_source, 'A-\S+|ABC\S+', 1, column_value) as ref_num
 34  from your_table cross join
 35    table(cast(multiset(select level from dual
 36                        connect by level <= regexp_count (data_source, chr (10))
 37                       ) as sys.odcinumberlist))
 38  where regexp_substr (data_source, 'A-\S+|ABC\S+', 1, column_value) is not null
 39  /

        ID REF_NUM
---------- ------------------------------
         1 A-123456789
         1 ABC123456790
         1 A-123456791
         1 ABC123456792
         1 ABC123456793
         2 A-123456794
         2 ABC123456795
         2 ABC123456796
         2 A-123456797
         2 ABC123456798

10 rows selected.

SQL>

【讨论】:

嗨@Littlefoot,它可以工作,但如果解析 HugeClob,性能会很差。任何解决方法来最小化空记录而不是通过 Where ref_num is not null… 您是在解析一个巨大的 CLOB,还是在解析整个表(“n”行和 CLOB 列)?因为,如果是前者,恐怕你无能为力。如果是后者,那么是的 - 它可以被重写并 - 希望 - 运行得更快一些。 嗨@Littlefoot,我正在为每条记录解析一个 col hugeclob,每条记录大约 5,000 个字符...... 我又加了一个例子;请看一下。 嗨@Littlefoot,非常感谢!

以上是关于使用 Oracle Query 显示所有匹配的记录的主要内容,如果未能解决你的问题,请参考以下文章

Laravel Join Query 获取所有匹配的记录

Elasticsearch多重匹配在提供空字符串时不返回所有结果

在 Oracle Forms 中按升序查看记录

Big Query 匹配表之间的记录

Oracle学习日记

带有匹配的MongoDB聚合显示所有记录