-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy pathcalendar2.sql
119 lines (118 loc) · 5.14 KB
/
calendar2.sql
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
COL res FORMAT A500
WITH p AS ( /*Входные параметры календаря*/
SELECT trunc(SYSDATE,'YEAR') y,
12 mrows,
4 cpd, -- ширина колонки с месцем
4 padd -- расстояние между колонками
FROM dual),
ds AS ( /*Все дни года*/
SELECT to_number(to_char(y+LEVEL-1,'MM')) m,
y+LEVEL-1 yd,
to_char(y+LEVEL-1,'d') wd
FROM p
CONNECT BY LEVEL <=add_months(y,12)-y),
ms AS ( /*Месяцы и их позиция в прямоугольнике 3х4*/
SELECT --+materialize
LEVEL m, -- номер месяца
to_number(to_char(add_months(y,LEVEL-1),'d'))-2 offs, -- мсещение первого дня от начала недели
--/* это по временам года:
MOD(LEVEL,3)*(7*cpd+padd)+2 mcol,
trunc((LEVEL)/3)*mrows mrow
--*/
/* разбросать по столу:
2+trunc(dbms_random.value(1,80)) mcol,
2+trunc(dbms_random.value(1,90)) mrow
--*/
-- по диагонали:
-- 4*level mcol,4*level mrow
FROM p
CONNECT BY LEVEL<=12),
bcal AS ( /*Базовая информация для дней года*/
SELECT m,
yd,
wd, -- день недели (колонка)
trunc((to_number(to_char(yd,'dd'))+offs)/7) lno, --номер строки в месяце
mcol,
mrow
FROM ds JOIN ms USING(m)
ORDER BY yd),
wds AS ( /*Дни недели - для шапки*/
SELECT to_char(SYSDATE+LEVEL,'D') dn,
lpad(to_char(SYSDATE+LEVEL,'fmDy'),cpd,' ') ds
FROM p
CONNECT BY LEVEL<=7),
q AS ( /*Выводимые надписи*/
SELECT r,c,txt
FROM (SELECT m,1 l, /*"Подложки" под месяцы*/
mrow+p1.i AS r,
mcol AS c,
lpad(' ',7*cpd+3,' ') txt
FROM ms,p,(SELECT LEVEL-1 i FROM p CONNECT BY LEVEL<=9) p1
UNION ALL
SELECT /*Дни*/
to_number(to_char(yd,'MM')) m, 2 l,
mrow+2+lno AS r,
mcol+wd*cpd+1-length(to_number(to_char(yd,'DD'))) c,
case when yd=trunc(sysdate) then '**'
else to_char(to_number(to_char(yd,'DD')))
end txt
FROM bcal,p
UNION ALL
SELECT /*Строчки, подчеркивающие месяцы*/
m, 2 l,
mrow+case when m>to_number(to_char(sysdate,'MM')) then 0 else 8 end AS r,
mcol c,
'*'||lpad('-',7*cpd+1,'-')||'*' txt
FROM ms,p
UNION ALL
SELECT /*Заголовки месяцев*/
m, 2 l,
mrow+case when m>to_number(to_char(sysdate,'MM')) then 8 else 0 end AS r,
--(см. выше) вот переключалка названия месяца верх/низ
mcol c,
'*'||lpad('['||to_char(add_months(y,m-1),'fmMonth')||']',7*cpd-1,'-')||'--*' txt
FROM ms,p
UNION ALL
SELECT /*Боковые вертикальные границы*/
m, 2 l,
mrow+radd AS r,
mcol+cadd c,
'|' txt
FROM ms,p,
(SELECT LEVEL radd FROM dual CONNECT BY LEVEL<=7) p1,
(SELECT sign(level-1)*(7*cpd+2) cadd FROM p CONNECT BY LEVEL<=2) p2
UNION ALL
SELECT /*Дни недели в каждом месяце*/
m, 2 l,
mrow+1 AS r,
mcol+1+(dn-1)*cpd c,
ds txt
FROM ms, wds,p
UNION ALL
SELECT /*Год в шапке отчета*/
0 m, 2 l,
1 AS r,
trunc((3*(7*cpd+2)+2*padd)/2-2) c,
to_char(y,'YYYY') txt
FROM p)
ORDER BY abs(-m+to_number(to_char(sysdate,'MM'))) desc, l asc ),
qr as ( /*Упорядочим все выводимые надписи*/
select rownum-1 i, r,c,txt from q),
pvt as ( /*Здесь у нас пивотик - в упор не помню, зачем я его пририсовал, но пусть будет*/
select level-1 i from (select max(r) r from q) connect by LEVEL<r),
mdl as ( /*А вот это, собственно, наш GUI :) */
select *
from qr
model dimension by(i)
measures(r,c,txt,cast(null as varchar2(1000)) res)
rules iterate(1e6) until (r[iteration_number] is null) (
res[r[iteration_number]] = rpad(nvl(substr(res[r[iteration_number]],1,c[iteration_number]-1),' '),c[iteration_number]-1,' ')||
txt[iteration_number]||
substr(res[r[iteration_number]],c[iteration_number]+length(txt[iteration_number]))
)
)
select res
from pvt right join mdl using(i)
WHERE res IS NOT NULL -- пустые строчки не выводим - грубо, конечно, но сойдет для сельской местности
order by i -- Не забудем упорядочить, а то мало ли что
/