PostgreSQL创建每月天数表

3
我正在尝试编写一个脚本,返回一个包含每个月份天数的列表。它参考了这张表格。
 CREATE TABLE generic.time_series_only (measurementdatetime TIMESTAMP WITHOUT TIME ZONE NOT NULL)

这只是一个按时间顺序排列的时间序列(在连接具有不同位置中断的数据表时非常有用,但如果您想要输出连续的时间序列,则可能有更聪明的方法,但我尚未找到)。

SELECT date_part('year'::text, time_series_only.measurementdatetime) AS
    measyear,
         date_part('month'::text, time_series_only.measurementdatetime) AS
           measmonth,
         date_trunc('month'::text, time_series_only.measurementdatetime) +
           '1 mon'::interval - date_trunc('month'::text,
           time_series_only.measurementdatetime) AS days_in_month
  FROM generic.time_series_only
  GROUP BY date_part('year'::text, time_series_only.measurementdatetime),
           date_part('month'::text, time_series_only.measurementdatetime)
  ORDER BY date_part('year'::text, time_series_only.measurementdatetime),
           date_part('month'::text, time_series_only.measurementdatetime);

但是我遇到了这个错误:
  ERROR:  column "time_series_only.measurementdatetime" must appear in the GROUP BY clause or be used in an aggregate function

我不能将这一列放在GROUP BY子句中,因为这样我会得到time_series_only表中每个条目的结果,而我无法想出一种使用聚合函数得到相同结果的方法。有任何建议都非常欢迎 :-)

4个回答

2
你没有使用generate_series吗?就像这样:
vao=# with pre as (select generate_series('2016-01-01','2017-03-31','1 day'::interval) g) select distinct
extract('year' from g), extract('month' from g), count(1) over (partition by date_trunc('month',g)) from pre order by 1,2;
 date_part | date_part | count
-----------+-----------+-------
      2016 |         1 |    31
      2016 |         2 |    29
      2016 |         3 |    31
      2016 |         4 |    30
      2016 |         5 |    31
      2016 |         6 |    30
      2016 |         7 |    31
      2016 |         8 |    31
      2016 |         9 |    30
      2016 |        10 |    31
      2016 |        11 |    30
      2016 |        12 |    31
      2017 |         1 |    31
      2017 |         2 |    28
      2017 |         3 |    31
(15 rows)

2

使用 distinct on 对一对 (年份,月份) 进行去重。您可以使用函数 generate_series() 替换表格 time_series_only,例如:

select distinct on (date_part('year', d), date_part('month', d))
    date_part('year', d) as year, 
    date_part('month', d) as month, 
    date_part('day', d) as days_in_month
from 
    generate_series('2016-01-01'::date, '2016-12-31'::date, '1d'::interval) d
order by 1, 2, 3 desc;

 year | month | days_in_month 
------+-------+---------------
 2016 |     1 |            31
 2016 |     2 |            29
 2016 |     3 |            31
 2016 |     4 |            30
 2016 |     5 |            31
 2016 |     6 |            30
 2016 |     7 |            31
 2016 |     8 |            31
 2016 |     9 |            30
 2016 |    10 |            31
 2016 |    11 |            30
 2016 |    12 |            31
(12 rows)

1

这个更加高效,因为它只生成每个月的最后一天,因此不需要聚合:

select
    date_part('year', d) as year, 
    date_part('month', d) as month, 
    date_part('day', d) as days_in_month
from 
    generate_series('2016-01-01'::date, '2016-12-01', '1 month') gs(gsd)
    cross join lateral
    (select gsd + interval '1 month - 1 day') d(d)
order by 1, 2;

 year | month | days_in_month 
------+-------+---------------
 2016 |     1 |            31
 2016 |     2 |            29
 2016 |     3 |            31
 2016 |     4 |            30
 2016 |     5 |            31
 2016 |     6 |            30
 2016 |     7 |            31
 2016 |     8 |            31
 2016 |     9 |            30
 2016 |    10 |            31
 2016 |    11 |            30
 2016 |    12 |            31

0

另一种变化,使用CTEs使其更易读,在我看来(此示例生成当前日期日历月份后三个完整月的月份和数据)

WITH series AS (                                                                                                                                                   
  SELECT generate_series ( 
    date_trunc ('month', date_trunc('day', now()) + interval '1 month'), 
    date_trunc('day', now() + interval '4 months'), '1d'::interval
  ) AS day                                                                                                                                                                               )                                                                                                                                                                                 SELECT DISTINCT ON (date_part('year', series.day),     date_part('month', series.day))
  date_part('year', series.day) as year,
  date_part('month', series.day) as month,
  date_part('day', series.day) as days_in_month
FROM series
ORDER BY 1, 2, 3 desc LIMIT 3;

 year | month | days_in_month 
------+-------+---------------
 2021 |     1 |            31
 2021 |     2 |            28
 2021 |     3 |            31

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接