如何使用 Oracle 以年、月和日为单位获取年龄

Posted

技术标签:

【中文标题】如何使用 Oracle 以年、月和日为单位获取年龄【英文标题】:How to get age in years,months and days using Oracle 【发布时间】:2016-01-25 10:12:27 【问题描述】:

我正在尝试使用这种格式打印每个人的年龄:

例如:19 岁 8 个月 13 天。

我用谷歌搜索了很多,我注意到有一个特定的函数可以计算日期之间的差异DATEDIFF

但是 SQL*Plus 中不存在此功能,所以我继续尝试使用 MONTHS_BETWEEN() 和一些运算符。

我的尝试:

SELECT name , ' ' || 
    FLOOR(MONTHS_BETWEEN(to_date(SYSDATE),to_date(date_of_birth))/12)||' years ' ||  
    FLOOR(MOD(MONTHS_BETWEEN(to_date(SYSDATE),to_date(date_of_birth)),12)) || ' months ' || 
    FLOOR(MOD(MOD(MONTHS_BETWEEN(to_date(SYSDATE),to_date(date_of_birth)),12),4))|| ' days ' AS "Age"
FROM persons;

我的问题取决于日子。我不知道我应该如何计算天数,使用这个函数('尝试除以 4 或 30);我认为我的逻辑很糟糕,但我想不通,有什么想法吗?

【问题讨论】:

您应该在标签中添加“oracle” 我认为是同一个问题here 【参考方案1】:

与拉利特的答案非常相似,但您可以通过使用add_months 调整整个月的总差异来获得准确的天数,而无需假设每月 30 天:

select sysdate,
  hiredate,
  trunc(months_between(sysdate,hiredate) / 12) as years,
  trunc(months_between(sysdate,hiredate) -
    (trunc(months_between(sysdate,hiredate) / 12) * 12)) as months,
  trunc(sysdate)
    - add_months(hiredate, trunc(months_between(sysdate,hiredate))) as days
from emp;

SYSDATE    HIREDATE        YEARS     MONTHS       DAYS
---------- ---------- ---------- ---------- ----------
2015-10-26 1980-12-17         34         10          9
2015-10-26 1981-02-20         34          8          6
2015-10-26 1981-02-22         34          8          4
2015-10-26 1981-04-02         34          6         24
2015-10-26 1981-09-28         34          0         28
2015-10-26 1981-05-01         34          5         25
2015-10-26 1981-06-09         34          4         17
2015-10-26 1982-12-09         32         10         17
2015-10-26 1981-11-17         33         11          9
2015-10-26 1981-09-08         34          1         18
2015-10-26 1983-01-12         32          9         14
2015-10-26 1981-12-03         33         10         23
2015-10-26 1981-12-03         33         10         23
2015-10-26 1982-01-23         33          9          3

您可以通过反转计算来验证:

with tmp as (
    select trunc(sysdate) as today,
      hiredate,
      trunc(months_between(sysdate,hiredate) / 12) as years,
      trunc(months_between(sysdate,hiredate) -
        (trunc(months_between(sysdate,hiredate) / 12) * 12)) as months,
      trunc(sysdate)
        - add_months(hiredate, trunc(months_between(sysdate,hiredate))) as days
    from emp
)
select * from tmp
where today != add_months(hiredate, (12 * years) + months) + days;

no rows selected

【讨论】:

这正是我想要的。【参考方案2】:

根据 YEARSMONTHS 获取年龄很容易,但棘手的部分是 DAYS

如果您可以修复一个月中的天数,则可以在同一 SQL 中获取天数。例如,使用标准 SCOTT.EMP 表并假设每个月有 30 天:

SQL> SELECT SYSDATE,
  2        hiredate,
  3        TRUNC(months_between(SYSDATE,hiredate)/12) years,
  4        TRUNC(months_between(SYSDATE,hiredate)  -
  5        (TRUNC(months_between(SYSDATE,hiredate)/12)*12)) months,
  6        TRUNC((months_between(SYSDATE,hiredate) -
  7        TRUNC(months_between(SYSDATE,hiredate)))*30) days
  8  FROM emp;

SYSDATE    HIREDATE        YEARS     MONTHS       DAYS
---------- ---------- ---------- ---------- ----------
2015-10-26 1980-12-17         34         10          9
2015-10-26 1981-02-20         34          8          6
2015-10-26 1981-02-22         34          8          4
2015-10-26 1981-04-02         34          6         23
2015-10-26 1981-09-28         34          0         28
2015-10-26 1981-05-01         34          5         24
2015-10-26 1981-06-09         34          4         17
2015-10-26 1982-12-09         32         10         17
2015-10-26 1981-11-17         33         11          9
2015-10-26 1981-09-08         34          1         18
2015-10-26 1983-01-12         32          9         14
2015-10-26 1981-12-03         33         10         22
2015-10-26 1981-12-03         33         10         22
2015-10-26 1982-01-23         33          9          3

14 rows selected.

但是,请注意,并非每个月都有 30 天。因此,您无法获得天数的准确性。


更新

我错过了@Alex Poole 在他接受的答案中解释的整个月的差异。我会让这个答案让未来的读者了解计算天数时遗漏的部分。

修改这个:

TRUNC((months_between(SYSDATE,hiredate) -       
TRUNC(months_between(SYSDATE,hiredate)))*30) days

有了这个:

TRUNC(SYSDATE) - add_months(hiredate, TRUNC(months_between(sysdate,hiredate)))

【讨论】:

确实很棘手,我现在明白了。 当它没有给出准确的天数时,这怎么可能是一个被接受的答案 @Hogan 我不知道 OP 接受了我的回答,因为我个人希望 Alex 的回答被接受。我错过了天数计算。现在我想把它留给未来的读者更好地理解。如果我删除它,它会破坏流程。没关系,毕竟我们都在学习或分享。【参考方案3】:

语法:

SELECT 
  CONCAT(
    TIMESTAMPDIFF(YEAR, ?, NOW()),
    ' Years,',
    TIMESTAMPDIFF(MONTH, ?, NOW()) % 12,
    ' Months,',
    FLOOR(TIMESTAMPDIFF(DAY, ?, NOW()) % 30.4375),
    ' Days'
  ) AS age 
FROM
  DUAL
输入: 代替 '?'与出生日期。例如,'1994-07-08' 输出: 此查询将返回“X”年“Y”月和“Z”天的年龄。

【讨论】:

问题标记为 Oracle。此语法对 Oracle 无效。【参考方案4】:

另一种获取月份的简化方法是-

TRUNC(MOD(months_between(sysdate,hiredate),12)) AS months

【讨论】:

以上是关于如何使用 Oracle 以年、月和日为单位获取年龄的主要内容,如果未能解决你的问题,请参考以下文章

给定出生日期的年龄(以年为单位)

从python中的第周、月和日获取日期

如何将天数转换为年、月和日[重复]

如何将年、月和日列合并到单个日期时间列?

无论如何要更改日期输入字段中年、月和日分隔符 (/) 的占位符样式?

C#中年,月和日参数的不可表示的DateTime