PostgreSQL:范围内的天数总和
我的表格如下:PostgreSQL:范围内的天数总和,sql,postgresql,Sql,Postgresql,我的表格如下: Table "public.fish_schedule" Column | Type | Collation | Nullable | Default --------+------------------------+-----------+----------+--------- name | character varying(255) | | not
Table "public.fish_schedule"
Column | Type | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
name | character varying(255) | | not null |
tr | timerange | | not null |
mr | int4range | | not null |
示例数据:
name | tr | mr
--------------+---------------------+--------
ray | [04:00:00,21:00:00) | [8,12)
moray eel | [00:00:00,24:00:00) | [8,11)
yellow perch | [00:00:00,24:00:00) | [1,4)
(3 rows)
字段mr
表示月份范围。我想加上总天数,例如从8月到10月的海鳗
到目前为止,我只成功地使下面的SQL正常工作,还不知道如何编写一个函数来完成我需要的任务
选择生成_系列(1,12)作为n,
生成_系列('2020-01-01':日期,'2020-12-01':日期,'1个月::间隔)+'1个月::间隔-生成_系列('2020-01-01':日期,'2020-12-01':日期,'1个月::间隔)作为m;
这是输出
n | m
----+---------
1 | 31 days
2 | 29 days
3 | 31 days
4 | 30 days
5 | 31 days
6 | 30 days
7 | 31 days
8 | 31 days
9 | 30 days
10 | 31 days
11 | 30 days
12 | 31 days
(12 rows)
因此,函数必须根据mr
字段中的范围将8月(31日)、9月(30日)和10月(31日)的天数相加
如有任何指导或指示,将不胜感激
更新:以下是好奇者的解决方案
WITH feeding(name, the_hours, start_schedule, end_schedule) AS
(SELECT name,
EXTRACT(HOUR FROM upper(tr)-lower(tr)),
make_date(extract(year from now())::int4,lower(mr),1)::timestamp,
make_date(extract(year from now())::int4,upper(mr)-1,1)::timestamp
+ interval '1 month' - interval '1 day'
from fish_schedule
)
SELECT name, SUM(the_hours * (EXTRACT (days from (end_schedule - start_schedule)) + 1)) "total_hours"
FROM feeding
GROUP by name
ORDER by total_hours;
要获取一年中的天数,可以执行以下操作:
select sum(d) from (
SELECT
date_part('month',generate_series) as n,
generate_series as startOfMonth,
date_trunc('month',generate_series) + '1 month'::interval - '1 day'::interval as endOfMonth,
date_part('days', date_trunc('month',generate_series) + '1 month'::interval - '1 day'::interval) as d
FROM generate_series('2020-01-01'::date,'2020-12-01'::date,'1 month'::interval)
) x
;
这将返回366天,内部查询将返回:
n | startofmonth | endofmonth | d
----+------------------------+------------------------+----
1 | 2020-01-01 00:00:00+01 | 2020-01-31 00:00:00+01 | 31
2 | 2020-02-01 00:00:00+01 | 2020-02-29 00:00:00+01 | 29
3 | 2020-03-01 00:00:00+01 | 2020-03-31 00:00:00+02 | 31
4 | 2020-04-01 00:00:00+02 | 2020-04-30 00:00:00+02 | 30
5 | 2020-05-01 00:00:00+02 | 2020-05-31 00:00:00+02 | 31
6 | 2020-06-01 00:00:00+02 | 2020-06-30 00:00:00+02 | 30
7 | 2020-07-01 00:00:00+02 | 2020-07-31 00:00:00+02 | 31
8 | 2020-08-01 00:00:00+02 | 2020-08-31 00:00:00+02 | 31
9 | 2020-09-01 00:00:00+02 | 2020-09-30 00:00:00+02 | 30
10 | 2020-10-01 00:00:00+02 | 2020-10-31 00:00:00+01 | 31
11 | 2020-11-01 00:00:00+01 | 2020-11-30 00:00:00+01 | 30
12 | 2020-12-01 00:00:00+01 | 2020-12-31 00:00:00+01 | 31
(12 rows)
我希望这确实有助于更改您的查询以获得正确的结果
SELECT
name,
to_date('2020-' || upper(mr) || '-01', 'yyyy-mm-dd')
- to_date ('2020-' || lower(mr) || '-01', 'yyyy-mm-dd')
FROM
fish_schedule;
在闰日你一定要小心吗?2020年是闰年。您不需要一个月内的天数,因为您在连续的时间范围内的任何给定行都需要天数。以下内容将MT列转换为时间戳,从CTE中范围下限值的第一天到范围上限值的最后一天。然后,主体部分从差异中提取天数
with feeding( name, start_schedule, end_schedule) as
( select name
, make_date(extract(year from now())::int4,lower(mr),1)::timestamp
, make_date(extract(year from now())::int4,upper(mr),1)::timestamp
+ interval '1 month' - interval '1 day'
from fish_schedule
)
select name, extract(days from (end_schedule - start_schedule)) + 1 "# of days"
from feeding;
注:这里有一点意见。“间隔‘1天’和在main中添加1可以消除,并且仍然可以产生相同的结果。我更清楚地看到上面的意图。但是没有它们会使查询稍微短一些,并且‘无限’快一些
另外,它还处理闰年的@Vesa点。如果您这样做:
从generate_series(1,3)中选择sum(generate_series);
您将从1+2+3中获得sum。因此您必须执行从generate_series中选择generate_series(…)
这将允许您计算天数。这是一个有用的注释,谢谢。是的,我正在尝试对mr
范围内的元素执行reduce
操作,其中mr
中的每个元素代表一个月。是的,我知道闰年问题,感谢您的注意。我正在使用PostgreSQL 12和代码nippet抛出以下错误:错误:日期字段值超出范围:2020-13-01
这是因为没有第13个月。完整的错误消息和数据值是什么。这是完整的错误消息。它似乎不像上限(mr)
因为它返回了范围的上限,而它应该是一个非包容性的限制。例如,[1,13)表示1到12个范围,而不是1到13。但是PostgreSQL将其存储为1到13个范围,非包容性。看起来像是一个输入数据错误。下面产生了什么。从fish_schedule中选择*其中上限(mr)>12;选择不同的上限(mr)从fish_schedule;检查MR列是如何创建的。可能创建的范围是:选择int4range(8,12,“[])Postgres将其转换为int4range(8,13,“[]))