Sql 用计算值枚举两个日期之间的年份

Sql 用计算值枚举两个日期之间的年份,sql,database,postgresql,view,generate-series,Sql,Database,Postgresql,View,Generate Series,我有一个postgres表,看起来像这样: proposal_id | nih_budget_start | nih_budget_end | nsf_start_date | nsf_end_date | award_amount proposal_A | 03/01/2000 | 12/31/2000 | | | 10,000 proposal_B | |

我有一个postgres表,看起来像这样:

proposal_id | nih_budget_start | nih_budget_end  | nsf_start_date | nsf_end_date   | award_amount
proposal_A  | 03/01/2000       | 12/31/2000      |                |                | 10,000
proposal_B  |                  |                 | 08/01/2005     | 07/31/2009     | 5,000,000
proposal_C  | 06/27/2012       | 11/17/2013      |                |                | 420,000
日期具有日期数据类型

我想创建一个视图,告诉我提案每年的资金来源,以及平均奖励金额是多少。因此,视图可能类似于选项1:

proposal_id | start_year | end_year | average_award
proposal_A  | 2000       | 2000     | 10,000
proposal_B  | 2005       | 2009     | 1,000,000 
proposal_C  | 2012       | 2013     | 210,000
或者——甚至更好——选择2:

proposal_id | year | award
proposal_A  | 2000 | 10,000
proposal_B  | 2005 | 1,000,000
proposal_B  | 2006 | 1,000,000
proposal_B  | 2007 | 1,000,000
proposal_B  | 2008 | 1,000,000
proposal_B  | 2009 | 1,000,000
proposal_C  | 2012 | 210,000
proposal_C  | 2023 | 210,000
此外,将奖励金额按比例分配给部分年度资金也不错,但这并非完全必要

根据以下建议的答案,我目前正在这样做,似乎按照预期的方式工作,以获得上述选项1:

CREATE VIEW award_per_year AS
select t1.proposal_id,t1.START_DATE,t1.END_DATE,
(t1.adjusted_award_amount/((t1.END_DATE - t1.START_DATE) + 1.)) avg_award
from
(select t2.proposal_id,
(extract(year from START_DATE)) START_DATE,
(extract(year from END_DATE)) END_DATE,
t2.adjusted_award_amount from
(select proposal_id,
case when nih_budget_start is not NULL then nih_budget_start else nsf_start_date end start_date,
case when nih_budget_end is not NULL then nih_budget_end else nsf_end_date end end_date,
adjusted_award_amount from proposal)t2)t1

从您的澄清来看,您最好得到如下列表:

proposal_ID | years_funded  | average_award
proposal_A  | 2000          | 10,000
proposal_B  | 2005          | 1,000,000
proposal_B  | 2006          | 1,000,000
proposal_B  | 2007          | 1,000,000
proposal_B  | 2008          | 1,000,000
proposal_B  | 2009          | 1,000,000
proposal_C  | 2012          | 210,000
proposal_C  | 2013          | 210,000
在前端,您可以使用此列表显示提案的年度资金。请确认

根据您的输入,这里有一个查询,可以实现您想要的第一个输出结果集:

SELECT proposal_id,
     TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY') AS start_year,
     TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY') AS end_year,
     award_amount/(TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY')::INT - TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY')::INT+1) AS average_award
FROM Proposals
以下查询可以使用递归CTE获得所需的第二个结果集:

WITH RECURSIVE dates AS
( 
     SELECT proposal_id,nih_budget_start,nsf_start_date,nih_budget_end,nsf_end_date, TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY')::INT  AS Dt,
     award_amount/(TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY')::INT - TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY')::INT+1) AS average_award
     FROM proposals
     UNION ALL
     SELECT proposal_id,nih_budget_start,nsf_start_date,nih_budget_end,nsf_end_date, d1.dt + 1, average_award FROM dates d1
     WHERE d1.dt < TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY')::INT 
 )
SELECT proposal_id, dt AS year, average_award  FROM dates d ORDER BY proposal_id,dt

从您的说明中可以看到位于

的代码,您最好获得如下列表:

proposal_ID | years_funded  | average_award
proposal_A  | 2000          | 10,000
proposal_B  | 2005          | 1,000,000
proposal_B  | 2006          | 1,000,000
proposal_B  | 2007          | 1,000,000
proposal_B  | 2008          | 1,000,000
proposal_B  | 2009          | 1,000,000
proposal_C  | 2012          | 210,000
proposal_C  | 2013          | 210,000
在前端,您可以使用此列表显示提案的年度资金。请确认

