当前位置: 首页 > news >正文

读书笔记:深入理解 Oracle 的 DATE 类型:存储、计算与最佳实践

我们的文章会在微信公众号IT民工的龙马人生和博客网站( www.htz.pw )同步更新 ,欢迎关注收藏,也欢迎大家转载,但是请在文章开始地方标注文章出处,谢谢!
由于博客中有大量代码,通过页面浏览效果更佳。

本文为个人学习《Expert Oracle Database Architecture Techniques and Solutions for High Performance and Productivity(第四版本》一书过程中的笔记与理解分享,仅用于学习与交流,部分内容参考原书观点并结合>实际经验进行整理。若涉及版权问题,请联系删除或沟通处理。也请大家支持购买原版书籍。

深入理解 Oracle 的 DATE 类型:存储、计算与最佳实践

Oracle 数据库中的 DATE 类型是一种功能强大且高效的日期时间数据类型。它不仅用于存储日期,还精确到秒级时间。本文将深入探讨其内部存储格式、如何进行日期运算,并提供实用的最佳实践建议。

1. DATE 类型的内部存储机制

DATE 是一种固定宽度、占用 7 个字节的数据类型。每个字节分别存储以下七个属性:

  • 字节 1:世纪 (Century)
  • 字节 2:年份 (Year)
  • 字节 3:月份 (Month)
  • 字节 4:日 (Day)
  • 字节 5:小时 (Hour)
  • 字节 6:分钟 (Minute)
  • 字节 7:秒 (Second)

Oracle 使用一种特殊的内部格式存储这些值,并非直接存储我们看到的数字。我们可以使用 DUMP 函数来查看其内部实际存储的值。

示例:查看内部存储

SQL> CREATE TABLE t (x DATE);
SQL> INSERT INTO t (x) VALUES (TO_DATE('25-jun-2005 12:01:00', 'dd-mon-yyyy hh24:mi:ss'));
SQL> SELECT x, DUMP(x, 10) AS d FROM t;X          D
--------- -----------------------------------
25-JUN-05 Typ=12 Len=7: 120,105,6,25,13,2,1

解码存储格式:

  • 世纪和年份 (120,105):采用“excess-100”表示法。计算方式为 字节值 - 100
    • 世纪: 120 - 100 = 20 (20世纪)
    • 年份: 105 - 100 = 5 (05年)
    • 如果结果为负数,则表示公元前(BC)日期。
  • 月份和日期 (6,25):直接存储,无需转换。6 代表六月,25 代表25日。
  • 时间部分 (13,2,1):采用“excess-1”表示法。计算方式为 字节值 - 1
    • 小时: 13 - 1 = 12
    • 分钟: 2 - 1 = 1
    • 秒: 1 - 1 = 0
    • 因此,1,1,1 代表午夜 00:00:00。

这种精巧的存储格式使得日期能够自然地按二进制顺序排序,并且截断操作(如截取到天或月)非常高效,只需将相应字节设置为 1 即可。

2. 给 DATE 类型加减时间

DATE 类型增加或减少时间单位主要有三种方法:

  1. 直接加数字DATE + nn 代表天数,因此 1 是一天,1/24 是一小时,1/24/60 是一分钟,依此类推。
  2. 使用 INTERVAL 数据类型:例如 NUMTODSINTERVAL(n, 'unit') 用于天/秒级单位,NUMTOYMINTERVAL(n, 'unit') 用于年月级单位。
  3. 使用内置函数ADD_MONTHS(date, n) 专门用于增加月份,能智能处理月末日期。

推荐的最佳实践:

  • 秒、分钟、小时:使用 NUMTODSINTERVAL(n, 'second'/'minute'/'hour')。代码更清晰易读。
    SELECT SYSDATE + NUMTODSINTERVAL(1, 'HOUR') FROM dual; -- 加1小时
    
  • 天、周:直接加数字。
    SELECT SYSDATE + 7 FROM dual; -- 加1周
    
  • 月、年强烈推荐使用 ADD_MONTHS(date, n)。它能正确处理月末等特殊情况,避免错误。

为什么不推荐用 INTERVAL 加月/年?
ADD_MONTHS 会对月末日期进行智能舍入,而直接加 INTERVAL 可能导致错误。

-- ADD_MONTHS 能正确处理月末
SELECT ADD_MONTHS(TO_DATE('29-FEB-2000', 'DD-MON-YYYY'), 1) FROM dual;
-- 结果: 31-MAR-2000 (返回下个月的最后一天)-- 使用 INTERVAL 可能出错
SELECT TO_DATE('30-JAN-2001', 'DD-MON-YYYY') + NUMTOYMINTERVAL(1, 'MONTH') FROM dual;
-- 错误: ORA-01839: 日期对指定的月份无效 (因为二月没有30号)

3. 计算两个 DATE 之间的差异

直接相减即可得到两个日期之间相差的天数(包括小数部分)。

SELECT (SYSDATE - hire_date) AS days_diff FROM employees;

要获取更直观的“年-月-日 时:分:秒”格式的差异,可以结合使用函数:

SELECTNUMTOYMINTERVAL(TRUNC(MONTHS_BETWEEN(dt2, dt1)), 'month') AS years_months,NUMTODSINTERVAL(dt2 - ADD_MONTHS(dt1, TRUNC(MONTHS_BETWEEN(dt2, dt1))),'day') AS days_hours
FROM (SELECTTO_DATE('29-feb-2000 01:02:03', 'dd-mon-yyyy hh24:mi:ss') AS dt1,TO_DATE('15-mar-2001 11:22:33', 'dd-mon-yyyy hh24:mi:ss') AS dt2FROM dual
);-- 结果示例:
-- YEARS_MONTHS: +000000001-00 (1年0个月)
-- DAYS_HOURS:   +000000015 10:20:30.000000000 (15天10小时20分30秒)

解释:

  1. MONTHS_BETWEEN(dt2, dt1) 计算两个日期之间总月数(含小数)。
  2. TRUNC(...) 取整,得到完整的月数。
  3. NUMTOYMINTERVAL(...) 将整月数转换为“年-月”间隔。
  4. dt2 - ADD_MONTHS(dt1, 整月数) 计算扣除整月后剩余的时间差。
  5. NUMTODSINTERVAL(...) 将剩余的时间差转换为“天 时:分:秒”间隔。

总结

  • 存储:Oracle DATE 使用 7 字节高效存储,格式精巧,支持自然排序和快速截断。
  • 运算
    • 加/减时间:使用 NUMTODSINTERVAL 处理小时/分钟/秒,直接加数字处理天,使用 ADD_MONTHS 处理月/年。
    • 避免使用 NUMTOYMINTERVAL 直接给日期加月份或年份,以免因月末日期导致错误。
  • 差异:日期相减得天数。组合 MONTHS_BETWEEN, ADD_MONTHS, NUMTOYMINTERVALNUMTODSINTERVAL 函数可以计算出精确的年、月、日、时、分、秒差。

遵循这些最佳实践,您将能更加准确和高效地在 Oracle 中处理日期和时间数据。

------------------作者介绍-----------------------
姓名:黄廷忠
个人博客: (http://www.htz.pw)
CSDN地址: (https://blog.csdn.net/wwwhtzpw)
博客园地址: (https://www.cnblogs.com/www-htz-pw)

http://www.gsyq.cn/news/20291.html

相关文章:

  • 零基础新手的以太坊质押(Staking)终极科普文章
  • 【开题答辩全过程】以 springboot+美食电子商城的设计与实现为例,含有答辩的问题和答案
  • 2025 年工业 X 光机厂家最新推荐排行榜:聚焦技术领先与市场认可的优质国内企业选购指南X光检查机/食品X光机/异物检测厂家推荐
  • linux 系统指标 简单监控 脚本
  • 2025 年最新推荐!国内优质流量计厂家综合实力推荐榜,助力企业精准选购可靠流量测量设备涡街/超声波/液体/气体/工业流量计厂家推荐
  • 秒杀系统的架构(Golang 实现) - Lafite
  • 实用指南:STM32 单片机开发 - FreeRTOS 实时操作系统
  • 10-6
  • 10-5
  • P11118 [ROI 2024] 无人机比赛 (Day 2) 题解
  • 基于遗传算法和粒子群优化在梁结构拓扑优化中的技术方案
  • Langchain+Neo4j+Agent 的结合案例-电商销售 - 详解
  • 如何用AI绘制程序时序图
  • # 这个函数对i1进行正则拆分, 返回列表. 跟re.split区别是他保留分隔符.
  • 老版本 EasyExcel 一个神出鬼没的异常 - 教程
  • 2025 年粮库空调厂家最新推荐榜:聚焦技术创新与实用适配,助力粮库精准选购优质设备粮库空调一体机/粮库空调机组/碳钢喷塑粮库空调/低温粮库空调厂家推荐
  • 2025年GEO(AI搜索优化)源头厂家权威推荐榜单:云视有客科技领跑行业新纪元
  • 2025年GEO服务商口碑推荐榜单:顶尖AI搜索优化厂家全方位解析
  • 2025 年油气回收设备厂家最新推荐排行榜:加油站 / 油库 / 码头 / 化工厂适用优质品牌精选
  • Vue3 + OpenLayers + 天地图 简单集成
  • 2025 年万能试验机厂家最新推荐排行榜:涵盖电子 / 液压 / 拉力 / 压力 / 冲击等类型,助力企业科研机构精准选购优质设备
  • 2025 年涡流分离器源头厂家最新推荐排行榜:聚焦国内优质企业,助力制造企业精准采购可靠分离设备旋转分配器/油路分配器/离心过滤器厂家推荐
  • 为了这0.1 dB,他在实验室蹲了整整8年
  • 有范同城全民任务小程序管理系统:连接厂家与播主的高效协作平台
  • axi_ad9361_rx.v
  • 2025年GEO(AI搜索优化)公司口碑推荐排行榜单
  • ​个人微信机器人开发
  • CSS学习日记
  • 2025中国不锈钢反应釜厂家TOP5权威推荐(附技术参数对比)
  • 中电金信 :源启数据建模平台:自定义功能上线,实现高效模型管理