Как выбрать первую и последнюю строки для каждого возвращенного набора - PullRequest
0 голосов
/ 05 августа 2020

У меня есть следующие данные, которые я хочу выбрать следующим образом: Как мне изменить запрос для выбора вывода, как показано ниже?

select primary_id, timestamp, secondary_id,... from tablename where 
timestamp <= to_timestamp('2020-07-29 00:00:00', 'YYYY-MM-DD HH24:MI:SS') and 
timestamp <  to_timestamp('2020-07-29 04:00:00', 'YYYY-MM-DD HH24:MI:SS') 
order by timestamp, secondary_id;
primary_id timestamp    secondary_id  attribute1  attribute2  ... -- I want to get
-------------------------------------------------------------------
1          2020/01/20   10            ...         ...         ... -- <- this
2          2020/02/28   10            ...         ...         ...
3          2020/03/01   10            ...         ...         ... -- <- and this
4          2020/04/08   20            ...         ...         ... -- <- this
5          2020/05/31   20            ...         ...         ...
6          2020/06/30   20            ...         ...         ...
7          2020/06/31   20            ...         ...         ...
8          2020/07/31   20            ...         ...         ... -- <- and this

Ответы [ 4 ]

3 голосов
/ 05 августа 2020

Вы можете использовать оконные функции для ранжирования записей, имеющих одинаковые secondary_id, по возрастанию и убыванию timestamp, а затем использовать эту информацию для фильтрации первой и последней записи в каждой группе:

select primary_id, timestamp, secondary_id, ... 
from (
    select 
        t.*, 
        row_number() over(partition by secondary_id order by timestamp asc ) rn_asc,
        row_number() over(partition by secondary_id order by timestamp desc) rn_desc
    from tablename t
    where 
            timestamp <= timestamp '2020-07-29 00:00:00'
        and timestamp <  timestamp '2020-07-29 04:00:00'
) t
where 1 in (rn_asc, rn_desc)
order by timestamp, secondary_id;

Обратите внимание, что вам не нужно to_timestamp() для преобразования этих буквальных строк: вместо этого вы можете использовать буквальные даты.

2 голосов
/ 05 августа 2020

Это также работает, когда значение secondary_id может повторяться в другой группе строк, он просто проверяет, отличается ли текущий идентификатор от предыдущей или следующей строки:

select *
from (
    select 
        t.*, 
        lag(secondary_id) over(order by timestamp asc ) lag_id,
        lead(secondary_id) over(order by timestamp asc) lead_id
    from tablename t
    where timestamp <= timestamp '2020-07-29 00:00:00'
      and timestamp <  timestamp '2020-07-29 04:00:00'
) t
where lag_id is null 
   or lead_id is null
   or lag_id <> secondary_id
   or lead_id <> secondary_id
order by timestamp, secondary_id;

Должно быть достаточно эффективным, поскольку для LEAD и LAG один и тот же ORDER BY.

0 голосов
/ 05 августа 2020

Вы можете использовать first_value и last_value . Это аналитические функции, которые можно использовать, как в демонстрации ниже.

with demo_data ( primary_id, secondary_id, timestamp)as
( select 1, 10, date '2020-01-01' from dual
  union all
  select 2 ,10, date '2020-01-28' from dual
  union all
  select 3, 10, date '2020-02-03' from dual
  union all
  select 4, 20, date '2020-03-02' from dual
  union all
  select 5, 20, date '2020-03-15' from dual
)
, grouped_data as
( select primary_id,
         secondary_id,
         timestamp,
         decode(first_value(primary_id) over(partition by secondary_id order by timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ), primary_id, 'Y', 'N') first_row_in_group,
         decode(last_value(primary_id) over(partition by secondary_id order by timestamp ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING), primary_id, 'Y', 'N') last_row_in_group
  from   demo_data
)
select primary_id, secondary_id, timestamp
from   grouped_data s
where  first_row_in_group = 'Y' or last_row_in_group = 'Y'
/
0 голосов
/ 05 августа 2020

Пожалуйста, используйте запрос ниже,

select primary_id, timestamp, secondary_id,... from
(select primary_id, timestamp, secondary_id,..., 
row_number() over (partition by secondary_id  order by timestamp) as rnk1,
row_number() over (partition by secondary_id  order by timestamp desc) as rnk2
from tablename where 
timestamp <= to_timestamp('2020-07-29 00:00:00', 'YYYY-MM-DD HH24:MI:SS') and 
timestamp <  to_timestamp('2020-07-29 04:00:00', 'YYYY-MM-DD HH24:MI:SS') ) qry
where rnk1=1 and rnk2 = 1
order by timestamp, secondary_id;
...