根据您的输入,这里有一个查询,可以实现您想要的第一个输出结果集:

SELECT proposal_id,
     TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY') AS start_year,
     TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY') AS end_year,
     award_amount/(TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY')::INT - TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY')::INT+1) AS average_award
FROM Proposals
以下查询可以使用递归CTE获得所需的第二个结果集:

WITH RECURSIVE dates AS
( 
     SELECT proposal_id,nih_budget_start,nsf_start_date,nih_budget_end,nsf_end_date, TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY')::INT  AS Dt,
     award_amount/(TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY')::INT - TO_CHAR(COALESCE(nih_budget_start, nsf_start_date),'YYYY')::INT+1) AS average_award
     FROM proposals
     UNION ALL
     SELECT proposal_id,nih_budget_start,nsf_start_date,nih_budget_end,nsf_end_date, d1.dt + 1, average_award FROM dates d1
     WHERE d1.dt < TO_CHAR(COALESCE(nih_budget_end, nsf_end_date),'YYYY')::INT 
 )
SELECT proposal_id, dt AS year, average_award  FROM dates d ORDER BY proposal_id,dt
请参见

处的代码,尝试此查询:

select t1.proposal_ID,t1.START_DATE,t1.END_DATE,
DIV(t1.award,(t1.END_DATE - t1.START_DATE + 1))award
from
(select t2.proposal_ID,
(substr(t2.START_DATE,7,4)::integer) START_DATE,
(substr(t2.END_DATE,7,4)::integer) END_DATE,
t2.award from
(select proposal_ID,
case when length(start_date1) = 10 then start_date1 else start_date2 end start_date,
case when length(end_date1) = 10 then end_date1 else end_date2 end end_date,
award from table1)t2)t1;
请尝试以下查询:

select t1.proposal_ID,t1.START_DATE,t1.END_DATE,
DIV(t1.award,(t1.END_DATE - t1.START_DATE + 1))award
from
(select t2.proposal_ID,
(substr(t2.START_DATE,7,4)::integer) START_DATE,
(substr(t2.END_DATE,7,4)::integer) END_DATE,
t2.award from
(select proposal_ID,
case when length(start_date1) = 10 then start_date1 else start_date2 end start_date,
case when length(end_date1) = 10 then end_date1 else end_date2 end end_date,
award from table1)t2)t1;
备选案文1:使用

备选案文2:使用

备选案文1:使用

备选案文2:使用


为什么需要阵列?为什么不仅仅是第一年和去年?或者类似的?我想画出提案获得资助的每一年的平均奖励金额。但是,我想我可以对数据库之外的年份进行枚举。我想那会更容易些。。。嗯。那么我想如果你把提案的年份作为行而不是逗号分隔的列表,那会更好,对吗?请重新思考为什么需要阵列?为什么不仅仅是第一年和去年?或者类似的?我想画出提案获得资助的每一年的平均奖励金额。但是,我想我可以对数据库之外的年份进行枚举。我想那会更容易些。。。嗯。那么我想如果你把提案的年份作为行而不是逗号分隔的列表,那会更好,对吗?请重新考虑是的。这样就好了。我更新了我的问题,以反映这一选择。谢谢好的,Gr8,我会尽快给你答案。这样就好了。我更新了我的问题,以反映这一选择。谢谢好的,Gr8,我会尝试给你一个解决方案,这看起来似乎是可行的,但它不起作用,因为我的日期有日期数据类型。只是缺少了'NaN'值,而不是字符串'NaN'。因此,我认为我应该能够使用extractyear from START_DATE来获取年份,尽管我不确定丢失值会发生什么。这看起来似乎有道理,但它不起作用,因为我的日期具有日期数据类型。只是缺少了'NaN'值,而不是字符串'NaN'。因此,我认为我应该能够使用extractyear from START_DATE来获取年份,尽管我不确定丢失值会发生什么。选项1非常有效!选项2给出了以下错误:错误:函数生成系列双精度,双精度不exist@ems:缺少对整数的强制转换。添加了小提琴来演示。@ems从Coaleschenih\u budget\u start,nsf\u start\u date::INT是必需的选项1非常有效!选项2给出了以下错误:错误:函数生成系列双精度,双精度不exist@ems:缺少对整数的强制转换。添加了小提琴来演示。@ems从Coaleschenih\u预算开始算起一年,nsf\u开始日期::INT是必需的