检查生日是否在跨越年假的 6 个月之间

Checking if a Birthday was between a 6 month span which crosses the year break

我正在尝试编写 SQL 代码(使用 SQL 开发人员)来检查一个人是否在过去 6 个月的保险期限内过生日。

这是我的代码目前的样子。

SELECT DRIVER_KEY, CASE WHEN BDAY BETWEEN EFFDAY AND EXPDAY THEN 1 ELSE 0 END AS BDAYIND FROM (
    SELECT DISTINCT A.DRIVER_KEY
    , TO_CHAR(A.BIRTH_DATE,'mm/dd') AS BDAY          
     , TO_CHAR(SUBSTR(A.EFFECTIVE_DATE_KEY,5,2)||'/'||SUBSTR(A.EFFECTIVE_DATE_KEY,7,2) ) AS EFFDAY
    , TO_CHAR(SUBSTR(A.EXPIRATION_DATE_KEY,5,2)||'/'||SUBSTR(A.EXPIRATION_DATE_KEY,7,2) ) AS EXPDAY
    FROM DRIVER_TABLE A
    );

它有效 - 只要该术语不跨越年份的休息时间。但是,我的代码目前表示 01/25 不在 09/19 和 03/19 之间......我该如何解决这个问题?

编辑: 正如 APC 所指出的,我的解决方案不适用于闰年。我通常会删除这个 post,但它已经被选为问题的答案。我更新了下面的代码以使用 Brian Leach 解决方案中的年份逻辑而不是 to_date 字符串。请给 Brian 或 APC 的答案投票。

这是我的任意日期的创建语句:

create table DRIVER_TABLE
(
  BIRTH_DATE date,
  EFFECTIVE_DATE_KEY date,
  EXPIRATION_DATE_KEY date
  );

  insert into DRIVER_TABLE
  values(to_date('05/01/1980','MM/DD/YYYY'),
         to_date('11/01/2016','MM/DD/YYYY'),
         to_date('04/01/2017','MM/DD/YYYY'));

这里是查询:

select case when BirthdayEFFYear between EFFECTIVE_DATE_KEY and EXPIRATION_DATE_KEY 
              or BirthdayEXPYear between EFFECTIVE_DATE_KEY and EXPIRATION_DATE_KEY
              or to_number(EXPIRATION_DATE_KEY - EFFECTIVE_DATE_KEY) / 365 > 1
        then 1 else 0 end BDAYIND
from(
select add_months(BIRTH_DATE,12 * (extract(year from EFFECTIVE_DATE_KEY) - extract(year from BIRTH_DATE))) BirthdayEFFYear,
       add_months(BIRTH_DATE,12 * (extract(year from EXPIRATION_DATE_KEY) - extract(year from BIRTH_DATE))) BirthdayEXPYear,
       EFFECTIVE_DATE_KEY,EXPIRATION_DATE_KEY
from DRIVER_TABLE A
)

SQLFiddle

将日期作为日期而不是字符串进行比较。

显然 EFFECTIVE_DATE_KEY 的前四个字符包含年份,因此下面的内容应该可以满足您的需求:

SELECT DRIVER_KEY,
       CASE
         WHEN BDAY BETWEEN EFFDAY AND EXPDAY THEN 1
         ELSE 0
       END AS BDAYIND
  FROM (SELECT DISTINCT A.DRIVER_KEY,
                        A.BIRTH_DATE AS BDAY,
                        TO_DATE(A.EFFECTIVE_DATE_KEY, 'YYYYMMDD') AS EFFDAY,
                        TO_DATE(A.EXPIRATION_DATE_KEY, 'YYYYMMDD') AS EXPDAY
          FROM DRIVER_TABLE A);

祝你好运。

'01/25' 不在 '09/19''03/19' 之间,因为当第二个参数小于第一个参数时 between() 永远不会为真。你落入这个陷阱是因为你在处理弦乐。使用 DATE 数据类型处理日期总是更容易。

