Friday, November 24, 2006

SQL Puzzle VI.

The calendar (man 1 cal) is reborn from the ashes...

SQL> REM  Copyright(c) 2000,2002,2006 Vladimir Begun, All Rights Reserved.
SQL> REM  No warranty, the code is distributed "as is". This header
SQL> REM  must not be removed in case of using the code or the algorithm.
SQL> 
SQL> REM
SQL> REM This code is based on the original idea of mine published at:
SQL> REM http://www.oracle.com/global/ru/oramag/april2003/russia_com_cal.html
SQL> REM
SQL> REM The original Pavel's (Hi, Pavel!) article was published at:
SQL> REM http://www.geocities.com/luzanovp/calendar_comments.html
SQL> REM
SQL> REM No performance test were done, just introduced some code
SQL> REM improvements
SQL> REM
SQL> DEFINE cd = "COALESCE(TO_DATE(SYS_CONTEXT('MY_CTX', 'CAL_DATE'), 'YYYYMMDD'), SYSDATE)"
SQL> SET DEFINE "&" VERIFY OFF
SQL> 
SQL> 
SQL> CREATE OR REPLACE VIEW vb_calendar_v
  2  AS
  3  /*
  4     Copyright(c) 2000,2002,2006 Vladimir Begun, All Rights Reserved.
  5     No warranty, the code is distributed "as is". This header
  6     must not be removed in case of using the code or the algorithm.
  7  */
  8  WITH calendar_days AS (
  9    SELECT ROWNUM dd
 10         , DECODE(MOD(ROWNUM, 7)
 11                 , 0, 7
 12                    , MOD(ROWNUM, 7)
 13           ) rn
 14      FROM dual
 15   CONNECT BY LEVEL <= 31
 16  )
 17    SELECT
 18           d1
 19         , d2
 20         , d3
 21         , d4
 22         , d5
 23         , d6
 24         , d7
 25      FROM (
 26           SELECT 'DAYS' AS d0
 27                , MAX(DECODE(day_of_week, '1', name_of_day)) AS d1
 28                , MAX(DECODE(day_of_week, '2', name_of_day)) AS d2
 29                , MAX(DECODE(day_of_week, '3', name_of_day)) AS d3
 30                , MAX(DECODE(day_of_week, '4', name_of_day)) AS d4
 31                , MAX(DECODE(day_of_week, '5', name_of_day)) AS d5
 32                , MAX(DECODE(day_of_week, '6', name_of_day)) AS d6
 33                , MAX(DECODE(day_of_week, '7', name_of_day)) AS d7
 34             FROM (
 35                  SELECT LPAD(TO_CHAR(&&cd + dd, 'DY'), 3) AS name_of_day
 36                       , TO_CHAR(&&cd + dd, 'D') AS day_of_week
 37                    FROM calendar_days
 38                   WHERE dd <= 7
 39                  )
 40           UNION ALL
 41           SELECT 'WEEKS' || week_of_month AS d0
 42                , MAX(DECODE(day_of_week, '1', day_of_month)) AS d1
 43                , MAX(DECODE(day_of_week, '2', day_of_month)) AS d2
 44                , MAX(DECODE(day_of_week, '3', day_of_month)) AS d3
 45                , MAX(DECODE(day_of_week, '4', day_of_month)) AS d4
 46                , MAX(DECODE(day_of_week, '5', day_of_month)) AS d5
 47                , MAX(DECODE(day_of_week, '6', day_of_month)) AS d6
 48                , MAX(DECODE(day_of_week, '7', day_of_month)) AS d7
 49             FROM (
 50                  SELECT DECODE(dd
 51                               , TO_NUMBER(TO_CHAR(&&cd, 'DD')), '['
 52                                                              || LPAD(TO_CHAR(dd, 'FM99'), 2)
 53                                                              || ']'
 54                                                               , LPAD(TO_CHAR(dd, 'FM99'), 3)
 55                         ) AS day_of_month
 56                       , SIGN(SIGN(rn - TO_NUMBER(TO_CHAR(TRUNC(&&cd, 'MM') + dd - 1, 'D'))) - 1)
 57                       + TO_NUMBER(TO_CHAR(TRUNC(&&cd, 'MM') + dd - 1, 'W')) AS week_of_month
 58                       , TO_CHAR(TRUNC(&&cd, 'MM') + dd - 1, 'D') AS day_of_week
 59                    FROM calendar_days
 60                   WHERE dd <= TO_NUMBER(TO_CHAR(LAST_DAY(&&cd), 'DD'))
 61                  )
 62            GROUP BY
 63                  week_of_month
 64           )
 65     ORDER BY d0
 66  /

Представление создано.

SQL> SET FEEDBACK OFF TERMOUT ON HEADING OFF VERIFY OFF LINES 100
SQL> COLUMN d1 FORMAT A4 ALIAS d
SQL> COLUMN d2 LIKE d
SQL> COLUMN d3 LIKE d
SQL> COLUMN d4 LIKE d
SQL> COLUMN d5 LIKE d
SQL> COLUMN d6 LIKE d
SQL> COLUMN d7 LIKE d
SQL> 
SQL> ALTER SESSION SET NLS_TERRITORY=AMERICA NLS_DATE_LANGUAGE=AMERICAN;
SQL> SELECT * FROM vb_calendar_v;

SUN  MON  TUE  WED  THU  FRI  SAT
                 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
SQL> ALTER SESSION SET NLS_TERRITORY=GERMANY NLS_DATE_LANGUAGE=GERMAN;
SQL> SELECT * FROM vb_calendar_v;

 MO   DI   MI   DO   FR   SA   SO
            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
SQL> ALTER SESSION SET NLS_TERRITORY=CIS NLS_DATE_LANGUAGE=RUSSIAN;
SQL> SELECT * FROM vb_calendar_v;

 П    В    С    Ч    П    С    В
            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

No comments: