Ограничить результат запроса на основе значения поля

#sql #postgresql

#sql #postgresql

Вопрос:

У меня есть таблица account с остаточной структурой:

 | agg_type  | agg_id  | sequence | payload | is_snapshot | timestamp |
| "account" | "agg_1" | 1        | "..."   | false       | ...       |
| "account" | "agg_1" | 2        | "..."   | true        | ...       |
| "account" | "agg_1" | 3        | "..."   | false       | ...       |
| "account" | "agg_1" | 4        | "..."   | false       | ...       |
| "account" | "agg_1" | 5        | "..."   | false       | ...       |
| "account" | "agg_1" | 6        | "..."   | false       | ...       |
| "account" | "agg_1" | 7        | "..."   | true        | ...       |
| "account" | "agg_1" | 8        | "..."   | false       | ...       |
  

Мне нужно написать запрос, который извлечет все строки из этой таблицы, начиная с последнего моментального снимка конкретного агрегата. Например, в случае этой таблицы запрос вернул бы две последние строки (последовательности 7 и 8).

Я думаю, что запрос будет выглядеть примерно так

 SELECT * FROM account 
WHERE
  agg_type='account'
  AND agg_id='agg_1'
ORDER BY sequence ASC
LIMIT (???);
  

Это (???) часть, которую я не совсем уверен в том, как реализовать.

Obs:

  • Я использую Postgres, если это может как-то помочь.
  • Комбинация (agg_type, agg_id, sequence) является первичным ключом.

Комментарии:

1. Будете ли вы делать это для всех agg или для определенного каждый раз?

2. Для каждого из них каждый раз.

Ответ №1:

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

 SELECT * FROM account a
WHERE
  a.agg_type='account'
  AND a.agg_id='agg_1' 
  AND a.sequence >= 
    (SELECT MAX(sequence) FROM account b WHERE a.agg_type = b.agg_type AND a.agg_id = b. agg_id AND b.is_snapshot = true)
  

Если бы вы хотели выполнить их все, было бы понятнее записать это как join:

 SELECT a.* 
FROM 
  account a
  INNER JOIN
  (
    SELECT 
      agg_type, 
      agg_id, 
      MAX(sequence) as maxseq 
    FROM account b 
    GROUP BY agg_type, add_id
  ) maxes
  ON 
    a.agg_type = maxes.agg_type and
    maxes.agg_id = a.max_id and
    a.sequence >= maxes.maxseq
  

Это не значит, что мы не могли бы выполнить ни ту, ни другую задачу с любой формой (и внутренне postgres, вероятно, в любом случае выполнит их одинаково), но я всегда чувствовал, что использование объединения в качестве ограничения «здесь 10000 строк, и я хочу, чтобы только 2000 строк соответствовали критериям, установленным этими 1000 строками», наиболее четко мыслится в терминах блоков данных, которые соединяются вместе

Ответ №2:

С помощью AS ( ВЫБЕРИТЕ * ,row_number() поверх (разделение ПО типу.agg_type, ПОРЯДОК.agg_id В ПОРЯДКЕ.»SEQUENCE» DESC) rnk ИЗ учетной записи a ) ВЫБЕРИТЕ * ИЗ a, ГДЕ a.rnk <= 2;

Ответ №3:

Оконная функция может извлекать это для всех (agg_type, agg_id) комбинаций только с одной сортировкой:

 with mark as (
  select *, 
         bool_or(is_snapshot) over w as trail_true
    from account
  window w as (partition by agg_type, agg_id 
                   order by sequence
            rows between 1 following
                     and unbounded following)
)
select *
  from mark
 where not coalesce(trail_true, false)
 order by agg_type, agg_id, sequence