【问题标题】:Pick lowest row in a group选择组中的最低行
【发布时间】:2021-12-21 08:52:35
【问题描述】:

有 1 个表,其中所有这些记录都是为 1 名员工维护的。由于此表中还有一个列在此示例中未显示,因此该人对于甚至 1 个工作有多行,即工作 J1 有 2 行,工作 J2 有 3 行,工作 J1 再有 2 行,顺序和位置相同.该人从工作 J1 切换到 J2,然后再次切换到 J1,并且位置发生相同的变化。每当发生切换时,如何提取所需的行,因为当工作或位置发生变化时,我必须提取每行中最少的行。请帮帮我。

StDt              EdDt            Job       Location   Required_Rows
01-Jan-21      31-Jan-21        J1         L1          Y
01-Feb-21      30-Jun-21        J1         L1          N
01-Jul-21      30-Jul-21        J2         L1          Y
01-Aug-21      15-Aug-21        J2         L2          Y 
16-Aug-21      31-Aug-21        J2         L2          N
01-Sep-21      01-Nov-21        J1         L2          Y
02-Nov-21      31-Dec-21        J1         L1          Y

【问题讨论】:

  • 在这里创建您的架构并询问:db-fiddle.com
  • 请包含您的 Oracle 版本。不同的工具有不同的版本。另外:您真的有一张供单个员工使用的桌子吗?不适合所有员工?如果该表适用于所有员工,请在示例数据中显示 - 并说明您是需要查询单个员工 (where employee_id = :input_id) 还是需要一次性查询所有员工。

标签: sql oracle gaps-and-islands


【解决方案1】:

这是一种方法,假设表名为job_history,它有一个额外的列employee_id,您需要查询一次性为您提供所有员工的答案,并且您的Oracle版本至少为12.1:

select *
from   job_history
match_recognize(
  partition by employee_id
  order     by stdt
  all rows per match
  pattern   ( y {- n* -} )
  define    n as job = prev(job) and location = prev(location)
);

查询所做的只是根据您的定义将每一行“标记”(“分类”)为 Y 或 N,然后从输出中排除 N 行(pattern{- ... -} 的含义子句)。

如果您只需要一名员工,请添加 where 子句并删除 match_recognize 中的 partition by 子句,因为它不再需要。

【讨论】:

    【解决方案2】:

    几乎是您的previous question 的副本:

    从 Oracle 12 开始,您可以使用MATCH_RECOGNIZE

    SELECT *
    FROM   table_name
    MATCH_RECOGNIZE(
      ORDER BY stDt
      ALL ROWS PER MATCH
      PATTERN (same {- same* -})
      DEFINE
        same AS FIRST(job) = job AND FIRST(location) = location
    )
    

    对于早期版本,您可以使用LAG 解析函数:

    SELECT StDt,
           EdDt,
           Job,
           location
    FROM   (
      SELECT t.*,
             LAG(job) OVER (ORDER BY StDt) AS prev_job,
             LAG(location) OVER (ORDER BY StDt) AS prev_location
      FROM   table_name t
    )
    WHERE  prev_job IS NULL
    OR     prev_job != job
    OR     prev_location IS NULL
    OR     prev_location != location;
    

    其中,对于样本数据:

    CREATE TABLE table_name (StDt, EdDt, Job, Location) AS
    SELECT DATE '2021-01-01', DATE '2021-01-31', 'J1', 'L1' FROM DUAL UNION ALL
    SELECT DATE '2021-02-01', DATE '2021-06-30', 'J1', 'L1' FROM DUAL UNION ALL
    SELECT DATE '2021-07-01', DATE '2021-07-31', 'J2', 'L1' FROM DUAL UNION ALL
    SELECT DATE '2021-08-01', DATE '2021-08-15', 'J2', 'L2' FROM DUAL UNION ALL
    SELECT DATE '2021-08-16', DATE '2021-08-31', 'J2', 'L2' FROM DUAL UNION ALL
    SELECT DATE '2021-09-01', DATE '2021-11-01', 'J1', 'L2' FROM DUAL UNION ALL
    SELECT DATE '2021-11-01', DATE '2021-12-31', 'J1', 'L1' FROM DUAL
    

    两个输出:

    STDT EDDT JOB LOCATION
    2021-01-01 00:00:00 2021-01-31 00:00:00 J1 L1
    2021-07-01 00:00:00 2021-07-31 00:00:00 J2 L1
    2021-08-01 00:00:00 2021-08-15 00:00:00 J2 L2
    2021-09-01 00:00:00 2021-11-01 00:00:00 J1 L2
    2021-11-01 00:00:00 2021-12-31 00:00:00 J1 L1

    db小提琴here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-02-21
      • 2019-12-09
      • 1970-01-01
      • 2016-03-18
      • 2017-04-13
      • 2022-01-01
      • 2018-09-03
      相关资源
      最近更新 更多