正则表达式在Oracle DB的列数据中找到多次出现的字符串(11g)

时间:2016-05-06 06:26:32

标签: sql regex oracle

在其中一个专栏中,我以文本格式存储JSON数据。示例数据如下所示:

{
    "dummy_time": "2016-04-27T18:44:55+00:00",
    "timeout_data": "2016-04-29T16:22:35+00:00,2016-04-30T16:22:35+00:00,2016-05-29T16:22:35+00:00",
    "time_id": "T101",
    "time_desc": "bla bla bla"
}

我需要编写SQL查询来查找此列有多个密钥timeout_data日期的行。我对REGEX并不是那么好。我编写了简单的查询来查找关键timeout_data中的两个日期:

SELECT *
FROM table1 f
WHERE REGEXP_LIKE(f.data, '.+\"timeout_data\": \".+,.+\",\"time_id\".*')
AND ROWNUM<6;

这个查询已经运行了很久。表有大约35,000,000行。 我不确定如何在密钥timeout_data中找到多个日期。如果您需要更多信息,请与我们联系。

3 个答案:

答案 0 :(得分:0)

也许instr()会更快。

SELECT 'test'
FROM  (SELECT '{
    "dummy_time": "2016-04-27T18:44:55+00:00",
    "timeout_data": "2016-04-29T16:22:35+00:00,2016-05-29T16:22:35+00:00",
    "time_id": "T101",
    "time_desc": "bla bla bla"
}' data FROM dual)
WHERE instr(data,',',instr(data,'"timeout_data"')) < instr(data,'"',instr(data,'"timeout_data"'),4);

您可以在数据的子集上进行测试。此外,instr(data,'"timeout_data"')被使用了两次,可能将其分解将加速该过程。

更新:您的REGEX似乎有问题 - 需要在.+之前\"time_id\"

此外 - REGEX不是限制因素。在我的机器上,一个100k SELECT .. FROM dual循环需要4.3秒。增加REGEX需要0.1秒。

答案 1 :(得分:0)

1)使用timeout_data

提取行

2)计算模式的出现次数。

select REGEXP_COUNT(regexp_substr(json,'^.*timeout_data.*$', 1,1,'m'), '\d{4}-\d{2}-\d{2}T')
from ( 
select '{
    "dummy_time": "2016-04-27T18:44:55+00:00",
    "timeout_data": "2016-04-29T16:22:35+00:00,2016-04-30T16:22:35+00:00,2016-05-29T16:22:35+00:00",
    "time_id": "T101",
    "time_desc": "bla bla bla"
}' json from dual
);

答案 2 :(得分:0)

您可以使用正则表达式找到ISO8601格式的日期:

\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}

如果您想要多个以逗号分隔的副本,那么您可以使用:

pattern(,pattern)+

(如果您只想找到两个匹配项,请删除尾随+

所以

\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}(,\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2})+

哪会使您的查询:

SELECT *
FROM table1 f
WHERE REGEXP_LIKE(f.data, '"timeout_data":\s*"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2}(,\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}[+-]\d{2}:\d{2})+"')
AND ROWNUM<6;

但是,如果您不想专门匹配日期,只想测试是否有多个以逗号分隔的值,那么您可以使用:

[^,"]+(,[^,"]+)+

(注意:确保模式与结束双引号不匹配 - 否则模式可能会超出属性的结尾。)

哪会使您的查询:

SELECT *
FROM table1 f
WHERE REGEXP_LIKE(f.data, '"timeout_data":\s*"[^,"]+([^,"]+)+"')
AND ROWNUM<6;

注意:您不需要在过滤段之前或之后查找任何内容,也不需要转义双引号。