SQL 列出一年中所有的星期五,对于一周的某一天,你想找出一年中与之对应的所有日期。例如,你希望生成一个列表,列出当前年份所有的星期五。
SQL 列出一年中所有的星期五 问题描述
对于一周的某一天,你想找出一年中与之对应的所有日期。例如,你希望生成一个列表,列出当前年份所有的星期五。
SQL 列出一年中所有的星期五 解决方案
不论使用哪一种数据库,解决本问题的关键都在于先列出当前年份的每一天,然后筛选出符合条件的日期。下面的解决方案以找出所有的星期五为例。
DB2
使用 WITH
递归查询列出当前年份的每一天,然后调用 DAYNAME
函数筛选出星期五对应的日期。
Oracle
使用 CONNECT BY
递归查询列出当前年份的每一天,然后调用 TO_CHAR
函数筛选出星期五对应的日期。
PostgreSQL
使用 GENERATE_SERIES
函数列出当前年份的每一天,然后调用 TO_CHAR
函数筛选出星期五对应的日期。
MySQL
使用数据透视表 T500
列出当前年份的每一天,然后调用 DAYNAME
函数筛选出星期五对应的日期。
SQL Server
使用 WITH
递归查询列出当前年份的每一天,然后调用 DAYNAME
函数筛选出星期五对应的日期。
SQL 列出一年中所有的星期五 扩展知识
DB2
为了找出当前年份所有的星期五,我们必须先列出来当前年份的每一天。第一步要调用 DAYOFYEAR
函数找到当前年份的第一天。从当前日期里减去 DAYOFYEAR(CURRENT_DATE)
函数调用的返回值可以得到上一年 12 月 31 日,再加上 1 天就得到了当前年份的第一天。
现在我们知道了当前年份的第一天,接着使用 WITH
子句在当前年份第一天的基础上逐次加上 1 天,直至得到的日期不再属于当前年份。上述得到的结果集将是当前年份的每一天(递归视图 X
查询的部分结果如下所示)。
最后,调用 DAYNAME
函数筛选出星期五对应的日期。
Oracle
为了找到当前年份所有的星期五,我们必须先列出来当前年份的每一天。首先调用 TRUNC
函数得到当前年份的第一天。
然后,使用 CONNECT BY
子句返回当前年份的每一天(参见第 13 章中的相关内容,以了解如何使用 CONNECT BY
生成行数据)。
顺便说一下,虽然本实例采用了基于
WITH
子句的解决方案,但其实也可以使用内嵌视图达到同样目的。
在写作本书时,Oracle 的 WITH
子句并不用于实现递归操作(这不同于 DB2 和 SQL Server),递归操作是由 CONNECT BY
完成的。视图 X
返回的部分结果集如下所示。
最后,调用 TO_CHAR
函数筛选出星期五对应的日期。
PostgreSQL
为了找出当前年份所有的星期五,我们必须先把当前年份的每一天都当作一条记录返回。这里需要使用 GENERATE_SERIES
函数。GENERATE_SERIES
函数返回的起点和终点值分别是 0 和当前年份总天数减 1。传递给 GENERATE_SERIES
函数的第一个参数是 0,第二个参数则是一个查询,该查询用于计算出当前年份有多少天。(因为我们要在当前年份第一天的基础上逐日累加,实际上要累加的天数恰好比当前年份的总天数少 1 天,这样才不至于溢出到下一年。)GENERATE_SERIES
函数的第二个参数返回的结果如下所示。
请记住,根据上述结果集,FROM
子句里的 GENERATE_SERIES
函数调用看起来是这样的:GENERATE_SERIES(0,364)
。如果是闰年,例如 2004 年,第二个参数则是 365。
为了生成当前年份全部日期的列表,下一步就要把 GENERATE_SERIES
函数的返回值依次加上当前年份的第一天。部分结果如下所示。
最后,调用 TO_CHAR
函数筛选出星期五对应的日期。
MySQL
为了找出当前年份的全部星期五,我们先列出来当前年份的每一天。首先要调用 DAYOFYEAR
函数找出当前年份的第一天。从当前日期里减去 DAYOFYEAR(CURRENT_DATE)
函数调用的返回值,然后再加上 1 天,这样就得到了当前年份的第一天。
然后,使用 T500
表生成足够多的行以返回当前年份的每一天。我们要在当前年份第一天的基础上逐一加上 T500.ID
的值,直至当前年份结束。这个操作的部分结果如下。
最后,调用 DAYNAME
函数筛选出星期五对应的日期。
SQL Server
为了找出当前年份所有的星期五,我们必须先列出当前年份的每一天。首先要调用 DATEPART
函数得到当前年份的第一天。从当前日期里减去 DATEPART(DY,GETDATE())
函数调用的返回值,并加上 1 天,就得到了当前年份的第一天。
现在知道了当前年份的第一天,接着使用 WITH
子句和 DATEADD
函数在第一天的基础上逐次加上 1 天,直至当前年份的最后一天。这样一来,得到的结果集就是当前年份的每一天(递归视图 X
返回的部分行如下所示)。
最后,调用 DATENAME
函数筛选出星期五对应的日期。对于本解决方案而言,我们必须设置 MAXRECURSION
的值,使之不小于 366(这是为了过滤递归视图 X
,使得查询结果都是当前年份的数据,并保证结果集不超过 366 行)。