【问题标题】:SQL Query to find the first occurence of the date changeSQL 查询查找第一次发生的日期更改
【发布时间】:2022-01-09 12:39:46
【问题描述】:

我已更改问题以使其更易于理解

我创建了一个查询来获取以下带有日期的输出:

PERSON_nUMBER  base_element_name  effective_start_date  effective_end_date  Value   
           11  Health             2021-11-21            4712-12-31            5.5
           11  Health             2021-10-18            2021-11-20            5.5
           12  Health             2021-11-11            4712-12-31              0
           12  Health             2021-11-01            2021-11-10            5.5
           13  Health             2021-11-01            2021-11-09            6
           
           14 Health              2021-11-10            2021-11-19            6
           14  Health             2021-11-20            2021-11-30            6
           14  Health             2021-12-01            2021-12-05            5
           14  Health             2021-12-06            4712-12-31            5
           
           
           15  Health             2021-11-10           2021-11-19           6
           15  Health             2021-11-20            2021-11-30           6
           15  Health             2021-12-01            2021-12-05           6
           15  Health              2021-12-06            2021-12-15           5
           15  Health              2021-12-16            4712-12-31           5

       
       

我将参数传递为 01-11-2021 和 30-11-2021

select 
    petf.person_number
    petf.base_element_name,
    to_char(peef.effective_start_date,'YYYY-MM-DD') effective_start_date ,
     to_char(peef.effective_end_date,'YYYY-MM-DD') effective_end_date,
     pivf.value  
    from pay_element_types_f petf ,
    pay_input_values_f pivf,
    per_all_elementries_f peef
    where pivf.element_type_id = petf.element_type_id
    AND petf.base_element_name in ('Health')
    and peef.element_entry_id= pivf.element_entry_id
    and peef.effective_start_date between :from_date and :to_date

如何调整上述查询,以便如果值列(如 person_number 12)发生变化,那么这两行应该输出;如果同一员工的两行内没有变化,例如 person_number 11,则只应选择最新的行。

预期的输出是 -

PERSON_nUMBER  base_element_name  effective_start_date    Value   
           11  Health             2021-11-21               5.5
           12  ~Health            2021-11-11               0
           12  Health             2021-11-01              5.5
           13  Health             2021-11-01               6
           14  Health             2021-11-10               6 
           14  ~Health             2021-12-01               5
           15  Health             2021-11-10               6
           15  ~Health             2021-12-06               5

    

案例

  1. 如果 person_number 12 的值从 5.5 变为 0,那么这两行都应该出现,并且最新的一个 base_element_name 应该添加“~”。
  2. 如果仅向员工标记了一次健康并且是结束日期,则应仅显示该行。
  3. 如果日期范围内的值没有变化,那么最新的行应该是 example-11
  4. 对于 person#14 和 15 ,第一个生效开始日期应该是“最新”更改或最后更改值的第一次出现生效开始日期

