Подсчет нулевых значений между датами - PullRequest
1 голос
/ 30 сентября 2019

Я пытаюсь вычислить количество нулевых значений между датами.

Моя таблица выглядит следующим образом:

transaction_date    transaction_sale
10/1/2018           NULL
11/1/2018           33
12/1/2018           NULL
1/1/2019            NULL
2/1/2019            NULL
3/1/2019            2
4/1/2019            NULL
5/1/2019            NULL
6/1/2019            10

Я хочу получить следующий вывод:

transaction_date    transaction_sale   count
10/1/2018           NULL               NULL
11/1/2018           33                 1
12/1/2018           NULL               NULL
1/1/2019            NULL               NULL
2/1/2019            NULL               NULL
3/1/2019            2                  3
4/1/2019            NULL               NULL
5/1/2019            NULL               NULL
6/1/2019            10                 2

Ответы [ 4 ]

1 голос
/ 01 октября 2019

count(expression) не учитывает значения NULL, будь то агрегатная функция или оконная функция. Руководство:

количество строк ввода, для которых значение выражение не равно нулю

Это ключэлемент для простого и быстрого запроса.

Предполагается, что transaction_date равен UNIQUE, как показано в вашем примере, или вам придется определить, как разорвать связи между повторяющимися значениями. (Фактическое определение таблицы пояснит.)

SELECT transaction_date, transaction_sale
     , CASE WHEN transaction_sale IS NOT NULL
            THEN count(*) OVER (PARTITION BY grp) - 1
       END AS count 
FROM  (
   SELECT *
        , count(transaction_sale) OVER (ORDER BY transaction_date DESC) AS grp
   FROM   tbl
   ) sub
ORDER  BY transaction_date;

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

Во внешнем SELECT подсчитайте количество строк в группе и покажите, где transaction_sale IS NOT NULL. Фикс офф-1. Вуаля.

Связанные:

В качестве альтернативы , считайте с FILTER (WHERE transaction_sale IS NULL) - полезно в смежных случаях, когда мы не можем просто вычесть 1 :

SELECT transaction_date, transaction_sale
     , CASE WHEN transaction_sale IS NOT NULL
            THEN count(*) FILTER (WHERE transaction_sale IS NULL)
                          OVER (PARTITION BY grp)
       END AS count 
FROM  (
   SELECT *
        , count(transaction_sale) OVER (ORDER BY transaction_date DESC) AS grp
   FROM   tbl
   ) sub
ORDER  BY transaction_date;

О предложении FILTER:

db <> fiddle здесь

1 голос
/ 30 сентября 2019

Это не делает никаких предположений о последовательных датах и ​​т. Д.

with data as (
    select transaction_date, transaction_sale,
        count(transaction_sale)
            over (order by transaction_date desc) as grp
    from T /* replace with your table */
)
select transaction_date, transaction_sale,
    case when transaction_sale is null then null else
        count(case when transaction_sale is null then 1 end)
            over (partition by grp) end as "count"
from data
order by transaction_date;

См. Демонстрацию здесь. Несмотря на то, что демонстрационная версия - SQL Server, она должна работать одинаково на вашей платформе: https://rextester.com/GVR65084

Также смотрите PostgreSQL: http://sqlfiddle.com/#!15/07c85f/1

0 голосов
/ 30 сентября 2019

Если дата транзакции является полем даты, вы можете просто использовать:

select count(*) from Counter where transaction_date > date_lower and transaction_date < date_higher and tx_sale is null;
0 голосов
/ 30 сентября 2019

Если даты являются последовательными, вы можете использовать следующую информацию для получения предыдущей даты:

select t.*,
       max(transaction_date) filter where (transaction_sale is not null) over (order by transaction_date order by transaction date rows between unbounded preceding and 1 preceding)
from t;

Если разница меньше 12, вы можете использовать age() и extract():

select t.*,
       extract(month from
               age(max(transaction_date) filter where (transaction_sale is notnull)
                       over (order by transaction_date order by transaction date rows between unbounded preceding and 1 preceding
                            ), transaction_date
                   )
               ) as diff
...