如何使用Oracle SQL创建日历

时间:2018-11-30 14:48:08

标签: sql oracle

我可以使用以下脚本创建日历: enter image description here

SELECT CASE
         WHEN (NEW_YWEEK = MIN(NEW_YWEEK)
               OVER(PARTITION BY MON ORDER BY NEW_YWEEK)) THEN
          MON_NAME
         ELSE
          MON_NAME
       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,
                             /*decode(
TO_CHAR(DAYOFYEAR, 'd') ,
'2','1','3','2','4','3','5','4' ,'6','5','7','6' ,'7' )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;

但是以上是将星期日作为一周的第一天,我想将星期一作为一周的第一天,如下所示,谢谢!

enter image description here

2 个答案:

答案 0 :(得分:1)

您可以通过以下操作更简单地做到这一点:

WITH dts AS (SELECT TRUNC(to_date('&year', 'yyyy'), 'yyyy') + LEVEL -1 AS dt
             FROM   dual
             CONNECT BY LEVEL <= to_char(TO_DATE(&YEAR || '1231', 'yyyymmdd'), 'ddd')),
    dts2 AS (SELECT dt,
                    TRUNC(dt, 'mm') dt_mon,
                    TRUNC(dt, 'iw') dt_start_of_week,
                    to_char(dt, 'fmdd') day_of_month
             FROM   dts)
SELECT to_char(dt_mon, 'fmMonth') "MONTH",
       row_number() OVER (PARTITION BY to_char(dt_mon, 'fmMonth') ORDER BY dt_start_of_week) week_num,
       MAX(CASE WHEN dt = dt_start_of_week THEN day_of_month END) mon,
       MAX(CASE WHEN dt = dt_start_of_week + 1 THEN day_of_month END) tue,
       MAX(CASE WHEN dt = dt_start_of_week + 2 THEN day_of_month END) wed,
       MAX(CASE WHEN dt = dt_start_of_week + 3 THEN day_of_month END) thu,
       MAX(CASE WHEN dt = dt_start_of_week + 4 THEN day_of_month END) fri,
       MAX(CASE WHEN dt = dt_start_of_week + 5 THEN day_of_month END) sat,
       MAX(CASE WHEN dt = dt_start_of_week + 6 THEN day_of_month END) sun
FROM   dts2
GROUP BY dt_mon,
         to_char(dt_mon, 'fmMonth'),
         dt_start_of_week
ORDER BY dt_mon, dt_start_of_week;

如果希望一周从星期日开始,则可以在dts2子查询中将dt_start_of_week列更改为trunc(dt + 1, 'iw') - 1 dt_start_of_week,并将这些列的别名从mon-sun更改为sun-sat。

这可以通过找到等周起始日(始终是星期一)来实现。然后,您可以使用它进行分组,并在其上加上row_number分析函数以查找该行的月份中的星期几。

答案 1 :(得分:0)

TO_CHAR(DAYOFYEAR, 'd')的值取决于NLS_TERRITORY参数的值。

您有2个选择:

选项1 将NLS_TERRITORY参数设置为将星期一视为第一天的值(例如“ UNITED KINGDOM”),然后执行以下查询(SUM(DECODE(WDAY,已调整):

ALTER SESSION SET NLS_TERRITORY = 'UNITED KINGDOM';

SELECT CASE
         WHEN (NEW_YWEEK = MIN(NEW_YWEEK)
               OVER(PARTITION BY MON ORDER BY NEW_YWEEK)) THEN
          MON_NAME
         ELSE
          MON_NAME
       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 MON,
       SUM(DECODE(WDAY, '2', MDAY, NULL)) AS TUE,
       SUM(DECODE(WDAY, '3', MDAY, NULL)) AS WED,
       SUM(DECODE(WDAY, '4', MDAY, NULL)) AS THU,
       SUM(DECODE(WDAY, '5', MDAY, NULL)) AS FRI,
       SUM(DECODE(WDAY, '6', MDAY, NULL)) AS SAT,
       SUM(DECODE(WDAY, '7', MDAY, NULL)) AS SUN
  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,
                             /*decode(
TO_CHAR(DAYOFYEAR, 'd') ,
'2','1','3','2','4','3','5','4' ,'6','5','7','6' ,'7' )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'))
--where TO_CHAR(DAYOFYEAR, 'Month') = 'November'
                                   )
 GROUP BY MON, MON_NAME, NEW_YWEEK;

选项2 请勿触摸NLS_TERRITORY参数并在下面的查询中执行({SUM(DECODE(WDAY,已调整,并且WDAY的值的计算方式已更改):

SELECT CASE
         WHEN (NEW_YWEEK = MIN(NEW_YWEEK)
               OVER(PARTITION BY MON ORDER BY NEW_YWEEK)) THEN
          MON_NAME
         ELSE
          MON_NAME
       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 MON,
       SUM(DECODE(WDAY, '2', MDAY, NULL)) AS TUE,
       SUM(DECODE(WDAY, '3', MDAY, NULL)) AS WED,
       SUM(DECODE(WDAY, '4', MDAY, NULL)) AS THU,
       SUM(DECODE(WDAY, '5', MDAY, NULL)) AS FRI,
       SUM(DECODE(WDAY, '6', MDAY, NULL)) AS SAT,
       SUM(DECODE(WDAY, '7', MDAY, NULL)) AS SUN
  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,
               DECODE(MOD(TO_CHAR(DAYOFYEAR, 'd')-1, 7), 0,7, TO_CHAR(DAYOFYEAR, 'd')-1) AS WDAY,
                             /*decode(
TO_CHAR(DAYOFYEAR, 'd') ,
'2','1','3','2','4','3','5','4' ,'6','5','7','6' ,'7' )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'))
--where TO_CHAR(DAYOFYEAR, 'Month') = 'November'
                                   )
 GROUP BY MON, MON_NAME, NEW_YWEEK;