正确的方法似乎是衡量在这两项任务上花费的 DAYS,然后将这些日期相加,然后将其转换为 本质上不精确 给予或接受类似街头谈话的年份形式 -月日。 更多内容如下
借用 Livius 的转换查询,并将系数调整为更现实,将发展为:
https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=2fba0ace6a70ae16a167ec838642dc28
在这里,我们一步一步地移动,从简单的积木到越来越复杂的积木,最终给了我们16年零5个月零2天:
select rdb$get_context('SYSTEM', 'ENGINE_VERSION') as version from rdb$database;
|版本 |
| :-------- |
| 3.0.5 |
create table KP (
ID_CONTACT integer not null,
DATE_FROM date not null,
DATE_TO date not null
)
-- https://stackoverflow.com/questions/51551257/how-to-get-correct-year-month-and-day-in-firebird-function-datediff
✓
create index KP_workers on KP(id_contact)
✓
insert into KP values (1, '1988-09-15', '2000-03-16')
1 行受影响
insert into KP values (1, '2000-03-16', '2005-02-28')
1 行受影响
-- the sample data from https://stackoverflow.com/questions/60030543
-- might expose the rounding bug in my original formulae:
-- unexpected ROUNDING UP leading to NEGATIVE value for months
insert into KP values (2, '2018-02-08', '2019-12-01')
1 行受影响
insert into KP values (2, '2017-02-20', '2018-01-01')
1 行受影响
select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KP a
ID_CONTACT | DATE_FROM | DATE_TO | DAYS_COUNT 天
---------: | :--------- | :--------- | :---------
1 | 1988-09-15 | 2000-03-16 | 4200
1 | 2000-03-16 | 2005-02-28 | 1810
2 | 2018-02-08 | 2019-12-01 | 661
2 | 2017-02-20 | 2018-01-01 | 315
-- Original answer by Livius
SELECT
KP3.id_contact
, KP3.D2-KP3.D1 as days_count
, (KP3.D2-KP3.D1) / (12*31) AS Y
, ((KP3.D2-KP3.D1) - ((KP3.D2-KP3.D1) / (12*31)) * 12 * 31) / 31 AS M
, CAST(MOD((KP3.D2-KP3.D1) - (((KP3.D2-KP3.D1) / (12*31)) * 12 * 31), 31) AS INTEGER) AS D
FROM
(SELECT
KP2.id_contact, SUM(KP2.D1) AS D1, SUM(KP2.D2) AS D2
FROM
(
SELECT
KP.id_contact, DATEDIFF(MONTH, KP.DATE_FROM, KP.DATE_TO) / 12 AS Y, CAST(MOD(DATEDIFF(MONTH, KP.DATE_FROM, KP.DATE_TO), 12) AS INTEGER) AS M
, EXTRACT(YEAR FROM KP.DATE_FROM)*12*31+EXTRACT(MONTH FROM KP.DATE_FROM)*31+EXTRACT(DAY FROM KP.DATE_FROM) D1
, EXTRACT(YEAR FROM KP.DATE_TO)*12*31+EXTRACT(MONTH FROM KP.DATE_TO)*31+EXTRACT(DAY FROM KP.DATE_TO) D2
FROM
KP
) AS KP2
GROUP BY KP2.id_contact
) AS KP3
ID_CONTACT | DAYS_COUNT |是 |中号 | D
---------: | :--------- | :- | :- | -:
1 | 6120 | 16 | 5 | 13
2 | 997 | 2 | 8 | 5
select ID_CONTACT, sum(DAYS_COUNT) as DAYS_COUNT
from (
select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KP a
)
GROUP BY 1
ID_CONTACT | DAYS_COUNT 天
---------: | :---------
1 | 6010
2 | 976
-- this step taken from https://dbfiddle.uk/?rdbms=firebird_3.0&fiddle=52c1e130f589ca507c9ff185b5b2346d
-- based on original Livius forumla with non-exact integer coefficients
-- it seems not be generating negative counts, but still shows very different results
SELECT
KP_DAYS.id_contact,
KP_DAYS.DAYS_COUNT / (12*31) AS Y,
((KP_DAYS.DAYS_COUNT) - ((KP_DAYS.DAYS_COUNT) / (12*31)) * 12 * 31) / 31 AS M,
CAST(MOD((KP_DAYS.DAYS_COUNT) - (((KP_DAYS.DAYS_COUNT) / (12*31)) * 12 * 31), 31) AS INTEGER) AS D
FROM
(
select ID_CONTACT, sum(DAYS_COUNT) as DAYS_COUNT
from (
select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KP a
)
GROUP BY 1
) as KP_DAYS
ID_CONTACT |是 |中号 | D
---------: | :- | :- | -:
1 | 16 | 1 | 27
2 | 2 | 7 | 15
SELECT
KP_DAYS.id_contact, KP_DAYS.days_count
, FLOOR(KP_DAYS.DAYS_COUNT / 365.25) AS Y
, FLOOR( (KP_DAYS.DAYS_COUNT - (FLOOR(KP_DAYS.DAYS_COUNT / 365.25) * 365.25) ) / 30.5) AS M
, CAST(MOD((KP_DAYS.DAYS_COUNT) - (((KP_DAYS.DAYS_COUNT) / 365.25) * 365.25), 30.5) AS INTEGER) AS D
FROM
(
select ID_CONTACT, sum(DAYS_COUNT) as DAYS_COUNT
from (
select a.*, datediff(day, a.DATE_FROM, a.DATE_TO) as DAYS_COUNT from KP a
)
GROUP BY 1
) as KP_DAYS
ID_CONTACT | DAYS_COUNT |是 |中号 | D
---------: | :--------- | :- | :- | -:
1 | 6010 | 16 | 5 | 2
2 |第976章2 | 8 | 1
请注意,以上在数学上仍然不正确。但应该给出时间戳的“直觉”。
以 Y-M-D 形式获得精确和精确的时间跨度测量的问题是没有实际意义的。
例如,您引用了 3 天,而此查询给出了 2 天。我看那里没有错误。因为月份和年份彼此不同,所以您只是无法正确地以月份为单位测量时间距离。这就像测量城市的地理距离一样。
伦敦和巴黎之间有多少个纽约?厄尔布鲁士山有多少华沙?你不可能有任何数学上正确的答案。
因此,您只能使用非精确估计来回答。适合在街头谈话中给予或接受。因此,任何基于 DateDiff 的查询本质上都会生成“2Y 10M 给予或花费几天”的完全有效的答案——这个答案对于“只给我总体印象”的上下文是有效的。
将这种简单的感觉与数学准确性的完美主义结合起来是不可能的。例如,假设您的跨度约为 6Y。现在你应该考虑多少个闰年? 1999 年到 2004 年的“6Y”有两个闰年,而 1998 年到 2003 年的“6Y”只有一个闰年。哪个是“6Y”的正确度量???
然后我们有千禧年,2000 年是闰年,但 1900 年不是。同样的“滑动窗口”问题会在像“110Y”这样的时间跨度内为您提供不稳定的未定义闰年数。如果您想按照外行的看法并以“年和月”计算时间跨度 - 您必须同意这使事情变得容易、简单且根据定义不精确。几年的一天或几天的不匹配是常态,可以