计算日期之间的空值

时间:2019-09-30 20:06:52

标签: sql postgresql window-functions gaps-and-islands

我正在尝试计算日期之间的空值数量。

我的桌子看起来像这样:

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 个答案:

答案 0 :(得分:1)

这不对连续日期等做任何假设。

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

答案 1 :(得分:1)

count( expression )不计算NULL值,无论是作为集合函数还是作为窗口函数。 The manual:

  

表达式的值不为空的输入行数

这是简单快速查询的关键元素。

假设您的示例建议transaction_dateUNIQUE,或者您必须定义如何打破重复值之间的联系。 (将阐明一个实际的表定义。)

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错误。 Voilá。

相关:

或者,用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 <>提琴here

答案 2 :(得分:0)

如果日期是连续的,则可以使用以下命令获取前一个日期:

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

答案 3 :(得分:0)

如果交易日期是日期字段,则可以简单地使用:

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