SQL запрос сравнения строк внутри таблицы (Oracle DB) - PullRequest
0 голосов
/ 11 июля 2020

В 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     

Заранее спасибо

Ответы [ 4 ]

1 голос
/ 11 июля 2020

Обновлено после уточнения

Match_recognize обычно работает быстрее, чем старое решение start_of_group, основанное на аналитических c функциях:

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;

Full пример с вашими тестовыми данными:

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
1 голос
/ 11 июля 2020

Вы можете использовать агрегирование с расширением 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   

Подробнее .

Я пропустил, что одна из дат повторяется, так что это проблема с пробелами и островками. Табибитозан спешит на помощь:

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

Здесь также есть вторая строка для Смита, но это выглядит правильно; Не уверен, что в ваших данных выборки отсутствует звездочка или 01.07.2025 допущена опечатка.

0 голосов
/ 11 июля 2020

Вы можете использовать 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)
0 голосов
/ 11 июля 2020

Примерно так должно работать:

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