Sql 甲骨文将于今年的今天诞生

Sql 甲骨文将于今年的今天诞生,sql,oracle,oracle11g,Sql,Oracle,Oracle11g,我想写一个查询,告诉我一个人今年的生日是什么时候。对于闰年来说,下个月就可以了。我计划通过计算今天和他们的出生日期之间的差异并将其添加到他们的出生日期中来实现这一点。如果一个人出生在1999年11月1日,我想计算一下他们今年的生日是什么时候。预计产量为今年11月1日。以下是我实现这一目标的尝试: 我试着数一数这两个日期之间有多少个月,然后把它加到出生日期上 select ADD_MONTHS(to_date('01-NOV-1999'), ROUND(MONTHS_BETWEEN(TRUNC(

我想写一个查询,告诉我一个人今年的生日是什么时候。对于闰年来说,下个月就可以了。我计划通过计算今天和他们的出生日期之间的差异并将其添加到他们的出生日期中来实现这一点。如果一个人出生在1999年11月1日,我想计算一下他们今年的生日是什么时候。预计产量为今年11月1日。以下是我实现这一目标的尝试:

我试着数一数这两个日期之间有多少个月,然后把它加到出生日期上

select  ADD_MONTHS(to_date('01-NOV-1999'), ROUND(MONTHS_BETWEEN(TRUNC(SYSDATE), to_date('01-NOV-1999'))))  from dual;
此输出包括以下内容: 19年10月1日

我试着计算出生日期和今天之间的间隔天数,并将其添加到他们的出生日期中。但是,这似乎并不正确:

select  to_date('01-NOV-1999') + (TRUNC(SYSDATE) - to_date('01-NOV-1999'))  from dual;
产出:19年10月2日

我希望得到的是2019年11月1日。我发布的系统日期是19年10月2日。这两个日期似乎都比我的预期产出晚了一个月。如果我尝试在第一个查询中使用OCT而不是NOV运行同一个查询,它将正常工作


我使用的是Oracle数据库11g

生日不是从出生日期算起的公式。除了闰年之外,它是一年中固定的一天。使用该逻辑,您可以通过以下查询计算今年的生日:

with date_of_birth as
(SELECT TO_DATE('01-NOV-1971','DD-MON-YYYY') as dt FROM DUAL
UNION
SELECT TO_DATE('29-FEB-2004','DD-MON-YYYY')FROM DUAL
)
SELECT 
  dt as date_of_birth
 ,CASE 
    WHEN TO_CHAR(dt,'DD-MON') = '29-FEB' THEN
      TO_DATE('01-MAR-'||EXTRACT(year FROM sysdate),'DD-MON-YYYY')
    ELSE 
      TO_DATE(TO_CHAR(dt,'DD-MON-')||EXTRACT(year FROM sysdate),'DD-MON-YYYY')
  END AS this_year_birthday
  FROM date_of_birth;
这会回来的

DATE_OF_BIR THIS_YEAR_B
----------- -----------
01-NOV-1971 01-NOV-2019
29-FEB-2004 01-MAR-2019
-编辑。正如Jeffrey指出的,如果在闰年运行,上述查询将返回错误的结果。这是一个更新版本,允许用户在当前年份以外的其他年份运行它。将返回与Jeffrey Kemps的答案相同的结果,但从另一个角度考虑

with 
FUNCTION is_valid_date (date_str_i VARCHAR2, format_i VARCHAR2) RETURN VARCHAR2
/* check if date is valid */
AS
  l_dummy_dt DATE;
  date_not_valid_for_m EXCEPTION;
  PRAGMA EXCEPTION_INIT(date_not_valid_for_m, -01839);  
BEGIN
  SELECT TO_DATE(date_str_i,format_i) INTO l_dummy_dt FROM DUAL;
  RETURN 'Y';
EXCEPTION WHEN date_not_valid_for_m THEN
  RETURN 'N';
END; 
date_of_birth as
(SELECT TO_DATE('01-NOV-1971','DD-MON-YYYY') as dt FROM DUAL
UNION
SELECT TO_DATE('29-FEB-2004','DD-MON-YYYY')FROM DUAL
),
year_to_check as
(SELECT '2016' as yr FROM DUAL)
SELECT 
  dt as date_of_birth
 ,CASE 
    WHEN TO_CHAR(dt,'DD-MON') = '29-FEB' THEN
      CASE 
        WHEN is_valid_date(date_str_i => '29-FEB-'||yr,format_i => 'DD-MON-YYYY') = 'N' 
          THEN TO_DATE('01-MAR-'||yr,'DD-MON-YYYY')
        ELSE
          TO_DATE(TO_CHAR(dt,'DD-MON-')||yr,'DD-MON-YYYY')
        END 
    ELSE 
      TO_DATE(TO_CHAR(dt,'DD-MON-')||yr,'DD-MON-YYYY')
  END AS this_year_birthday
  FROM date_of_birth, year_to_check;
/

生日不是从出生日期算起的公式。除了闰年之外,它是一年中固定的一天。使用该逻辑,您可以通过以下查询计算今年的生日:

with date_of_birth as
(SELECT TO_DATE('01-NOV-1971','DD-MON-YYYY') as dt FROM DUAL
UNION
SELECT TO_DATE('29-FEB-2004','DD-MON-YYYY')FROM DUAL
)
SELECT 
  dt as date_of_birth
 ,CASE 
    WHEN TO_CHAR(dt,'DD-MON') = '29-FEB' THEN
      TO_DATE('01-MAR-'||EXTRACT(year FROM sysdate),'DD-MON-YYYY')
    ELSE 
      TO_DATE(TO_CHAR(dt,'DD-MON-')||EXTRACT(year FROM sysdate),'DD-MON-YYYY')
  END AS this_year_birthday
  FROM date_of_birth;
这会回来的

DATE_OF_BIR THIS_YEAR_B
----------- -----------
01-NOV-1971 01-NOV-2019
29-FEB-2004 01-MAR-2019
-编辑。正如Jeffrey指出的,如果在闰年运行,上述查询将返回错误的结果。这是一个更新版本,允许用户在当前年份以外的其他年份运行它。将返回与Jeffrey Kemps的答案相同的结果,但从另一个角度考虑

with 
FUNCTION is_valid_date (date_str_i VARCHAR2, format_i VARCHAR2) RETURN VARCHAR2
/* check if date is valid */
AS
  l_dummy_dt DATE;
  date_not_valid_for_m EXCEPTION;
  PRAGMA EXCEPTION_INIT(date_not_valid_for_m, -01839);  
BEGIN
  SELECT TO_DATE(date_str_i,format_i) INTO l_dummy_dt FROM DUAL;
  RETURN 'Y';
EXCEPTION WHEN date_not_valid_for_m THEN
  RETURN 'N';
END; 
date_of_birth as
(SELECT TO_DATE('01-NOV-1971','DD-MON-YYYY') as dt FROM DUAL
UNION
SELECT TO_DATE('29-FEB-2004','DD-MON-YYYY')FROM DUAL
),
year_to_check as
(SELECT '2016' as yr FROM DUAL)
SELECT 
  dt as date_of_birth
 ,CASE 
    WHEN TO_CHAR(dt,'DD-MON') = '29-FEB' THEN
      CASE 
        WHEN is_valid_date(date_str_i => '29-FEB-'||yr,format_i => 'DD-MON-YYYY') = 'N' 
          THEN TO_DATE('01-MAR-'||yr,'DD-MON-YYYY')
        ELSE
          TO_DATE(TO_CHAR(dt,'DD-MON-')||yr,'DD-MON-YYYY')
        END 
    ELSE 
      TO_DATE(TO_CHAR(dt,'DD-MON-')||yr,'DD-MON-YYYY')
  END AS this_year_birthday
  FROM date_of_birth, year_to_check;
/

这是一个令人惊讶的复杂问题,这激发了一整篇关于它的博客文章。以下是一个应该让大多数人满意的解决方案:

with
  function birthday (d in date, age in number) return date is
  begin
    if to_char(d,'DD/MM') = '28/02'
    and to_char(add_months(d,age*12),'DD/MM') = '29/02'
    then
      return add_months(d,age*12)-1;
    else
      return add_months(d,age*12);
    end if;
  end;
select * from (
  with testdata as (
  select date'2000-12-25' as d1
        ,date'2000-02-29' as d2
        ,date'2000-02-28' as d3
        ,date'2001-02-28' as d4
  from dual)
  select rownum-1 as age
        ,birthday(d1,rownum-1) as d1
        ,birthday(d2,rownum-1) as d2
        ,birthday(d3,rownum-1) as d3
        ,birthday(d4,rownum-1) as d4
  from testdata connect by level <= 12
);

这是一个令人惊讶的复杂问题,这激发了一整篇关于它的博客文章。以下是一个应该让大多数人满意的解决方案:

with
  function birthday (d in date, age in number) return date is
  begin
    if to_char(d,'DD/MM') = '28/02'
    and to_char(add_months(d,age*12),'DD/MM') = '29/02'
    then
      return add_months(d,age*12)-1;
    else
      return add_months(d,age*12);
    end if;
  end;
select * from (
  with testdata as (
  select date'2000-12-25' as d1
        ,date'2000-02-29' as d2
        ,date'2000-02-28' as d3
        ,date'2001-02-28' as d4
  from dual)
  select rownum-1 as age
        ,birthday(d1,rownum-1) as d1
        ,birthday(d2,rownum-1) as d2
        ,birthday(d3,rownum-1) as d3
        ,birthday(d4,rownum-1) as d4
  from testdata connect by level <= 12
);

这将给出生在2月29日的人带来错误的日期,在闰年,他们会正确地期望他们的生日庆祝会在当年的2月29日举行。对于这些情况,您的查询返回3月1日。感谢您指出这一点!我添加了第二个版本,检查2月29日是否为有效日期,如果不是,则只将其更改为3月1日。这将为2月29日出生的人提供错误的日期,在闰年中,他们正确地期望他们的生日庆祝会在当年的2月29日举行。对于这些情况,您的查询返回3月1日。感谢您指出这一点!我添加了第二个版本,用于检查2月29日是否为有效日期,如果不是,则仅将其更改为3月1日。当我运行此版本时,我在第15行第12列的错误处获取缺少的关键字这是一个livesql版本,这可能会帮助您:当我运行此版本时,我在第15行第12列的错误处获取缺少的关键字这是一个livesql版本,这可能会帮助您: