Counting null values between dates

拈花ヽ惹草 提交于 2021-01-29 03:37:35

问题


I'm trying to calculate the number of null values between dates.

My table looks like this:

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

I'm looking to get the following output:

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

回答1:


count(expression) does not count NULL values, be it as aggregate function or as window function. The manual:

number of input rows for which the value of expression is not null

This is the key element for a simple and fast query.

Assuming transaction_date is UNIQUE like your example suggests, or you'll have to define how to break ties between duplicate values. (An actual table definition would clarify.)

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;

Form groups in the subquery. Since every nonnull value starts a new group according to your definition, just count actual values in descending order in a window function to effectively assign a group number to every row. The rest is trivial.

In the outer SELECT, count the rows per group and display where transaction_sale IS NOT NULL. Fix off-by-1. Voilá.

Related:

  • Select longest continuous sequence

Alternatively, count with FILTER (WHERE transaction_sale IS NULL) - useful for related cases where we cannot simply subtract 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;

About the FILTER clause:

  • How can I simplify this game statistics query?

db<>fiddle here




回答2:


This doesn't make any assumptions about consecutive dates, etc.

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;

See a demo here. Although the demo is SQL Server it should work identically on your platform: https://rextester.com/GVR65084

Also see for PostgreSQL: http://sqlfiddle.com/#!15/07c85f/1




回答3:


If the dates are consecutive, you can use the following to get the previous date:

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;

If the difference is less than 12, you can use age() and 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



回答4:


If transaction date is a date field you can simply use:

select count(*) from Counter where transaction_date > date_lower and transaction_date < date_higher and tx_sale is null;


来源:https://stackoverflow.com/questions/58174638/counting-null-values-between-dates

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!