Как использовать Oracle SQL для создания календаря - PullRequest
0 голосов
/ 30 ноября 2018

Я могу создать календарь с помощью этого скрипта: 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 голосов
/ 30 ноября 2018

Значение TO_CHAR(DAYOFYEAR, 'd') зависит от значения параметра NLS_TERRITORY.

У вас есть 2 варианта:

Опция 1 Установите для параметра NLS_TERRITORY значение, для которого установлен понедельник.рассматривается как 1-й день (например, «СОЕДИНЕННОЕ КОРОЛЕВСТВО») и выполнить запрос ниже (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;
0 голосов
/ 30 ноября 2018

Вы можете сделать это намного проще, выполнив:

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;

Если вы хотите, чтобы неделя начиналась с воскресенья, вы можете изменить столбец dt_start_of_week на trunc(dt + 1, 'iw') - 1 dt_start_of_week в подзапросе dts2, кака также изменение псевдонимов столбцов с mon-sun на sun-sat.

Это работает путем нахождения дня начала iso недели, который всегда является понедельником.Затем вы можете использовать это для группировки, плюс добавив к нему аналитическую функцию row_number, чтобы найти номер недели в номере этой строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...