Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/postgresql/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL:范围内的天数总和_Sql_Postgresql - Fatal编程技术网

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,“[]))