【问题标题】:Asking for overlapping date ranges in same SQL table在同一个 SQL 表中要求重叠的日期范围
【发布时间】:2019-02-14 09:01:28
【问题描述】:

我在 oracle SQL 数据库中有一个表。

它的列是 VEHICLE_ID、GEAR_ID、STARTDATE、ENDDATE、AA。

开始日期和结束日期表示特定车辆的齿轮有效日期范围。

我的问题是我需要找到同一辆车的相同档位,但日期重叠。

我想出了这个查询

SELECT DISTINCT G.* FROM VEHICLE_GEARS G JOIN (SELECT A.*, B.CNT FROM VEHICLE_GEARS A JOIN
(SELECT VEHICLE_ID, GEAR_ID, COUNT(GEAR_ID) CNT FROM VEHICLE_GEARS GROUP BY 

VEHICLE_ID, GEAR_ID HAVING COUNT(GEAR_ID) > 1) B
    ON A.VEHICLE_ID = B.VEHICLE_ID AND A.GEAR_ID = B.GEAR_ID) ASDF ON
    G.VEHICLE_ID = ASDF.VEHICLE_ID AND G.GEAR_ID = ASDF.GEAR_ID
WHERE 
    NOT(
        TRUNC(ASDF.STARTDATE) >= TRUNC(G.ENDDATE)
        OR
        TRUNC(ASDF.ENDDATE) <= TRUNC(G.STARTDATE)
        )
    ORDER BY 1, 5

问题在于,这考虑到即使齿轮的结束日期与齿轮的开始日期相同的日期也会重叠,这是我不想要的,但即使从 where 子句中删除相等性,结果也是相同的。

请帮忙,提前谢谢。

编辑: 样本数据(经过上述查询):

000000006   2012-02-20 00:00:00 3   2999-12-31 00:00:00 804
000000006   1991-07-01 00:00:00 9   2999-12-31 00:00:00 804
000000147   1991-07-01 00:00:00 1   1992-10-08 00:00:00 601
000000147   1992-10-08 00:00:00 2   2999-12-31 00:00:00 601

预期的是,车辆 000000147 不应出现在结果集中,因为齿轮 601 的结束日期与其第二个“实例”的起始日期相同。 前两条记录(车辆 00000006)是正确的,因为档位 804 的日期重叠。

样本表数据:

000000000   2014-02-25 00:00:00 1   2999-12-31 00:00:00 302
000000000   2006-12-15 00:00:00 3   2999-12-31 00:00:00 604
000000000   2006-12-15 00:00:00 4   2999-12-31 00:00:00 605
000000006   1991-07-01 00:00:00 1   2999-12-31 00:00:00 601
000000006   2016-01-18 00:00:00 10  2999-12-31 00:00:00 605
000000006   2012-02-20 00:00:00 3   2999-12-31 00:00:00 804
000000006   1991-07-01 00:00:00 9   2999-12-31 00:00:00 804
000000147   1991-07-01 00:00:00 1   1992-10-08 00:00:00 601
000000147   1992-10-08 00:00:00 2   2999-12-31 00:00:00 601

预期结果:

000000000   2006-12-15 00:00:00 4   2999-12-31 00:00:00 605
000000006   2016-01-18 00:00:00 10  2999-12-31 00:00:00 605

【问题讨论】:

  • 轻松为您提供帮助:stackoverflow.com/help/mcve
  • 还需要什么?我的问题还不清楚吗?
  • 一些示例表数据和预期结果。 (作为格式化文本,而不是图像。)

标签: sql oracle


【解决方案1】:

您可以使用LAGLEAD 分析函数,然后您不需要使用任何自联接:

Oracle 设置

