Poniżej jest kolejny przykład wykorzystania klauzuli model w wersji iteracyjnej, tym razem do wygenerowania kalendarza z uwzględnieniem świąt i dni roboczych na rok 2016. Jest zdefiniowany jeden wymiar oraz cztery miary: data, nazwa dnia tygodnia, nazwa święta obchodzonego w danym dniu oraz informacja, czy dany dzień jest roboczy.
Dodatkowo został przedstawiony sposób tworzenia funkcji nieskładowanych definiowanych jedynie na potrzeby SQL. To jest bardzo wygodne rozwiązanie, bo upraszcza składnię zapytań, zamiast komplikować składnię zapytania, niektóre fragmenty czytelniej jest przenieść do funkcji - np. kiedy byśmy chcieli napisać ogólny algorytm obliczania świąt ruchomych, to moim zdaniem lepiej umieścić go w procedurze Fdb_JestSwieto.
Przy pisaniu zapytania położyłem większy nacisk na czytelność niż wydajność..
WITH FUNCTION Fdb_JestSwieto(pd_dt DATE) RETURN VARCHAR2 AS
pn_Month NUMBER;
pn_Day NUMBER;
BEGIN
pn_Day := EXTRACT (DAY FROM pd_dt);
pn_Month := EXTRACT (MONTH FROM pd_dt);
IF pn_Month = 1 AND pn_Day =1 THEN
RETURN 'Nowy Rok';
ELSIF pn_Month = 1 AND pn_Day =6 THEN
RETURN 'Święto Trzech Króli' ;
ELSIF pn_Month = 3 AND pn_Day =27 THEN
RETURN 'Wielkanoc' ;
ELSIF pn_Month = 3 AND pn_Day =28 THEN
RETURN 'Poniedziałek Wielkanocny';
ELSIF pn_Month = 5 AND pn_Day =1 THEN
RETURN 'Święto Pracy';
ELSIF pn_Month = 5 AND pn_Day =3 THEN
RETURN 'Święto Konstytucji 3 Maja';
ELSIF pn_Month = 5 AND pn_Day =15 THEN
RETURN 'Zielone Świątki';
ELSIF pn_Month = 5 AND pn_Day =26 THEN
RETURN 'Boże Ciało';
ELSIF pn_Month = 8 AND pn_Day =15 THEN
RETURN 'Wniebowzięcie NMP';
ELSIF pn_Month = 11 AND pn_Day =1 THEN
RETURN 'Wszystkich Świętych';
ELSIF pn_Month = 11 AND pn_Day =11 THEN
RETURN 'Święto Niepodległości';
ELSIF pn_Month = 12 AND pn_Day IN (25, 26) THEN
RETURN 'Boże Narodzenie';
END IF;
RETURN NULL;
END;
SELECT
DZIEN , DZIEN_TYGODNIA, SWIETO,
DZIEN_ROBOCZY
FROM (SELECT 0 a FROM DUAL)
MODEL
DIMENSION BY (0 lp)
MEASURES (TO_DATE('2016-01-01', 'YYYY-MM-DD') DZIEN,
CAST(NULL AS VARCHAR2(30 CHAR)) SWIETO,
CAST(NULL AS VARCHAR2(30 CHAR)) DZIEN_TYGODNIA,
CAST( NULL AS NUMBER(1)) DZIEN_ROBOCZY )
RULES
ITERATE (10000000) UNTIL ( ITERATION_NUMBER = 365)
(
DZIEN[ ITERATION_NUMBER ] = DZIEN[0] + ITERATION_NUMBER,
SWIETO[ ITERATION_NUMBER ] = Fdb_JestSwieto( DZIEN [ ITERATION_NUMBER ]),
DZIEN_TYGODNIA[ ITERATION_NUMBER ] = TO_CHAR(DZIEN [ ITERATION_NUMBER ], 'DAY'),
DZIEN_ROBOCZY [ ITERATION_NUMBER ] = CASE WHEN SWIETO [ ITERATION_NUMBER ] IS NOT NULL OR TO_CHAR(DZIEN [ ITERATION_NUMBER ], 'D') IN ('6','7')
THEN 0
ELSE 1
END
)