ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 【转载】日历

【转载】日历

原创 Linux操作系统 作者:klamm0 时间:2009-11-09 12:52:35 0 删除 编辑
SQL的魅力是无限的。这里给大家展示一下使用SQL得到日历,同时,用SQL*Plus的break命令格式化显示效果。

sys@ora10g> break on month skip 1
sys@ora10g> col month for a20
sys@ora10g> col Su for a4
sys@ora10g> col Mo for a4
sys@ora10g> col Tu for a4
sys@ora10g> col We for a4
sys@ora10g> col Th for a4
sys@ora10g> col Fr for a4
sys@ora10g> col Sa for a4
sys@ora10g> select LPAD (Month, 20 - (20 - LENGTH (month)) / 2) month,
  2         "Su",
  3         "Mo",
  4         "Tu",
  5         "We",
  6         "Th",
  7         "Fr",
  8         "Sa"
  9    from (select TO_CHAR (dt, 'fmMonthfm YYYY') month,
 10                 case
 11                    when TO_CHAR (dt, 'fmMonthfm YYYY') like 'Dec%'
 12                     and TO_CHAR (dt + 1, 'iw') = '01'
 13                    then
 14                       '53'
 15                    when TO_CHAR (dt, 'fmMonthfm YYYY') like 'Jan%'
 16                     and TO_CHAR (dt + 1, 'iw') = '53'
 17                    then
 18                       '.5'
 19                    else
 20                       TO_CHAR (dt + 1, 'iw')
 21                 end
 22                    week,
 23                 MAX(DECODE (TO_CHAR (dt, 'd'),
 24                             '1', LPAD (TO_CHAR (dt, 'fmdd'), 2)))
 25                    "Su",
 26                 MAX(DECODE (TO_CHAR (dt, 'd'),
 27                             '2', LPAD (TO_CHAR (dt, 'fmdd'), 2)))
 28                    "Mo",
 29                 MAX(DECODE (TO_CHAR (dt, 'd'),
 30                             '3', LPAD (TO_CHAR (dt, 'fmdd'), 2)))
 31                    "Tu",
 32                 MAX(DECODE (TO_CHAR (dt, 'd'),
 33                             '4', LPAD (TO_CHAR (dt, 'fmdd'), 2)))
 34                    "We",
 35                 MAX(DECODE (TO_CHAR (dt, 'd'),
 36                             '5', LPAD (TO_CHAR (dt, 'fmdd'), 2)))
 37                    "Th",
 38                 MAX(DECODE (TO_CHAR (dt, 'd'),
 39                             '6', LPAD (TO_CHAR (dt, 'fmdd'), 2)))
 40                    "Fr",
 41                 MAX(DECODE (TO_CHAR (dt, 'd'),
 42                             '7', LPAD (TO_CHAR (dt, 'fmdd'), 2)))
 43                    "Sa"
 44            from (select TRUNC (SYSDATE, 'y') - 1 + ROWNUM dt
 45                    from all_objects
 46                   where ROWNUM <=
 47                            ADD_MONTHS (TRUNC (SYSDATE, 'y'), 12)
 48                            - TRUNC (SYSDATE, 'y'))
 49          group by TO_CHAR (dt, 'fmMonthfm YYYY'), TO_CHAR (dt + 1, 'iw')
 50          order by TO_CHAR (dt + 1, 'iw'))
 51  order by TO_DATE (month, 'Month YYYY'), TO_NUMBER (week)
 52  /

MONTH                Su   Mo   Tu   We   Th   Fr   Sa
-------------------- ---- ---- ---- ---- ---- ---- ----
    January 2009                          1    2    3
                      4    5    6    7    8    9   10
                     11   12   13   14   15   16   17
                     18   19   20   21   22   23   24
                     25   26   27   28   29   30   31

   February 2009      1    2    3    4    5    6    7
                      8    9   10   11   12   13   14
                     15   16   17   18   19   20   21
                     22   23   24   25   26   27   28

     March 2009       1    2    3    4    5    6    7
                      8    9   10   11   12   13   14
                     15   16   17   18   19   20   21
                     22   23   24   25   26   27   28
                     29   30   31

     April 2009                      1    2    3    4
                      5    6    7    8    9   10   11
                     12   13   14   15   16   17   18
                     19   20   21   22   23   24   25
                     26   27   28   29   30

      May 2009                                 1    2
                      3    4    5    6    7    8    9
                     10   11   12   13   14   15   16
                     17   18   19   20   21   22   23
                     24   25   26   27   28   29   30
                     31

     June 2009             1    2    3    4    5    6
                      7    8    9   10   11   12   13
                     14   15   16   17   18   19   20
                     21   22   23   24   25   26   27
                     28   29   30

     July 2009                       1    2    3    4
                      5    6    7    8    9   10   11
                     12   13   14   15   16   17   18
                     19   20   21   22   23   24   25
                     26   27   28   29   30   31

    August 2009                                     1
                      2    3    4    5    6    7    8
                      9   10   11   12   13   14   15
                     16   17   18   19   20   21   22
                     23   24   25   26   27   28   29
                     30   31

   September 2009               1    2    3    4    5
                      6    7    8    9   10   11   12
                     13   14   15   16   17   18   19
                     20   21   22   23   24   25   26
                     27   28   29   30

    October 2009                          1    2    3
                      4    5    6    7    8    9   10
                     11   12   13   14   15   16   17
                     18   19   20   21   22   23   24
                     25   26   27   28   29   30   31

   November 2009      1    2    3    4    5   6    7
                      8    9   10   11   12   13   14
                     15   16   17   18   19   20   21
                     22   23   24   25   26   27   28
                     29   30

   December 2009                1    2    3    4    5
                      6    7    8    9   10   11   12
                     13   14   15   16   17   18   19
                     20   21   22   23   24   25   26
                     27   28   29   30   31


