【问题标题】:SQL - Select date ranges without overlappingSQL - 选择不重叠的日期范围
【发布时间】:2022-01-25 01:12:23
【问题描述】:

我有下表(Oracle 数据库):

ID valid_from valid_to
1 01.01.22 28.02.22
1 01.03.22 30.06.22
1 01.07.22 31.12.22
1 01.01.23 null
2 01.01.22 31.03.22
2 01.04.22 null

我现在如何最好地提取所有日期范围而不会在两个 ID 上重叠?最终结果集应如下所示:

valid_from valid_to
01.01.22 28.02.22
01.03.22 31.03.22
01.04.22 30.06.22
01.07.23 31.12.22
01.01.23 null

Null 代表 max_date(PL / SQL Oracle Max Date)。

此外,我应该只选择对当年有效的值(假设我们已经在 2022 年)。

提前感谢您的帮助!

【问题讨论】:

  • 我将从一个提取重叠范围的查询开始(这可以通过简单的连接来完成)。
  • 为什么从 01.03.22 到 30.06.22 的行无效(在您的示例中为第二行)?您用于选择这些日期的某些规则丢失了吗? id 相对于日期范围的最终列表是什么意思?

标签: sql select plsql overlap


【解决方案1】:

您可以应用下一个选择语句:

with 
  -- main table
  t1 AS (SELECT w, q1, q2, to_date(q1,'dd.mm.yy') q1d, to_date(q2,'dd.mm.yy') q2d FROM www)

  -- custom year in YYYY format
, t0 AS (SELECT '2022' y FROM dual)

  -- join and order dates FROM - TO
, t2 AS (SELECT t1.q1, t1.q1d, s2.q2, s2.q2d 
         FROM t1 
         LEFT JOIN t1 s2 on t1.q1d <= s2.q2d 
         ORDER BY t1.q1d,  s2.q2d)

  -- mark the first each new row-pair by row_number()
 , t3 AS (SELECT t2.*, 
                 row_number() OVER (PARTITION BY t2.q1d ORDER BY t2.q1d ) r 
          FROM t2 )
 
-- join custom year value and select desired rows based on that value
SELECT q1, q2 FROM t3 
  JOIN t0 on 1=1
WHERE r = 1 
  -- for the custom year
     AND t0.y <= to_char(q1d, 'yyyy')
ORDER BY q1d;

Demo

在我的表格示例中,日期以varchar2 数据类型和dd.mm.yy 日期格式显示。如果您的表字段的数据类型为date,那么您不需要为这两个字段实现函数to_date()

使用过的表格样本:

create table www (w integer, q1 varchar2(30), q2 varchar2(30));
    
insert into www values (1, '01.01.22', '28.02.22');
insert into www values (1, '01.03.22', '30.06.22');
insert into www values (1, '01.07.22', '31.12.22');
insert into www values (1, '01.01.23', '');
insert into www values (2, '01.01.22', '31.03.22');
insert into www values (2, '01.04.22', '');

如果您的表示例在字段valid_to 中有更多具有null 值的行并且valid_from 中的日期不在任何范围内,假设:

insert into www values (1, '01.01.24', '');

那么之前的解决方案最终将产生更多行,并带有null 值。 在这种情况下,您可以使用更复杂的解决方案:

... 
-- join custom year value and select desired rows based on that value
  , t4 as (SELECT q1, q2, q1d FROM t3 
            JOIN t0 on 1=1 
           WHERE  r = 1 AND
            -- for the custom year
                t0.y <= to_char(q1d, 'yyyy')
           ORDER BY q1d)

  -- filter non-nullable rows 
 , t5 as ( SELECT q1, q2 FROM t4 WHERE Q2 IS NOT NULL )

  -- max date from rows where Q2 field has null value 
 , t6 as ( SELECT to_char(MAX(Q1D),'dd.mm.yy') q1, q2 
           FROM t4 
           WHERE Q2 IS NULL 
           GROUP BY q2) 

 -- append rows with max date  
 SELECT * FROM t5
 UNION ALL
 SELECT * FROM t6; 

Demo

【讨论】:

    猜你喜欢
    • 2020-04-24
    • 2018-03-03
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多