CREATE TABLE VEHICLE_GEARS ( vehicle_id, startdate, enddate, gear_id ) AS
SELECT '000000000', DATE '2014-02-25', DATE '2999-12-31', 302 FROM DUAL UNION ALL -- No duplicate vehicle & gear
SELECT '000000000', DATE '2006-12-15', DATE '2999-12-31', 604 FROM DUAL UNION ALL -- No duplicate vehicle & gear
SELECT '000000000', DATE '2006-12-15', DATE '2999-12-31', 605 FROM DUAL UNION ALL -- No duplicate vehicle & gear
SELECT '000000006', DATE '1991-07-01', DATE '2999-12-31', 601 FROM DUAL UNION ALL -- No duplicate vehicle & gear
SELECT '000000006', DATE '2016-01-18', DATE '2999-12-31', 605 FROM DUAL UNION ALL -- No duplicate vehicle & gear
SELECT '000000006', DATE '2012-02-20', DATE '2999-12-31', 804 FROM DUAL UNION ALL -- Overlaps previous
SELECT '000000006', DATE '1991-07-01', DATE '2999-12-31', 804 FROM DUAL UNION ALL -- Overlaps next
SELECT '000000147', DATE '1991-07-01', DATE '1992-10-08', 601 FROM DUAL UNION ALL -- Same end date as next start date
SELECT '000000147', DATE '1992-10-08', DATE '2999-12-31', 601 FROM DUAL UNION ALL -- Same start date as previous end date
SELECT '000000567', DATE '2018-01-01', DATE '2018-12-31', 203 FROM DUAL UNION ALL -- Overlaps next
SELECT '000000567', DATE '2018-12-01', DATE '2019-01-10', 203 FROM DUAL UNION ALL -- Overlaps previous and next
SELECT '000000567', DATE '2018-12-31', DATE '2019-01-10', 203 FROM DUAL UNION ALL -- Overlaps previous and next
SELECT '000000567', DATE '2018-12-31', DATE '2019-01-31', 203 FROM DUAL UNION ALL -- Overlaps previous
SELECT '000000567', DATE '2019-01-31', DATE '2019-02-28', 203 FROM DUAL           -- Same start date as previous

查询

SELECT vehicle_id,
       startdate,
       enddate,
       gear_id
FROM   (
  SELECT G.*,
         LAG( enddate   ) OVER ( PARTITION BY vehicle_id, gear_id ORDER BY startdate, enddate ) AS prev_enddate,
         LEAD( startdate ) OVER ( PARTITION BY vehicle_id, gear_id ORDER BY startdate, enddate ) AS next_startdate
  FROM   VEHICLE_GEARS G
)
WHERE  prev_enddate > startdate
AND    ( enddate <= next_startdate OR next_startdate IS NULL );

输出

VEHICLE_ID |开始日期 |结束日期 | GEAR_ID :--------- | :-------- | :-------- | ------: 000000006 | 12 年 2 月 20 日 | 99 年 12 月 31 日 | 804 000000567 | 18 年 12 月 31 日 | 19 年 1 月 31 日 | 203

db小提琴here

【讨论】:

    【解决方案2】:

    在最简单的形式中,这给出了表格中从另一行结束之前开始的所有内容,其中齿轮和车辆使用简单的自连接:

    select t1.*, t2.*
    from VEHICLE_GEARS t1
    inner join VEHICLE_GEARS t2
      on t1.gear_id = t2.gear_id
      and t1.vehicle_id = t2.vehicle_id
      and t2.startdate < t1.enddate
      and t1.startdate < t2.startdate
    

    【讨论】:

    • 感谢您的回复,您提供的查询并没有带来预期的结果。我得到的车辆没有具有相同齿轮 ID 的重叠日期的结果。这是一个示例: 000000000 2014-02-25 00:00:00 1 2999-12-31 00:00:00 302、000000000 2006-12-15 00:00:00 3 2999-12-31 00:00: 00 604. 日期是重叠的,但齿轮是 302 和 604。如果齿轮相同,那就是正确的。
    猜你喜欢
    • 2011-07-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 2018-01-02
    • 1970-01-01
    • 1970-01-01
    • 2014-01-31
    相关资源
    最近更新 更多