Postgresql中,计算两个日期月份差值或年月日,实现Oracle中months_between、add_months的效果

该博客介绍了如何在PostgreSQL中创建与Oracle相似的months_between和add_months函数,用于计算年龄和日期操作。通过示例展示了函数的创建过程和使用方法,并提供了使用PostgreSQL内置函数age()的替代方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Oracle中存在months_between、add_months函数,用作计算年龄等,例如计算某个人的年龄:岁(age)-月(monthss)-天(days)

SELECT rowid,
       a.fidate,
       a.fbirth,
       trunc(months_between(fidate, fbirth) / 12) age,
       trunc(mod(months_between(fidate, fbirth), 12)) monthss,
       trunc(fidate -
             add_months(fbirth, trunc(months_between(fidate, fbirth)))) days
  from t_noentryquery a;

Oracle中调用,如下图:
在这里插入图片描述

为兼容Postgresql计算年龄等,以此来创建函数months_between

--入参为date类型
CREATE OR REPLACE FUNCTION months_between(date1 date, date2 date)
RETURNS "pg_catalog"."int4" AS $BODY$
DECLARE
v_res int;
begin
SELECT 12*EXTRACT(YEAR from age(date1,  date2))+EXTRACT(MONTH from age(date1, date2)) into v_res from dual;
RETURN v_res;
end;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;

--或者

--入参为 timestamp without time zone类型
CREATE OR REPLACE FUNCTION months_between(
	date1 timestamp without time zone,
	date2 timestamp without time zone)
    RETURNS integer
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
AS $BODY$
DECLARE
v_res int;
begin
SELECT 12*EXTRACT(YEAR from age(date1::date,  date2::date))+EXTRACT(MONTH from age(date1::date, date2::date)) into v_res from dual;
RETURN v_res;
end;
$BODY$;

为兼容Postgresql计算年龄等,以此来创建函数add_months

--入参为timestamp without time zone,numeric类型
create or replace function add_months(timestamp without time zone, numeric) returns timestamp as $$  
declare  
  i interval := ($2 || 'month');  
  d1 date := date(to_timestamp($1::text,'yyyy-mm') + interval '1 month' - interval '1 day');  
  d2 date := date($1);  
  res timestamp;  
begin  
  select case when d1=d2 then ((to_char($1+i+interval '1 month', 'yyyy-mm')||'-01')::date - 1) + $1::time else $1+i end into res;  
  return res;  
end;  
$$ language plpgsql strict; 

--或者

--入参为timestamp,numeric类型
create or replace function add_months(timestamp, numeric) returns timestamp as $$  
declare  
  i interval := ($2 || 'month');  
  d1 date := date(to_timestamp($1::text,'yyyy-mm') + interval '1 month' - interval '1 day');  
  d2 date := date($1);  
  res timestamp;  
begin  
  select case when d1=d2 then ((to_char($1+i+interval '1 month', 'yyyy-mm')||'-01')::date - 1) + $1::time else $1+i end into res;  
  return res;  
end;  
$$ language plpgsql strict; 

Postgresql中调用:

SELECT 
       a.fidate,
       a.fbirth,
       trunc(months_between(fidate, fbirth) / 12) age,
       trunc(mod(months_between(fidate, fbirth), 12)) monthss,
       trunc(fidate::date - add_months(fbirth,
         cast(trunc(months_between(fidate, fbirth)) as numeric))::date) days
  from t_noentryquery a;

如下图:
在这里插入图片描述

当然也可以用Postgresql中自带的函数age(),更加方便快捷

select age(fidate ::date, fbirth ::date), a.fidate, a.fbirth
  from T_NOENTRYQUERY a
 where a.fidate is not null
   and a.fbirth is not null

如下图:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值