SQL выбрать все строки в группе после выполнения условия - PullRequest
1 голос
/ 25 марта 2020

Я хотел бы выбрать все строки для каждой группы после последнего выполнения условия для этой группы. На этот связанный вопрос есть ответ с использованием коррелированных подзапросов.

В моем случае у меня будут миллионы категорий и сотни миллионов / миллиардов строк. Есть ли способ добиться тех же результатов, используя более производительный запрос?

Вот пример. Условие - все строки (на группу) после последнего 0 в условном столбце.

category | timestamp |  condition 
--------------------------------------
   A     |     1     |     0 
   A     |     2     |     1 
   A     |     3     |     0 
   A     |     4     |     1
   A     |     5     |     1
   B     |     1     |     0 
   B     |     2     |     1
   B     |     3     |     1

Результат, который я хотел бы получить, -

category | timestamp |  condition 
--------------------------------------
   A     |     4     |     1
   A     |     5     |     1
   B     |     2     |     1
   B     |     3     |     1

Ответы [ 2 ]

1 голос
/ 25 марта 2020

Возможно, вы захотите попробовать оконные функции:

select category, timestamp, condition
from (
    select 
        t.*,
        min(condition) over(partition by category order by timestamp desc) min_cond
    from mytable t
) t
where min_cond = 1

Окно min() с предложением order by вычисляет минимальное значение condition для текущей и последующих строк одного и того же category: мы можем использовать его в качестве фильтра для удаления строк, для которых есть более свежая строка с 0.

По сравнению с подходом коррелированных подзапросов, преимущество использования оконных функций состоит в том, что он уменьшает количество сканов, необходимых на столе. Конечно, эти вычисления также имеют свою стоимость, поэтому вам нужно сравнить оба решения с вашими примерами данных.

1 голос
/ 25 марта 2020

Если вам нужно все после последнего 0, вы можете использовать оконные функции:

select t.*
from (select t.*,
             max(case when condition = 0 then timestamp end) over (partition by category) as max_timestamp_0
      from t
     ) t
where timestamp > max_timestamp_0 or
      max_timestamp_0 is null;

При индексе (category, condition, timestamp) коррелированная версия подзапроса также может работать довольно хорошо:

select t.*
from t
where t.timestamp > all (select t2.timestamp
                         from t t2
                         where t2.category = t.category and
                               t2.condition = 0
                        );
...