案例陈述:当日期距当年超过 90 年时 THEN 最大日期距当前日期 90 年

Case statement: WHEN date is more than 90 years from current year THEN max date out at 90 years from current date

我有一个包含人们生日的日期列。其中一些包含 90 多年前的日期,我希望将这些日期限制在 90 年前。

例子

current      desired
1930-01-01   1932-01-01
1930-02-11   1932-02-11

如您所见,如果生日自然超过 90 年,则期望的状态是让生日从当前日期算起 90 年。

它比我最初猜想的更棘手,它可以写得更简单,现在似乎有“竞争”,虽然,这比以前更不可读

90后无日期版本:

SELECT column1 as "current"
    ,iff(column1 < dateadd('year',-90, CURRENT_DATE), 
         date_from_parts(
            year(CURRENT_DATE) - 90 + (month(column1)*100+day(column1) < month(CURRENT_DATE)*100 + day(CURRENT_DATE))::int, 
             month(column1), 
             day(column1)), 
         column1
        ) as desired
FROM VALUES 
    ('1934-01-01'::date),
    ('1932-03-28'::date),
    ('1932-03-20'::date),
    ('1931-03-28'::date),
    ('1931-03-20'::date),
    ('1930-01-01'::date),
    ('1930-02-11'::date);
current DESIRED
1934-01-01 1934-01-01
1932-03-28 1932-03-28
1932-03-20 1933-03-20
1931-03-28 1932-03-28
1931-03-20 1933-03-20
1930-01-01 1933-01-01
1930-02-11 1933-02-11

90 年前(又名标题)版本之前的年份:

SELECT column1 as "current"
    ,iff(year(column1) < year(CURRENT_DATE)-90, date_from_parts(year(CURRENT_DATE)-90, month(column1), day(column1)), column1) as desired
FROM VALUES
    ('1934-01-01'::date),
    ('1932-03-28'::date),
    ('1932-03-20'::date),
    ('1931-03-28'::date),
    ('1931-03-20'::date),
    ('1930-01-01'::date),
    ('1930-02-11'::date)
;
current DESIRED
1934-01-01 1934-01-01
1932-03-28 1932-03-28
1932-03-20 1932-03-20
1931-03-28 1932-03-28
1931-03-20 1932-03-20
1930-01-01 1932-01-01
1930-02-11 1932-02-11

只唱CASE:

因此,由于在 CASE 语句的上下文中被要求,我又写了一遍(并修复了年份部分),但也将其解构,因此可以看出逻辑:

SELECT column1 as birth_day
    ,dateadd('year',-90, CURRENT_DATE) as ninety_years_ago
    ,year(ninety_years_ago) as ninety_years_ago_year
    ,(month(CURRENT_DATE)*100) + day(CURRENT_DATE) as current_partial_year
    ,(month(birth_day)*100) + day(birth_day) as birth_day_partial_year
    ,case when birth_day_partial_year < current_partial_year then 1 else 0 end as partial_year_correction
    ,(birth_day_partial_year < current_partial_year)::int as current_partial_year_alt_version /* not used just showing how it works */
    ,case
        WHEN column1 < ninety_years_ago then
            date_from_parts(ninety_years_ago_year + partial_year_correction, month(birth_day), day(birth_day))
        ELSE 
            birth_day
        END as desired
FROM VALUES 
    ('1934-01-01'::date),
    ('1932-04-28'::date),
    ('1932-03-20'::date),
    ('1931-04-28'::date),
    ('1931-03-20'::date),
    ('1930-01-01'::date),
    ('1930-02-11'::date);

给出:

BIRTH_DAY NINETY_YEARS_AGO NINETY_YEARS_AGO_YEAR CURRENT_PARTIAL_YEAR BIRTH_DAY_PARTIAL_YEAR PARTIAL_YEAR_CORRECTION CURRENT_PARTIAL_YEAR_ALT_VERSION DESIRED
1934-01-01 1932-03-31 1932 331 101 1 1 1934-01-01
1932-04-28 1932-03-31 1932 331 428 0 0 1932-04-28
1932-03-20 1932-03-31 1932 331 320 1 1 1933-03-20
1931-04-28 1932-03-31 1932 331 428 0 0 1932-04-28
1931-03-20 1932-03-31 1932 331 320 1 1 1933-03-20
1930-01-01 1932-03-31 1932 331 101 1 1 1933-01-01
1930-02-11 1932-03-31 1932 331 211 1 1 1933-02-11

这确实是一个棘手的问题。我什至在 timeanddate.com 检查了最长 90 年的日期差异 - 看起来不错。如果有人在这方面发现问题,请提供反馈。

select iff(extract(year,dateadd('year',90,column1::date))>extract(year,'2022-02-28'::date),
    column1,
    dateadd(day,
    datediff(day,column1::date,dateadd(year,-90,'2022-02-28'::date)),
    column1::date
    )) as test
    from
    values
    ('1932-02-29'::date)
    ,('1932-02-28'::date)
    ,('1932-03-01'::date)
    ,('1928-02-29'::date)
    ,('1924-02-29'::date)
    ,('1930-01-01'::date)
    ,('1940-05-01'::date)
    ,('1950-12-01'::date)
    ,('1980-10-01'::date)
    ,('1920-06-01'::date)
    ;
    
+------------+
| TEST       |
|------------|
| 1932-02-28 |
| 1932-02-28 |
| 1932-02-28 |
| 1932-02-28 |
| 1932-02-28 |
| 1932-02-28 |
| 1940-05-01 |
| 1950-12-01 |
| 1980-10-01 |
| 1932-02-28 |
+------------+