Postgresql group month wise with missing values

后端 未结 3 667
无人共我
无人共我 2020-12-21 06:34

first an example of my table:

id_object;time;value;status
1;2014-05-22 09:30:00;1234;1
1;2014-05-22 09:31:00;2341;2
1;2014-05-22 09:32:00;1234;1
...
1;2014-0         


        
相关标签:
3条回答
  • 2020-12-21 06:35

    you can use generate_series() function like this:

    select
        g.month,
        count(m)
    from generate_series(1, 12) as g(month)
        left outer join my_table as m on
            m.id_object = 1 and
            m.status = 1 and
            extract(year from m.time) = 2014 and
            extract(month from m.time) = g.month
    group by g.month
    order by g.month
    

    sql fiddle demo

    0 讨论(0)
  • 2020-12-21 06:41

    Rather than comparing with an extracted value, you'll want to use a range-table instead. Something that looks like this:

    month  startOfMonth  nextMonth
    1      '2014-01-01'  '2014-02-01'
    2      '2014-02-01'  '2014-03-01'
    ......
    12     '2014-12-01'  '2015-01-01'
    

    As in @Roman's answer, we'll start with generate_series(), this time using it to generate the range table:

    WITH Month_Range AS (SELECT EXTRACT(MONTH FROM month) AS month, 
                                month AS startOfMonth,
                                month + INTERVAL '1 MONTH' AS nextMonth
                         FROM generate_series(CAST('2014-01-01' AS DATE),
                                              CAST('2014-12-01' AS DATE),
                                              INTERVAL '1 month') AS mr(month))
    SELECT Month_Range.month, COUNT(My_Table) 
    FROM Month_Range
    LEFT JOIN My_Table
           ON My_Table.time >= Month_Range.startOfMonth
              AND My_Table.time < Month_Range.nextMonth
              AND my_table.id_object = 1
              AND my_table.status = 1
    GROUP BY Month_Range.month
    ORDER BY Month_Range.month
    

    (As a side note, I'm now annoyed at how PostgreSQL handles intervals)

    SQL Fiddle Demo

    The use of the range will allow any index including My_Table.time to be used (although not if an index was built over an EXTRACTed column.

    EDIT:

    Modified query to take advantage of the fact that generate_series(...) will also handle date/time series.

    0 讨论(0)
  • 2020-12-21 06:51

    generate_series can generate timestamp series

    select
        g.month,
        count(t)
    from
        generate_series(
            (select date_trunc('year', min(t.time)) from t),
            (select date_trunc('year', max(t.time)) + interval '11 months' from t),
            interval '1 month'
        ) as g(month)
        left outer join
        t on
            t.id_object = 1 and
            t.status = 1 and
            date_trunc('month', t.time) = g.month
    where date_trunc('year', g.month) = '2014-01-01'::date
    group by g.month
    order by g.month
    
    0 讨论(0)
提交回复
热议问题