61 rows selected.
 
 
 
 
select case
           when (new_yweek = min(new_yweek)over(partition by mon order by new_yweek)) then
             mon_name
           else
             null
         end as month,
         new_yweek as yweek,
         row_number() over(partition by mon order by new_yweek) as mweek,
         sum(decode(wday, '1', mday, null)) as sun,
         sum(decode(wday, '2', mday, null)) as mon,
         sum(decode(wday, '3', mday, null)) as tue,
         sum(decode(wday, '4', mday, null)) as wed,
         sum(decode(wday, '5', mday, null)) as thu,
         sum(decode(wday, '6', mday, null)) as fri,
         sum(decode(wday, '7', mday, null)) as sat
    from (select dayofyear as everyday,
                 to_char(dayofyear, 'mm') as mon,
                 to_char(dayofyear, 'Month') as mon_name,
                 to_char(dayofyear, 'w') as mweek,
                 to_char(dayofyear, 'ww') as yweek,
                 case
                   when (to_char(to_date(&year || '0101', 'yyyymmdd'), 'd') > '1') and
                        (to_char(dayofyear, 'd') <
                        to_char(to_date(&year || '0101', 'yyyymmdd'), 'd')) then
                    to_char(to_char(dayofyear, 'ww') + 1, 'fm00')
                   else
                    to_char(dayofyear, 'ww')
                 end as new_yweek,
                 to_char(dayofyear, 'd') as wday,
                 to_char(dayofyear, 'dd') as mday
            from (select to_date(&year || '0101', 'yyyymmdd') + level - 1 as dayofyear
                    from dual
                  connect by level <= to_char(to_date(&year || '1231', 'yyyymmdd'),'ddd')
                 )
         )
   group by mon, mon_name, new_yweek
 
1. 构造全年日期数据


  select to_date(&year || '0101', 'yyyymmdd') + level - 1 as dayofyear
    from dual
   connect by level <= to_char(to_date(&year || '1231', 'yyyymmdd'),'ddd')


在这里使用了connect by来构造数据(会受到数据库版本限制,适用于9.2或更高版本),
to_char(to_date(&year || '1231', 'yyyymmdd'),'ddd') 用来计算全年的天数, 这个虽然不是唯一的方法, 但也算是比较简单的方法了

2. 根据全年日期, 得到月/周等数据


  select dayofyear as everyday,
         ...
    from (select 全年日期 ...)


里面分别取了 mm/month/w/ww/d/dd 等数据, 
其中mm是后面用来排序的, month是后面用来显示月份的(因为month得到的数据不便于月份排序, 而mm的数据显示起来不好), 
w和ww在这里是冗余数据, 为了便于看中间数据的,
d 是用来行列转换的, dd是用来显示日期的(即几号)
而那个用case生成的new_yweek是行列转换时的分组标记, 为什么在这里不用IW呢, 而是这么麻烦的用case和ww呢?
因为我最终的显示sunday(星期天)是放在第一列的, 直观表示为一周的第一天, 如果是放在最后一列, 直观表示一周的最后一天的话, 用IW就可以了.

3. 根据周次和月份做行列转换, 把星期日~星期六转为7列


  select case ... as month,
         ...
    from (全年各种日期信息数据)
   group mon, mon_name, new_yweek


最终的 month 字段显示的是月份名称, 为了省去后面数行相同月份的名称, 因此用了case和分析函数;
yweek是用来表示全年的周次, 从1开始;
mweek是用来表示月中的周次, 每月从1开始;
其后从 sun ~ sat 就是每个星期几对应的月日了
如果之前to_char时用了IW而不是WW的话, 记得要把sun放到最后一列哦, 否则看着就不像日历了, ^_^.

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/22786751/viewspace-618409/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论

注册时间:2009-10-30

  • 博文量
    58
  • 访问量
    58091