微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Regexp_Substr 过滤 SQL 中的行

如何解决Regexp_Substr 过滤 SQL 中的行

对于下面的表结构和数据,我试图获取在过去 15 个月内至少包含 1 个日期的行,其中包含由模式分隔的字符串组。

CREATE TABLE TEMP(nbr NUMBER,dt VARCHAR2(4000));
INSERT INTO TEMP VALUES(1,'22/05/2016');
INSERT INTO TEMP VALUES(2,'22/05/2020##22/01/2020##22/10/2019');
INSERT INTO TEMP VALUES(3,'25/05/2020##22/07/2019##22/11/2019');
INSERT INTO TEMP VALUES(4,'25/05/2015##22/01/2017##22/06/2018');

我写的查询是:

select nbr,dt from temp
WHERE MONTHS_BETWEEN(SYSDATE,TO_DATE(REGEXP_SUBSTR(dt,'[^##]+',1,LEVEL)))<15
CONNECT BY LEVEL<=REGEXP_COUNT(dt,'[^##]+');

对于第 2 行和第 3 行,属性 dt 的值使得至少 1 个子字符串的日期小于 15 个月。 预期结果是:

nbr    dt

2   22/05/2020##22/01/2020##22/10/2019

3   25/05/2020##22/07/2019##22/11/2019

我得到的结果是:https://imgur.com/a/EHzRRY3

我确信这个查询遗漏了一些东西,因为我得到了所有这些重复的行。 这是我第一次尝试这种类型的东西。 有人可以向我指出我需要做些什么来纠正这个问题吗?

解决方法

您可以简单地将 EXISTS 过滤器与相关的分层子查询一起使用:

SELECT *
FROM   temp t
WHERE  EXISTS (
         SELECT 1
         FROM   DUAL
         WHERE  TO_DATE( REGEXP_SUBSTR( t.dt,'[^#]+',1,LEVEL ),'DD/MM/YYYY' )
                  >= ADD_MONTHS( TRUNC(SYSDATE),-15 )
         CONNECT BY
                LEVEL <= REGEXP_COUNT( t.dt,'[^#]+' )
       )

对于您的示例数据,输出:

NBR | DT                                
--: | :---------------------------------
  2 | 22/05/2020##22/01/2020##22/10/2019
  3 | 25/05/2020##22/07/2019##22/11/2019

dbfiddle here

,

如果我没有提到需要适当的数据模型,并且数据应该在从电子表格中导入时转换为该数据模型,那我将是疏忽大意。这样你就不会像现在一样试图通过箍来获得你想要的东西。当然你可以得到你想要的东西,但是代码很难让其他人在你身后维护。作为练习,我会鼓励您这样做,即使您可能会得到适合您当前情况的解决方案。亲眼看看如何花时间创建正确规范化的数据模型并将电子表格数据移入其中,这将使您能够创建更高效​​、更易于维护的代码。

好的,也就是说,考虑一下。这里的 WITH 子句像临时表一样用于创建要从中进行选择的数据集。该查询使用 CONNECT BY 来遍历字符串的每个元素,其中元素后跟分隔符 '##' 或行尾(使用这种形式的正则表达式处理 NULL 列表元素)。请注意,我在选择列表中包含了 LEVEL,因此您可以查看哪个元素与条件匹配。如果您不关心这一点,请将其删除并在 select 语句中添加 DISTINCT 以获得您在原始帖子中期望的输出。

WITH tbl(item_nbr,purchase_date) AS (
  SELECT 1,'22/05/2016' FROM dual UNION ALL
  SELECT 2,'22/05/2020##22/01/2020##22/10/2019' FROM dual UNION ALL
  SELECT 3,'25/05/2020##22/07/2019##22/11/2019' FROM dual UNION ALL
  SELECT 4,'25/05/2015##22/01/2017##22/06/2018' FROM dual
)
SELECT --DISTINCT
       item_nbr,LEVEL AS ELEMENT,purchase_date
FROM tbl
WHERE MONTHS_BETWEEN(SYSDATE,TO_DATE(REGEXP_SUBSTR(purchase_date,'(.*?)(##|$)',LEVEL,NULL,1),'DD/MM/YYYY' ) ) < 15
CONNECT BY LEVEL <= REGEXP_COUNT(purchase_date,'##') + 1
  AND PRIOR item_nbr = item_nbr
  AND PRIOR SYS_GUID() IS NOT NULL;


  ITEM_NBR    ELEMENT PURCHASE_DATE                     
---------- ---------- ----------------------------------
         2          1 22/05/2020##22/01/2020##22/10/2019
         2          2 22/05/2020##22/01/2020##22/10/2019
         2          3 22/05/2020##22/01/2020##22/10/2019
         3          1 25/05/2020##22/07/2019##22/11/2019
         3          3 25/05/2020##22/07/2019##22/11/2019

5 rows selected.
,

我喜欢为此使用标准递归查询。这是一种可移植的语法,可以在略有变化的数据库中使用,因此值得学习。另一个好处是我们可以使用简单的字符串函数而不是正则表达式。

我们可以使用以下递归查询将字符串元素解析为一系列包含相应 date 的行:

with cte (nbr,dt,dt_new,dt_rest) as (
    select nbr,null,dt || '##' from temp
    union all
    select nbr,to_date(
            substr(dt_rest,instr(dt_rest,'##') - 1)
            default null on conversion error,'dd/mm/yyyy'
        ),substr(dt_rest,'##') + 2) 
    from cte
    where instr(dt_rest,'##') > 0
)
select * from cte 
where dt_new is not null 
order by nbr,dt_new;

从那时起,我们可以简单地汇总并查看每个组的最新日期:

with cte (nbr,dt_rest ) as (...)
select nbr,max(dt_new) as max_dt_new
from cte
group by nbr,dt
having months_between(sysdate,max(dt_new)) < 15

Demo on DB Fiddle

NBR | DT                                 | MAX_DT_NEW
--: | :--------------------------------- | :---------
  2 | 22/05/2020##22/01/2020##22/10/2019 | 22-MAY-20 
  3 | 25/05/2020##22/07/2019##22/11/2019 | 25-MAY-20 

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?