【问题讨论】:

    标签: sql oracle oracle-sqldeveloper


    【解决方案1】:

    只需对您的查询进行排名以显示 2 个最新日期,然后将 ~ 添加到第 2 个最新日期。希望这会有所帮助。

    WITH CTE AS(
    select 
        petf.person_number
        petf.base_element_name,
        to_char(peef.effective_start_date,'YYYY-MM-DD') effective_start_date ,
         to_char(peef.effective_end_date,'YYYY-MM-DD') effective_end_date,
         pivf.value  
        ,RANK() OVER(PARTITION BY petf.person_number ORDER BY peef.effective_start_date desc) as my_rank --Add Rank  to Get the 2 latest date.
        from pay_element_types_f petf ,
        pay_input_values_f pivf,
        per_all_elementries_f peef
        where pivf.element_type_id = petf.element_type_id
        AND petf.base_element_name in ('Health')
        and peef.element_entry_id= pivf.element_entry_id
        and peef.effective_start_date between :from_date and :to_date
    )
    
    SELECT 
    person_number
    ,CASE WHEN my_rank = 2 THEN CONCAT('~',base_element_name) ELSE base_element_name END as base_element_name
    ,effective_start_date
    ,Value
    FROM CTE
    WHERE my_rank in (1,2)
    

    【讨论】:

    • 这只是为了#1?当这种情况像 #4​​ 时会发生什么......那么这个排名不会正常工作?
    • 对不起。我无法完全阅读#4。但是你可以有2个等级。 1 用于降序日期,另一个用于升序日期。对于 Ascending,将 RANK 1 作为您的 Start Date 对于 Descending,将 RANK 1 作为您的 Latest_Date。
    • 虽然这给了我最新的日期,但它没有检查价值是否有变化。如果只有更改,我们需要添加 ~
    【解决方案2】:

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

    SELECT person_number,
           CASE cls WHEN 'CHANGED' THEN '~' END || base_element_name
             AS base_element_name,
           effective_start_date,
           effective_end_date,
           value
    FROM   (
      SELECT *
      FROM   your_query
      -- Without date filter
    )
    MATCH_RECOGNIZE (
      PARTITION BY person_number
      ORDER     BY effective_start_date
      MEASURES
        CLASSIFIER() AS cls
      ALL ROWS PER MATCH
      PATTERN (first_row (changed | {- outside_range -} | $))
      DEFINE
       first_row     AS effective_start_date <  :to_date + INTERVAL '1' DAY
                    AND effective_end_date   >= :from_date,
       changed       AS value != first_row.value,
       outside_range AS effective_start_date >= :to_date + INTERVAL '1' DAY
    );
    

    其中,对于样本数据:

    CREATE TABLE your_query (
      PERSON_NUMBER,
      base_element_name,
      effective_start_date,
      effective_end_date,
      Value
    ) AS
    SELECT 11, 'Health', DATE '2021-11-21', DATE '4712-12-31', 5.5 FROM DUAL UNION ALL
    SELECT 11, 'Health', DATE '2021-10-18', DATE '2021-11-20', 5.5 FROM DUAL UNION ALL
    SELECT 12, 'Health', DATE '2021-11-11', DATE '4712-12-31', 0.0 FROM DUAL UNION ALL
    SELECT 12, 'Health', DATE '2021-11-01', DATE '2021-11-10', 5.5 FROM DUAL UNION ALL
    SELECT 13, 'Health', DATE '2021-11-01', DATE '2021-11-09', 6.0 FROM DUAL UNION ALL
    SELECT 14, 'Health', DATE '2021-11-10', DATE '2021-11-19', 6.0 FROM DUAL UNION ALL
    SELECT 14, 'Health', DATE '2021-11-20', DATE '2021-11-30', 6.0 FROM DUAL UNION ALL
    SELECT 14, 'Health', DATE '2021-12-01', DATE '2021-12-05', 5.0 FROM DUAL UNION ALL
    SELECT 14, 'Health', DATE '2021-12-06', DATE '4712-12-31', 5.0 FROM DUAL UNION ALL
    SELECT 15, 'Health', DATE '2021-11-10', DATE '2021-11-19', 6.0 FROM DUAL UNION ALL
    SELECT 15, 'Health', DATE '2021-11-20', DATE '2021-11-30', 6.0 FROM DUAL UNION ALL
    SELECT 15, 'Health', DATE '2021-12-01', DATE '2021-12-05', 6.0 FROM DUAL UNION ALL
    SELECT 15, 'Health', DATE '2021-12-06', DATE '2021-12-15', 5.0 FROM DUAL UNION ALL
    SELECT 15, 'Health', DATE '2021-12-16', DATE '4712-12-31', 5.0 FROM DUAL UNION ALL
    SELECT 16, 'Health', DATE '2021-10-16', DATE '2021-11-15', 4.0 FROM DUAL UNION ALL
    SELECT 16, 'Health', DATE '2021-11-16', DATE '4712-12-31', 5.0 FROM DUAL;
    

    (其中包括第 16 个人,其中第一行的 effective_start_date 在范围开始之前,但更改发生在范围内。)

    输出:

    PERSON_NUMBER BASE_ELEMENT_NAME EFFECTIVE_START_DATE EFFECTIVE_END_DATE VALUE
    11 Health 2021-11-21 00:00:00 4712-12-31 00:00:00 5.5
    12 Health 2021-11-01 00:00:00 2021-11-10 00:00:00 5.5
    12 ~Health 2021-11-11 00:00:00 4712-12-31 00:00:00 0
    13 Health 2021-11-01 00:00:00 2021-11-09 00:00:00 6
    14 Health 2021-11-20 00:00:00 2021-11-30 00:00:00 6
    14 ~Health 2021-12-01 00:00:00 2021-12-05 00:00:00 5
    15 Health 2021-11-20 00:00:00 2021-11-30 00:00:00 6
    16 Health 2021-10-16 00:00:00 2021-11-15 00:00:00 4
    16 ~Health 2021-11-16 00:00:00 4712-12-31 00:00:00 5

    db小提琴here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-25
      • 2019-12-06
      • 1970-01-01
      • 2010-12-08
      • 2016-04-05
      • 2018-07-25
      • 1970-01-01
      相关资源
      最近更新 更多