填充数组交叉表中的缺失数据

filling missing data in array crosstab

如何将数据汇总到数组中,才不会遗漏数据 例如我要查询所有注册用户从一月到十二月的年度报告:

    with s_table as (

    SELECT
     city,
     gs.mounth as month,
     coalesce(count(city),0) as count
    FROM
     generate_series('2017-01-01'::date, '2017-12-31'::date , interval '1 month') as gs(mounth)
    LEFT JOIN "user"
        ON to_char("user".datereg, 'YYYY-MM') = to_char(gs.mounth::date, 'YYYY-MM')
    GROUP BY city, gs.mounth
)
    select city,
    array_agg(count) as count
    from s_table
    group by s_table.city
    order by s_table.city;

它 returns 缺少数据:

|City  |arr_agg|
|Dublin|{1}|               //ONLY DECEMBER IS FILLED!
|Berlin|{1,4,5,10}            //ONLY JAN,MAR,APR,OCT ARE FILLED!

期待结果

    |City  |       Count users        |
    |Dublin|{0,0,0,0,0,0,0,0,0,0,0,1} |
    |Berlin|{1,0,4,5,0,0,0,0,0,10,0,0}|

如何用'0'填充缺失的数据?

您需要为所有城市生成所有月份。要获取行,请考虑 cross join:

with s_table as (
      select c.city, gs.month as month,
             count(u.city) as count
      from generate_series('2017-01-01'::date, '2017-12-31'::date , interval '1 month') as gs(month) cross join
           (select distinct u.city from user u) c left join
           "user" u
           on date_trunc('month', u.datereg,) = date_trunc(gs.month::date) and
              u.city = c.city
        group by c.city, gs.month
       )
select city, array_agg(count order by month) as count
from s_table
group by s_table.city
order by s_table.city;

注意答案中的其他变化:

  • 日期比较使用日期函数而不是字符串。
  • array_agg() 有一个 order by
  • 无需将 generate_series() 的结果转换为日期。
  • count() 没有 return NULL,所以 coalese() 是不必要的。