【发布时间】:2018-07-23 05:20:06
【问题描述】:
我经常看到有人认为DATEDIFF(YEAR, date_of_birth, GETDATE()) 会产生此人的当前年龄。
很遗憾,这是不正确的。 DATEDIFF 函数,至少在 SQL Server 中,不计算两个日期之间的完整年数 - 它计算跨越的日历边界的数量。
也就是说,在 YEAR 参数的情况下,DATEDIFF 计算 1-Januaries 越过的次数。使用MONTH 参数,它将计算当月的第一天数。
因此,例如,17 年 12 月 31 日出生的婴儿已经“1 岁”,而实际上他们要到 18 年 12 月 31 日才满 1 岁,而他们目前是 0 岁。
这样使用DATEDIFF函数就相当于写YEAR(GETDATE()) - YEAR(date_of_birth),当然没有考虑人的生日在一年中的哪个位置。
在这里查看了其他问题的一个很好的样本,似乎没有一个确定的答案,而且有很多答案是完全错误的。
所以我的问题是,给定一个人的出生日期和参考日期,计算一个人截至该参考日期的年龄的最简单表达式是什么?
我正在寻找以下术语的答案:
答案应该是一个内联表达式 - 能够被选择或合并到 where 子句中。
答案应该是可靠的,并且没有错误的极端情况 - 但这些情况并不常见或不可信。它应该适用于新生婴儿和数百岁的人,应该应对闰年,并且理想情况下应该能够将出生前的时期表示为负数(这个人成为 -出生前一天满 1 岁)。
答案应该是精确的数字 - 它不应该依赖于使用每年的平均天数或除以幻数,并四舍五入误差。我相信所有使用舍入的琐碎方法都有极端情况,因此不可靠,但我需要得到纠正。
对于那些生日在 2 月 29 日的人,如果参考年是闰年,则应将其年龄视为 2 月 29 日递增,如果参考年是闰年,则应将其年龄视为 3 月 1 日递增参考年不是闰年。
答案应忽略出生日期或参考日期的任何时间组成部分 - 即,应假定此人出生于午夜,并且其年龄应在随后生日的午夜递增。
我特别对 SQL Server 的答案感兴趣,但也有兴趣查看任何其他数据库平台的答案。
编辑:我很欣赏已经给出的答案以及之前问题的链接。此问题现已标记为重复。
令我震惊的是,对给定链接的接受答案是混乱的,并且以不正确的实现开头,并且上面的 cmets 指的是它的实现不正确 - 只有在我仔细阅读之后我才看到它已更新为正确的实现(夹在与我的问题无关的“十进制年龄”处理之间)。第三个答案也吸引了大量赞成票,但也是不正确的。还有无数其他质量参差不齐的答案。
我还要求一个答案,理想情况下,以某种方式正确处理“负年龄”(参考日期在出生日期之前),而链接的答案没有。因此,虽然我的问题处理的是同一个主题,但它不是重复的,因为我已经施加了该问题中不存在的几个额外限制,这将使(以一种或另一种方式)对该旧问题给出的所有答案无效问题。
老实说,考虑到有多少微妙的错误答案比比皆是(正如我在上面第一段中提到的那样),我本以为这个问题会得到更多的赞成和更多的兴趣,而不是反对和 3 票结束。
【问题讨论】:
-
完全依赖于数据库。我怀疑你想要一个“sql-server”标签。在 Postgres 中,您可以使用
age()。 -
@GordonLinoff,我确实想要“sql-server”标签,但正如我所说,我还想要任何其他平台的答案。我注意到您对 Postgres 的回答!理想情况下,这应该为所有平台生成一些明确的答案 - 是其他人的问题促使我问这个问题。
-
@AaronDietz,是的,对于 2017 年 2 月 28 日出生的婴儿,他们要到 18 年 3 月 1 日才满 1 岁。从 2017 年 2 月 28 日到 2018 年 2 月 28 日之间有 365 天。
365/365.25=0.99... -
这似乎可能会吸引到与this existing question 类似的一轮答案,无论您如何谨慎地表达您的要求......
标签: sql sql-server oracle date