作者:胖头鱼的鱼缸(尹海文) Oracle ACE Pro: Database PostgreSQL ACE 10年+数据库行业经验 拥有OCM 11g/12c/19c、MySQL 8.0 OCP、Exadata、CDP等认证 墨天轮MVP,ITPUB认证专家 圈内拥有“总监”称号,非著 名社恐(社交恐怖分子) 全网同名:胖头鱼的鱼缸 ITPUB:yhw1809 除授权转载并标明出处外,均为“非法”抄袭

前面写过 DATEDIFF 函数,用来计算两个日期之间的差。接着这个话题,本期看看 Oracle AI Database 23.26.3 引入的 DATEADD:给一个日期或时间戳,加上或者减去指定的时间。
Oracle 原来当然也能做日期计算,按天加减、用 ADD_MONTHS 处理月份、通过 INTERVAL 处理时分秒,都有相应写法。DATEADD 的方便之处,是把这些计算放进了同一种调用形式里。不过, 调用形式更统一,不代表所有行为都和原来的函数相同,尤其要留意月末。
DATEADD 接收时间单位、数量和日期时间值,返回计算后的日期时间。数量为负数时,向前计算;数量为正数时,向后计算。
它支持 DATE、TIMESTAMP,以及带时区的时间戳类型,返回类型与输入的日期时间类型一致。
DATEADD(time_unit, value, datetime)
| 参数 | 说明 |
|---|---|
| time_unit | 时间单位,可以直接写关键字,也可以传入运行时的字符值 |
| value | 增减的数量,本期演示全部使用整数 |
| datetime | 要计算的 DATE 或 TIMESTAMP 等日期时间值 |
支持的单位包括 YEAR、QUARTER、MONTH、WEEK、DAY、HOUR、MINUTE、SECOND、MILLISECOND、MICROSECOND 和 NANOSECOND。
DATE 不保存小数秒。传入 DATE,再增加毫秒,不会因此得到带毫秒的结果;要处理小数秒,应该使用相应精度的 TIMESTAMP。
月末行为也不能照搬 ADD_MONTHS。后面的测试会用同一个日期比较两种函数,已有业务如果依赖“月底加一个月仍然是月底”,替换前就得检查。
在本次环境中,DATEADD 可以在 SQL 中执行;直接把它写进 PL/SQL 的条件表达式会报未声明。如果要在 PL/SQL 中使用本期写法,可以通过
SELECT ... INTO 取得结果。
同之前一样,使用用户NFTEST,已授权DB_DEVELOPER_ROLE角色,测试操作均在NFTEST用户下执行。
先设置日期显示格式,避免结果只显示年月日,看不到时分秒。
alter session set nls_date_format='YYYY-MM-DD HH24:MI:SS';
select dateadd(day, 7, date '2026-07-01') as after_7_days, dateadd(minute, -15, date '2026-07-01' + 10/24) as before_15_min from dual;
两个结果分别是
2026-07-08 00:00:00 和
2026-07-01 09:45:00。第二个表达式先构造当天 10 点,再减去 15 分钟。
select to_char( dateadd(millisecond, 125, timestamp '2026-07-01 10:00:00.123456789'), 'YYYY-MM-DD HH24:MI:SS.FF9') as ts_plus_125ms from dual;
结果是
2026-07-01 10:00:00.248456789,增加了 125 毫秒。
换成 DATE 再试一次:
select to_char( dateadd(millisecond, 125, date '2026-07-01'), 'YYYY-MM-DD HH24:MI:SS') as date_plus_125ms from dual;
结果仍是
2026-07-01 00:00:00。函数返回的还是 DATE,它并没有保存小数秒的能力。
select to_char( dateadd(month, 1, date '2026-02-28'), 'YYYY-MM-DD') as dateadd_result, to_char( add_months(date '2026-02-28', 1), 'YYYY-MM-DD') as add_months_result from dual;
2026 年 2 月 28 日是月底,ADD_MONTHS 延续了月底规则;DATEADD 在这个例子里保留了 28 日。
计算合同到期日、账期时,这个差别可能直接改变业务结果,不能把两个函数当成完全等价的替换。
下面用三笔订单演示按行计算有效期。时间固定写在 SQL 里,方便以后重做时对照结果。
create table nft263_da_order ( order_id number primary key, created_at timestamp(9), valid_minutes number); insert into nft263_da_ordervalues (1, timestamp '2026-07-01 10:00:00', 30); insert into nft263_da_ordervalues (2, timestamp '2026-07-01 11:45:00', 15); insert into nft263_da_ordervalues (3, timestamp '2026-07-01 12:30:00', 60); commit;

select order_id, to_char(created_at, 'YYYY-MM-DD HH24:MI:SS') as created_time, valid_minutes, to_char(dateadd(minute, valid_minutes, created_at), 'YYYY-MM-DD HH24:MI:SS') as expires_at from nft263_da_order order by order_id;
三笔订单的到期时间分别是 10:30、12:00、13:30。这里增减的数量来自列值,不需要为每一种有效期写一套表达式。
以当天 12 点为检查时间,包含恰好到期的订单:
select order_id from nft263_da_order where dateadd(minute, valid_minutes, created_at) <= timestamp '2026-07-01 12:00:00' order by order_id;
返回订单 1 和 2。这里验证的是筛选结果,不涉及索引或性能比较(要用于大表,还需要结合实际查询检查执行计划)。
variable time_unit varchar2(12) exec :time_unit := 'WEEK'; select to_char( dateadd(:time_unit, 2, date '2026-07-01'), 'YYYY-MM-DD') as after_2_weeks from dual;
结果为
2026-07-15。时间单位既能直接写在 SQL 中,也可以在执行时通过字符值传入。
本期演示了 Oracle AI Database 23.26.3 引入的 DATEADD 函数,从简单的日期加减,到小数秒、按行计算和条件筛选,都可以使用同一种调用形式。
我觉得它比较实用的地方,是写日期增减时少了几种不同的表达方式。但 数据类型和月末规则仍然要按实际业务检查,尤其不能因为函数名字熟悉,就直接替换原有逻辑。
老规矩,知道写了些啥。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31466763/viewspace-3188999/ ,如需转载,请注明出处,否则将追究法律责任。