SQL 判断闰年判断当前年份是否闰年。
SQL 判断闰年 问题描述
判断当前年份是否闰年。
SQL 判断闰年 解决方案
如果你已经有了一段时间的 SQL 编程经验,那么你肯定知道本问题有多种解法。我也尝试过多种解决方案,它们都能给出正确答案,但是本实例提供的方案可能是最为简单的。下面的解决方案仅仅检查 2 月的最后一天:如果有 2 月 29 日,则当前年份是闰年。
DB2
使用 WITH
子句递归查询返回 2 月的每一天,然后调用聚合函数 MAX
确认 2 月的最后一天。
1 with x (dy,mth)
2 as (
3 select dy, month(dy)
4 from (
5 select (current_date -
6 dayofyear(current_date) days +1 days)
7 +1 months as dy
8 from t1
9 ) tmp1
10 union all
11 select dy+1 days, mth
12 from x
13 where month(dy+1 day) = mth
14 )
15 select max(day(dy))
16 from x
Oracle
使用 LAST_DAY
函数找出 2 月的最后一天。
1 select to_char(
2 last_day(add_months(trunc(sysdate,'y'),1)),
3 'DD')
4 from t1
PostgreSQL
使用 GENERATE_SERIES
函数返回 2 月的每一天,然后调用聚合函数 MAX
找出 2 月的最后一天。
1 select max(to_char(tmp2.dy+x.id,'DD')) as dy
2 from (
3 select dy, to_char(dy,'MM') as mth
4 from (
5 select cast(cast(
6 date_trunc('year',current_date) as date)
7 + interval '1 month' as date) as dy
8 from t1
9 ) tmp1
10 ) tmp2, generate_series (0,29) x(id)
11 where to_char(tmp2.dy+x.id,'MM') = tmp2.mth
MySQL
使用 LAST_DAY
函数找出 2 月的最后一天。
1 select day(
2 last_day(
3 date_add(
4 date_add(
5 date_add(current_date,
6 interval -dayofyear(current_date) day),
7 interval 1 day),
8 interval 1 month))) dy
9 from t1
SQL Server
使用 WITH
递归查询返回 2 月的每一天,然后调用聚合函数 MAX
确认 2 月的最后一天。
1 with x (dy,mth)
2 as (
3 select dy, month(dy)
4 from (
5 select dateadd(mm,1,(getdate()-datepart(dy,getdate()))+1) dy
6 from t1
7 ) tmp1
8 union all
9 select dateadd(dd,1,dy), mth
10 from x
11 where month(dateadd(dd,1,dy)) = mth
12 )
13 select max(day(dy))
14 from x
SQL 判断闰年 扩展知识
DB2
递归视图 X
里的内嵌视图 TMP1
按照下面的步骤返回 2 月的第一天。
(1) 从当前日期开始;
(2) 调用 DAYOFYEAR
函数确认当前日期是当前年份的第几天;
(3) 从当前日期里减去上述步骤算出的那个数字以得到上一年的 12 月 31 日,然后加上 1 天得到当前年份的 1 月 1 日;
(4) 再加上 1 个月得到 2 月 1 日。
上述步骤的运算结果如下所示。
select (current_date -
dayofyear(current_date) days +1 days) +1 months as dy
from t1
DY
-----------
01-FEB-2005
然后,调用 MONTH
函数找出内嵌视图 TMP1
返回的日期对应的月份。
select dy, month(dy) as mth
from (
select (current_date -
dayofyear(current_date) days +1 days) +1 months as dy
from t1
) tmp1
DY MTH
----------- ---
01-FEB-2005 2
到此为止的结果只是作为生成 2 月的每一天的递归操作的起点。为了获得 2 月的每一天,不断为 DY
加上 1 天,直到月份不再是 2 月为止。该 WITH
计算的部分结果如下所示。
with x (dy,mth)
as (
select dy, month(dy)
from (
select (current_date -
dayofyear(current_date) days +1 days) +1 months as dy
from t1
) tmp1
union all
select dy+1 days, mth
from x
where month(dy+1 day) = mth
)
select dy,mth
from x
DY MTH
----------- ---
01-FEB-2005 2
...
10-FEB-2005 2
...
28-FEB-2005 2
最后,针对 DY
列调用 MAX
函数返回 2 月的最后一天;如果是 29 日的话,则当前年份是闰年。
Oracle
首先,调用 TRUNC
函数找出当前年份的第一天。
select trunc(sysdate,'y')
from t1
DY
-----------
01-JAN-2005
由于 1 月 1 日是一年中的第一天,下一步就是在此基础上加上 1 个月得到 2 月 1 日。
select add_months(trunc(sysdate,'y'),1) dy
from t1
DY
-----------
01-FEB-2005
然后,调用 LAST_DAY
找出 2 月的最后一天。
select last_day(add_months(trunc(sysdate,'y'),1)) dy
from t1
DY
-----------
28-FEB-2005
最后,调用 TO_CHAR
得到 28 或者 29(这一步不是必需的)。
PostgreSQL
首先观察内嵌视图 TMP1
返回的结果。调用 DATE_TRUNC
函数得到当前年份的第一天,并将其转换为 DATE
类型。
select cast(date_trunc('year',current_date) as date) as dy
from t1
DY
-----------
01-JAN-2005
然后,在当前年份第一天的基础上加上 1 个月,得到 2 月的第一天,并转换为 DATE
类型。
select cast(cast(
date_trunc('year',current_date) as date)
+ interval '1 month' as date) as dy
from t1
DY
-----------
01-FEB-2005
接着,从内嵌视图 TMP1
里返回 DY
,并依据 DY
计算出月份的值。调用 TO_CHAR
函数返回月份的值。
select dy, to_char(dy,'MM') as mth
from (
select cast(cast(
date_trunc('year',current_date) as date)
+ interval '1 month' as date) as dy
from t1
) tmp1
DY MTH
----------- ---
01-FEB-2005 2
到此为止的计算结果构成了内嵌视图 TMP2
的结果集。下一步要用到一个非常有用的函数 GENERATE_SERIES
来生成 29 行数据(值从 1 逐一递增到 29)。GENERATE_SERIES
函数返回的每一行(别名为 X)都和内嵌视图 TMP2
的 DY
相加。部分结果如下所示。
select tmp2.dy+x.id as dy, tmp2.mth
from (
select dy, to_char(dy,'MM') as mth
from (
select cast(cast(
date_trunc('year',current_date) as date)
+ interval '1 month' as date) as dy
from t1
) tmp1
) tmp2, generate_series (0,29) x(id)
where to_char(tmp2.dy+x.id,'MM') = tmp2.mth
DY MTH
----------- ---
01-FEB-2005 02
...
10-FEB-2005 02
...
28-FEB-2005 02
最后,调用 MAX
函数找出 2 月的最后一天。针对该日期值调用 TO_CHAR
函数将得到 28 或者 29。
MySQL
首先找出当前年份的第一天:先计算出当前日期是当前年份的第几天,用当前日期减去该值,然后再加上 1 天。DATE_ADD
函数能完成这一步。
select date_add(
date_add(current_date,
interval -dayofyear(current_date) day),
interval 1 day) dy
from t1
DY
-----------
01-JAN-2005
接着,再次调用 DATE_ADD
函数在上述计算结果的基础上加上 1 个月。
select date_add(
date_add(
date_add(current_date,
interval -dayofyear(current_date) day),
interval 1 day),
interval 1 month) dy
from t1
DY
-----------
01-FEB-2005
现在得到了 2 月 1 日的日期值,接着调用 LAST_DAY
函数找出 2 月的最后一天。
select last_day(
date_add(
date_add(
date_add(current_date,
interval -dayofyear(current_date) day),
interval 1 day),
interval 1 month)) dy
from t1
DY
-----------
28-FEB-2005
最后,调用 DAY
函数返回 28 或者 29(这一步不是必需的)。
SQL Server
该解决方案利用 WITH
递归查询生成 2 月的每一天。第一步先找出 2 月的第一天。为达到此目的,先找出当前年份的第一天:计算出当前日期是当前年份的第几天,用当前日期减去该值,然后再加上 1 天。既然有了当前年份的第一天,调用 DATEADD
函数加上 1 个月,就能得到 2 月的第一天了。
select dateadd(mm,1,(getdate()-datepart(dy,getdate()))+1) dy
from t1
DY
-----------
01-FEB-2005
接着,返回 2 月的第一天,并计算出该日期对应月份的数值形式。
select dy, month(dy) mth
from (
select dateadd(mm,1,(getdate()-datepart(dy,getdate()))+1) dy
from t1
) tmp1
DY MTH
----------- ---
01-FEB-2005 2
然后利用 WITH
子句的递归特性,不断为内嵌视图 TMP1
返回的 DY
加上 1,直到日期对应的月份不再是 2 月,部分结果如下所示。
with x (dy,mth)
as (
select dy, month(dy)
from (
select dateadd(mm,1,(getdate()-datepart(dy,getdate()))+1) dy
from t1
) tmp1
union all
select dateadd(dd,1,dy), mth
from x
where month(dateadd(dd,1,dy)) = mth
)
select dy,mth from x
DY MTH
----------- ---
01-FEB-2005 02
...
10-FEB-2005 02
...
28-FEB-2005 02
现在得到了 2 月的每一天,最后调用 MAX
函数看一下最后一天是 28 日还是 29 日。还可以调用 DAY
函数返回数字 28 或者 29,而不是一个日期值;不过,这一步不是必需的。