【问题标题】:SQL query comparing rows inside table (Oracle DB)SQL查询比较表内的行(Oracle DB)
【发布时间】:2020-10-08 19:43:27
【问题描述】:

在 Oracle 数据库中,我有一个内容类似于以下内容的表:

Market_Intro_Date  Change_Date  Author
-------------------------------------------
   01.06.2025      10.07.2020   Meyer     *
   01.01.2025      30.06.2020   Harrin
   01.01.2025      01.05.2020   Floyd
   01.01.2025      15.04.2020   Peterson  *
   01.12.2024      20.03.2020   George
   01.12.2024      10.03.2020   Smith
   01.12.2024      15.01.2020   George    *
   01.01.2025      15.12.2019   Lee
   01.01.2025      01.11.2019   Alfonso
   01.01.2025      10.10.2019   Peterson  *
   01.07.2025      30.09.2019   Smith     *
   01.07.2024      20.09.2019   Lee
   01.07.2024      10.09.2019   Meyer     
   01.07.2024      01.05.2019   Smith     *

我需要一个 SQL 查询,该查询将返回市场引入日期的每次更改的第一次出现(最后用 * 标记)以及更改日期和作者。

所以查询的结果是:

Market_Intro_Date  Change_Date  Author
-------------------------------------------
   01.06.2025      10.07.2020   Meyer     
   01.01.2025      15.04.2020   Peterson  
   01.12.2024      15.01.2020   George    
   01.01.2025      10.10.2019   Peterson  
   01.07.2024      01.05.2019   Smith     

提前谢谢你

【问题讨论】:

  • 你为什么用“01.01.2025”和彼得森标记2行?看起来应该是 01.07.2025 30.09.2019 Smith 而不是 01.01.2025 15.04.2020 Peterson
  • 看起来彼得森的两行都应该在那里;但是否也应包括 01.07.2025/30.09.2019/Smith(并标有星号),还是该日期应该是 2024 年?
  • @SayanMalakshinov:有趣的不是每个市场引入日期的定义,而是变化发生的时间。
  • @AlexPoole:那是个错误。我纠正了它。谢谢你的提示!
  • 所以彼得森不应该出现两次,但史密斯应该出现?这就是我回答中的第一个查询所做的;但是为什么彼得森(仅)在您的输出中反对 15.04.2025 而不是 10.10.2024;顺便说一句,这与星号不匹配。我更不确定你到底想要什么。

标签: sql oracle plsql


【解决方案1】:

您可以使用聚合,扩展名为keep ... first

select Market_Intro_Date,
  min(Change_Date) as Change_Date,
  min(Author) keep (dense_rank first order by Change_Date) as Author
from your_table
group by Market_Intro_Date

MARKET_INTRO_DATE | CHANGE_DATE | AUTHOR  
:---------------- | :---------- | :-------
01-JUL-24         | 01-MAY-19   | Smith   
01-DEC-24         | 15-JAN-20   | George  
01-JAN-25         | 10-OCT-19   | Peterson
01-JUN-25         | 10-JUL-20   | Meyer   
01-JUL-25         | 30-SEP-19   | Smith   

Read more.


我错过了其中一个日期重复,所以这是一个差距和岛屿问题。 Tabibitosan救援:

select Market_Intro_Date,
  min(Change_Date) as Change_Date,
  min(Author) keep (dense_rank first order by Change_Date) as Author
from (
  select Market_Intro_Date, Change_Date, Author,
    row_number() over (partition by Market_Intro_Date order by Change_Date)
      - row_number() over (order by Change_Date) as grp
  from your_table
)
group by Market_Intro_Date, grp
order by Change_Date desc;

MARKET_INTRO_DATE | CHANGE_DATE | AUTHOR  
:---------------- | :---------- | :-------
01-JUN-25         | 10-JUL-20   | Meyer   
01-JAN-25         | 15-APR-20   | Peterson
01-DEC-24         | 15-JAN-20   | George  
01-JAN-25         | 10-OCT-19   | Peterson
01-JUL-25         | 30-SEP-19   | Smith   
01-JUL-24         | 01-MAY-19   | Smith   

db<>fiddle

Smith 也有第二行,但看起来是正确的;不确定您的示例数据是否遗漏了星号或 01.07.2025 是错字。

【讨论】:

    【解决方案2】:

    澄清后更新

    Match_recognize 通常比基于分析函数的旧 start_of_group 解决方案更快:

    select *
    from your_tab
    match_recognize (
       order by Change_Date
       measures
           first(Change_Date) as Change_Date,
           first(Market_Intro_Date) as Market_Intro_Date,
           first(Author     ) as Author     
       pattern (A B*)
       define
          b as Market_Intro_Date = prev(Market_Intro_Date)  and Change_Date>prev(Change_Date)
    )
    order by 1;
    

    您的测试数据的完整示例:

    with your_tab(Market_Intro_Date, Change_Date, Author) as (
       select to_date('01.06.2025','dd.mm.yyyy'), to_date('10.07.2020','dd.mm.yyyy'),   'Meyer   ' from dual union all
       select to_date('01.01.2025','dd.mm.yyyy'), to_date('30.06.2020','dd.mm.yyyy'),   'Harrin  ' from dual union all
       select to_date('01.01.2025','dd.mm.yyyy'), to_date('01.05.2020','dd.mm.yyyy'),   'Floyd   ' from dual union all
       select to_date('01.01.2025','dd.mm.yyyy'), to_date('15.04.2020','dd.mm.yyyy'),   'Peterson' from dual union all
       select to_date('01.12.2024','dd.mm.yyyy'), to_date('20.03.2020','dd.mm.yyyy'),   'George  ' from dual union all
       select to_date('01.12.2024','dd.mm.yyyy'), to_date('10.03.2020','dd.mm.yyyy'),   'Smith   ' from dual union all
       select to_date('01.12.2024','dd.mm.yyyy'), to_date('15.01.2020','dd.mm.yyyy'),   'George  ' from dual union all
       select to_date('01.01.2025','dd.mm.yyyy'), to_date('15.12.2019','dd.mm.yyyy'),   'Lee     ' from dual union all
       select to_date('01.01.2025','dd.mm.yyyy'), to_date('01.11.2019','dd.mm.yyyy'),   'Alfonso ' from dual union all
       select to_date('01.01.2025','dd.mm.yyyy'), to_date('10.10.2019','dd.mm.yyyy'),   'Peterson' from dual union all
       select to_date('01.07.2025','dd.mm.yyyy'), to_date('30.09.2019','dd.mm.yyyy'),   'Smith   ' from dual union all
       select to_date('01.07.2024','dd.mm.yyyy'), to_date('20.09.2019','dd.mm.yyyy'),   'Lee     ' from dual union all
       select to_date('01.07.2024','dd.mm.yyyy'), to_date('10.09.2019','dd.mm.yyyy'),   'Meyer   ' from dual union all
       select to_date('01.07.2024','dd.mm.yyyy'), to_date('01.05.2019','dd.mm.yyyy'),   'Smith   ' from dual
    )
    select *
    from your_tab
    match_recognize (
       order by Change_Date
       measures
           first(Change_Date) as Change_Date,
           first(Market_Intro_Date) as Market_Intro_Date,
           first(Author     ) as Author     
       pattern (A B*)
       define
          b as Market_Intro_Date = prev(Market_Intro_Date)  and Change_Date>prev(Change_Date)
    )
    order by 1;
    CHANGE_DATE         MARKET_INTRO_DATE   AUTHOR
    ------------------- ------------------- --------
    2019-05-01 00:00:00 2024-07-01 00:00:00 Smith
    2019-09-30 00:00:00 2025-07-01 00:00:00 Smith
    2019-10-10 00:00:00 2025-01-01 00:00:00 Peterson
    2020-01-15 00:00:00 2024-12-01 00:00:00 George
    2020-04-15 00:00:00 2025-01-01 00:00:00 Peterson
    2020-07-10 00:00:00 2025-06-01 00:00:00 Meyer
    

    【讨论】:

      【解决方案3】:

      这样的事情应该可以工作:

      select market_intro_date, change_date, replace(author,'    *','') author
      from table 
      where author like '%*%';
      

      【讨论】:

      • 我认为星号已添加到问题中的数据中以突出显示这些行,而不是实际在表中。虽然不完全清楚......但如果它们在那里,数量或空间会有所不同。
      • 我使用星号来标记输出条目。但除此之外,解决方案很棒;-)
      【解决方案4】:

      你可以使用not exists如下:

      Select t.*
        From your_table t
       Where not exists (select 1 from your_table tt
                          Where t.Market_Intro_Date = tt.Market_Intro_Date
                            And tt.changed_date < t.changed_date)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-12-09
        • 1970-01-01
        • 1970-01-01
        • 2021-03-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多