看起来您的列 effective_dateexpiry_date 可能不是存储为日期而是字符串;不幸的是,这是一个常见的数据建模错误。如果是这样,您需要先将它们转换为 DATE,然后再应用以下内容。

此解决方案有一个子查询,它从 driver_table 中选择相关列,并计算每个 driver 的当前年龄(以年为单位)。年龄用于推导出最后一个生日,然后在主查询中将其与保险条款的范围进行比较。因为我们导出了一个实际日期,所以我们可以使用 Oracle 的标准日期算法,因此可以正确计算 bdayind

SQL> with cte as (
  2       select driver_key
  3              , date_of_birth
  4              , trunc(months_between(sysdate, date_of_birth)/12) as age
  5              , add_months(date_of_birth, 12 * (trunc(months_between(sysdate, date_of_birth)/12))) as last_birthday
  6              , effective_date
  7              , expiry_date 
  8        from driver_table
  9    )
 10  select driver_key
 11         , date_of_birth as dob
 12         , age
 13         , effective_date as eff_date
 14         , expiry_date as exp_date
 15         , last_birthday as last_bday
 16         , case 
 17              when last_birthday between effective_date and expiry_date 
 18              then 1
 19              else 0 end as bdayind
 20  from cte
 21  /   

DRIVER_KEY DOB        AGE EFF_DATE  EXP_DATE  LAST_BDAY    BDAYIND
---------- --------- ---- --------- --------- --------- ----------
        12 02-APR-98   19 01-DEC-16 31-MAY-17 02-APR-17          1
        22 02-APR-98   19 01-JAN-17 30-JUN-17 02-APR-17          1
        32 02-SEP-98   18 01-DEC-16 31-MAY-17 02-SEP-16          0
        42 02-SEP-98   18 01-JAN-17 30-JUN-17 02-SEP-16          0

SQL> 

子查询同时生成 agelast_birthday 只是为了演示目的。在现实生活中,您只需要 last_birthday 列。

此解决方案与其他解决方案略有不同,因为:

  1. 适用于任何生效日期和到期日期之间的任何生日
  2. 它占闰年

raw_data 只是为示例设置日期:

    WITH
    raw_data
    AS
        (SELECT DATE '1963-08-03' AS birthday
              , DATE '2017-04-01' AS effectiveday
              , DATE '2017-10-31' AS expirationday
              , 'Billy' AS name
           FROM DUAL
         UNION ALL
         SELECT DATE '1995-03-20' AS birthday
              , DATE '2017-04-01' AS effectiveday
              , DATE '2017-10-31' AS expirationday
              , 'Sue' AS name
           FROM DUAL
         UNION ALL
         SELECT DATE '1997-01-15' AS birthday
              , DATE '2016-12-01' AS effectiveday
              , DATE '2017-05-31' AS expirationday
              , 'Olga' AS name
           FROM DUAL),
    mod_data
    AS
        (SELECT raw_data.*
              , ADD_MONTHS (
                    birthday
                  , (extract(year from effectiveday) - extract (year from birthday)) * 12
                )
                    effectiveanniversary
              , ADD_MONTHS (
                    birthday
                  , (extract(year from expirationday) - extract (year from birthday)) * 12
                )
                    expirationanniversary
           FROM raw_data)
SELECT name, mod_data.birthday, effectiveday, expirationday
     , CASE
           WHEN effectiveanniversary BETWEEN effectiveday AND expirationday
             OR expirationanniversary BETWEEN effectiveday AND expirationday
           THEN
               1
           ELSE
               0
       END
           found_between
  FROM mod_data

NAME  BIRTHDAY     EFFECTIVEDAY  EXPIRATIONDAY  FOUND_BETWEEN                          
Billy 1963/08/03   2017/04/01    2017/10/31     1                                      
Sue   1995/03/20   2017/04/01    2017/10/31     0                                      
Olga  1997/01/15   2016/12/01    2017/05/31     1