【问题标题】:Select Missing Date Ranges In table In Oracle在 Oracle 中的表中选择缺失的日期范围
【发布时间】:2017-09-14 12:29:22
【问题描述】:

我有以下数据表数据为:

员工日期 ---------------------------------- 101 2017 年 1 月 8 日 101 2017 年 2 月 8 日 101 2017 年 4 月 8 日 101 06/08/2017 101 2017 年 7 月 8 日 102 2017 年 1 月 8 日 102 2017 年 3 月 8 日 102 2017 年 6 月 8 日

我想写一个查询来获取以下缺失的日期 2017 年 1 月 8 日至 2017 年 7 月 8 日数据为:

员工日期 ---------------------------------- 101 2017 年 3 月 8 日 101 2017 年 5 月 8 日 101 2017 年 7 月 8 日 102 2017 年 2 月 8 日 102 2017 年 4 月 8 日 102 2017 年 5 月 8 日 102 2017 年 7 月 8 日

如何处理?!

【问题讨论】:

  • 这里已经回答了这个问题:stackoverflow.com/questions/18207721/…
  • @kazzi - 不是完全重复的,因为这里的 OP 也有不同的 EMPLOYEEID,这使问题复杂化。
  • 您是否需要仅为您展示的两名员工执行此操作?或者 - 好多了! - 您是否有另一个表,其中所有 EMPLOYEEID 都存在(并且 EMPLOYEEID 是主键)?因此,例如,如果有 EMPLOYEEID = 103,他根本不在您的第一个表中,他是否必须显示在输出中,并且所有日期都被视为缺失?

标签: sql oracle plsql


【解决方案1】:

要么使用我认为更好的日期表,要么使用派生表来填充日期(谷歌中“Oracle 如何生成日期”下的许多代码):

SELECT t.employeeid,s.date
FROM (SELECT distinct p.employeeid FROM YourTable p) t
CROSS JOIN ( DATE TABLE \ Derived Table) s

此查询将为每个员工生成整个日期范围。如果你只想要那些缺失的:

SELECT t.employeeid,s.date
FROM (SELECT distinct p.employeeid FROM YourTable p) t
CROSS JOIN ( DATE TABLE \ Derived Table) s
LEFT JOIN YourTable h
 ON(h.employeeID = t.employeeId and h.date = s.date)
WHERE h.employeeID IS NULL

【讨论】:

    【解决方案2】:

    您可以使用分层查询生成所有行:

    SELECT DATE '2017-08-01' + LEVEL - 1 AS dt
    FROM   DUAL
    CONNECT BY DATE '2017-08-01' + LEVEL - 1 <= DATE '2017-08-07'
    

    或递归子查询因式分解子句:

    WITH alldates ( dt ) AS (
      SELECT DATE '2017-08-01' FROM DUAL
    UNION ALL
      SELECT dt + 1 FROM alldates WHERE dt < DATE '2017-08-07'
    )
    SELECT * FROM alldates
    

    然后,您可以使用分区外连接将其与现有的数据和过滤器结合起来处理那些缺失的行:

    WITH alldates ( dt ) AS (
      SELECT DATE '2017-08-01' FROM DUAL
    UNION ALL
      SELECT dt + 1 FROM alldates WHERE dt < DATE '2017-08-07'
    )
    SELECT employeeId,
           dt
    FROM   alldates d
           LEFT OUTER JOIN
           your_table t
           PARTITION BY ( t.employeeID )
           ON ( t.daydate = d.dt )
    WHERE  daydate IS NULL;
    

    【讨论】:

      【解决方案3】:

      假设您有一个 EMPLOYEE 表,其中 EMPLOYEEID 是主键 - 并假设可能有员工根本没有出现在您的 DATA_TABLE 中,然后他们必须包含在您的输出中:

      select e.employeeid, d.daydate
      from   employee e cross join ( select date '2017-08-01' + level - 1 as daydate
                                       from dual
                                       connect by level <= 7
                                   ) d
      where  (e.employeeid, d.daydate) not in (select employeeid, daydate from data_table)
      ;
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多