【问题标题】:Return all regex matches as new rows将所有正则表达式匹配作为新行返回
【发布时间】:2021-12-13 03:30:33
【问题描述】:

我有一个reviews 表如下:

r_id my_comment
1 Boxes with the TID 823 cannot exceed 40 kg
2 Parcel with the marking tid 63157 must not make the weight go over 31 k.g
3 Envelopes with TID 104124 and TID 92341 cant excel above 94.477kg
4 TID38204 cannot go over 45.4 kg and TID 8242602 cannot go over 92kg
5 Box with the TID 94514 cannot go over 52kg but also cannot go over 51KG

我正在尝试匹配两件事。 TID 和重量 (kg)。如您所见,需要牢记三件事

  • 重量始终以公斤为单位,不区分大小写,有两种写法,kgk.g,两种写法<weight> <kg or k.g><weight><kg or k.g>(一种带空格,一种不带空格)
  • TID 不区分大小写,有两种写法:TID<id>TID <id>(一种带空格,一种不带空格。
  • 一些 cmets 有多个 TID 和权重。我假设 TID 的第一次出现与重量的第一次出现有关,而 TID 的第二次出现与重量的第二次出现有关。我只增加了 2 个 TID/权重实例,但我希望它能够动态地适用于任意数量的实例。

所以如果评论只有 1 个权重和 1 个 TID,我可以提取 TID 和权重。但是,如果它有多个,我没有这样做。所以我想把多个分成不同的行。

这是我想要的输出

r_id tid weight my_comment
1 823 40 Boxes with the TID 823 cannot exceed 40 kg
2 63157 31 Parcel with the marking tid 63157 must not make the weight go over 31 k.g
3 104124 94.477 Envelopes with TID 104124 and TID 92341 can't excel above 94.477kg
3 92341 Envelopes with TID 104124 and TID 92341 can't excel above 94.477kg
4 38204 45.4 TID38204 cannot go over 45.4 kg and TID 8242602 cannot go over 92kg
4 8242602 92 TID38204 cannot go over 45.4 kg and TID 8242602 cannot go over 92kg
5 94514 52 Box with the TID 94514 cannot go over 52kg but also cannot go over 51KG
5 51 Box with the TID 94514 cannot go over 52kg but also cannot go over 51KG

SQL 创建表/虚拟数据:

CREATE TABLE reviews(
  r_id number(3) NOT NULL,
  my_comment VARCHAR(255) NOT NULL
);

INSERT INTO reviews (r_id, my_comment) VALUES (1, 'Boxes with the TID 823 cannot exceed 40 kg');
INSERT INTO reviews (r_id, my_comment) VALUES (2, 'Parcel with the marking tid 63157 must not make the weight go over 31 k.g');
INSERT INTO reviews (r_id, my_comment) VALUES (3, 'Envelopes with TID 104124 and TID 92341 cant excel above 94.477kg');
INSERT INTO reviews (r_id, my_comment) VALUES (4, 'TID38204 cannot go over 45.4 kg and TID 8242602 cannot go over 92kg');
INSERT INTO reviews (r_id, my_comment) VALUES (5, 'Box with the TID 94514 cannot go over 52kg but also cannot go over 51KG');

我的尝试中,我能够提取 tid 和 weight,但只能提取第一个实例并且无法将其拆分为行。

SELECT
    r_id,

   REGEXP_SUBSTR (
        REGEXP_SUBSTR (my_comment, '(tid).*?[0-9]+', 1, 1, 'i'),
        '[0-9]+'
    ) as "tid",

    REGEXP_SUBSTR (
        REGEXP_SUBSTR (my_comment, '(cannot exceed|go over| excel above).*?[0-9]+ ?(kg|k.g)', 1, 1, 'i'),
        '[0-9]+'
    ) as "weight"

FROM reviews;

【问题讨论】:

  • 顺便说一句,(kg|k.g) == k\.?g
  • @Bohemian 感谢您的提示。
  • 如果您试图通过从单个源字符串(行)中提取不同的数据来创建多行,那么您必须有点像 sql 向导。这可能会有所帮助 - community.oracle.com/tech/developers/discussion/4284229/…
  • 你的数据库真的是 10g 吗?那是一个非常旧的版本
  • 如果有 2 个 tids 和 2 个 weights,两者之间是否总是有一个“和”?

标签: sql regex database oracle oracle10g


【解决方案1】:

我能够提取 tid 和 weight,但只能提取第一个实例并且无法将其拆分为行。

您的查询,已修改:

  • 我没有对你已经写的东西做太多,因为你似乎对提取的tidweight很满意
    • 我所做的更改是regexp_substroccurrence 参数(以前是1,现在是column_value
  • 为了获得 split 数据,添加了 cross join,它“循环”通过 my_comment 的次数与 tidkg 之间出现次数最多的次数一样多(以任何形式)
    • 例如,如果有 2 个tid 和 1 个kg,它将“循环”2 次​​li>
    • 它还用于避免仅使用 connect by level 子句时会出现重复

您确实将问题标记为 Oracle 10;我没有了,但我知道它不支持regexp_count 功能。如果情况确实如此(您从未回答过 Koen 的问题),那么它将不起作用,您将不得不使用其他方式计算 tid/weight 的出现次数。不过,我希望你不在 10g 上。

我在 SQL*Plus 中运行了这段代码。 BREAK 在这里只是为了很好地区分 r_idmy_comment 值,没有任何其他目的。

SQL> break on r_id on my_comment
SQL> SELECT r_id,
  2         my_comment,
  3         REGEXP_SUBSTR (REGEXP_SUBSTR (my_comment,
  4                                       '(tid).*?[0-9]+',
  5                                       1,
  6                                       COLUMN_VALUE,
  7                                       'i'),
  8                        '[0-9]+') AS "tid",
  9         REGEXP_SUBSTR (
 10            REGEXP_SUBSTR (
 11               my_comment,
 12               '(cannot exceed|go over| excel above).*?[0-9]+ ?(kg|k.g)',
 13               1,
 14               COLUMN_VALUE,
 15               'i'),
 16            '[0-9]+') AS "weight"
 17    FROM reviews
 18         CROSS JOIN
 19         TABLE (
 20            CAST (
 21               MULTISET (
 22                      SELECT LEVEL
 23                        FROM DUAL
 24                  CONNECT BY LEVEL <= GREATEST (REGEXP_COUNT (my_comment, 'tid'     , 1, 'i'),
 25                                                REGEXP_COUNT (my_comment, '(kg|k.g)', 1, 'i')))
 26                  AS SYS.odcinumberlist));

导致

 R_ID MY_COMMENT                                                                tid     weight
----- ------------------------------------------------------------------------- ------- -------
    1 Boxes with the TID 823 cannot exceed 40 kg                                823     40
    2 Parcel with the marking tid 63157 must not make the weight go over 31 k.g 63157   31
    3 Envelopes with TID 104124 and TID 92341 cant excel above 94.477kg         104124  94
                                                                                92341
    4 TID38204 cannot go over 45.4 kg and TID 8242602 cannot go over 92kg       38204   45
                                                                                8242602 92
    5 Box with the TID 94514 cannot go over 52kg but also cannot go over 51KG   94514   52
                                                                                        51

8 rows selected.

SQL>

【讨论】:

    猜你喜欢
    • 2021-10-12
    • 2020-12-02
    • 1970-01-01
    • 1970-01-01
    • 2018-02-18
    • 2012-12-22
    • 1970-01-01
    • 2012-10-07
    • 2022-01-14
    相关资源
    最近更新 更多