Implementarea calendarului prin intermediul oracolului subordonat

mulțumesc

Acum este foarte la modă să faceți diverse aplicații web, așa că am întâmplat să dezvolte ceva similar, legat de calendar. Deschide pagina de utilizator. în cazul în care pe o parte a unui astfel de calendar lunar mic și în fiecare zi sub forma unei referințe. Faceți clic pe ziua dorită a lunii și acolo aveți știri pentru această zi sau o listă de activități, diverse, afișate.







Ca o bază de date pentru implementarea aplicației, desigur, Oracle a fost ales și ca instrumente de dezvoltare - cu toate acestea, acest lucru nu este important, deoarece Am crezut imediat că ar trebui să existe o soluție SQL simplă, în consecință, nu depinde de instrumentele de dezvoltare.

Desigur, problema care poate fi rezolvată în moduri diferite, dar toate la fel, mi se pare că curat SQL-decizie trebuie să fie cea mai preferabilă, deoarece acesta poate fi folosit în orice mediu de dezvoltare, în cazul în care (arată-mi unde nu este acceptat) este susținută de instrucțiunea SELECT.

În cursul decizia pe care am avut de a face cu o varietate de situații interesante, care de fapt și a determinat să scriu acest articol și sper că va fi de interes nu numai pentru mine, ci și tuturor cititorilor, în special dezvoltatorii de software.

Întrebare filosofică. Este foarte important să alegeți calea cea dreaptă, altfel totul va trebui să înceapă din nou.

În general, pentru imprimarea unui calendar lunar, aveți nevoie de un tabel, în care sunt garantate 31 de intrări. Și nu contează ce este stocat în acest tabel. Tot ce avem nevoie este funcțiile pseudocolumn și date ROWNUM.

Funcția LAST_DAY se întoarce în ultima zi a lunii pentru o anumită dată, TO_CHAR cu o mască de format „DD“ este asociat cu TO_NUMBER dau aceasta ultima zi, ca număr și mai important este numărul de înregistrări pe care doriți să le selectați, și care nu va depăși 31, (Munchhausen nu conta!).
Ei bine, vom alege din preferința reprezentării lui Thomas Kait ALL_OBJECTS:

Începutul este necesar!
Avem o solicitare care revine în toate zilele lunii curente.
Doar nu-mi spuneți că nu este corect să vă bazați pe faptul că vor exista întotdeauna 31 de intrări în vizualizarea ALL_OBJECTS. Da, mă bazez pe asta și cred că această ipoteză este complet justificată!

Vreau să vă atrag atenția asupra faptului că interogarea afișează numai zilele lunii curente (funcția SYSDATE este hardwired), deși ar fi mai corect să vă gândiți cumva posibilitatea de a afișa zile pentru diferite luni. Vreau să împart sarcina în părți. În primul rând, pentru a obține rezultatul cu luna curentă și numai pentru a se angaja în parametrizare. Și acesta este calea cea bună! Nu trebuie să încercați să îmbrățișați imensitatea, trebuie să vă separați și să decideți separat (și doriți să spuneți "să conduceți", dar aceasta este "dreptul de autor" al cuiva :-)).

Ei bine, acum este momentul să trecem la zilele săptămânii. Vreau să mă ocup de acest subiect în detaliu. forțat să admită că, pentru o lungă perioadă de timp, a fost conștient modul de a determina în mod programatic ziua săptămânii pentru o anumită dată :-(. Pentru o lungă perioadă de timp nu am avut, dar câțiva ani în urmă și cu care se confruntă soluția potrivită nu este găsit în curând. Nu ne-ar dori să altcineva a petrecut timp pentru asta.

Pe de o parte, se pare că totul este simplu, luăm funcția și obținem, respectiv, un nume scurt (trei litere) sau întregul din ziua săptămânii. Da, este un noroc, se pare că ziua săptămânii va fi returnată în limba stabilită de parametrii NLS ai sesiunii de utilizatori. Ie dacă utilizatorul primește limba engleză, MON (MONDAY), dacă este rusă, atunci MON (LUNI) va fi emis luni.

Sunteți sigur că toți utilizatorii vor folosi aplicația dvs. cu aceleași setări NLS? Personal, sunt aproape sigur de opusul, și această metodă nu mă convine.

Puteți încerca să utilizați TO_CHAR cu altă mască de format. care în locul numelui returnează numărul zilei din săptămână. Ei bine, numărul nu depinde de limbă! Limba nu depinde de limbă, ci depinde de parametrul NLS care determină teritoriul :-( Dacă în Rusia este luni prima zi a săptămânii, atunci în SUA aceasta este a doua zi.

Ce să facem în această situație? Verificați MON și HDPE în același timp? Nu serios.
Verificați setările utilizatorului la începutul sesiunii și încărcați constantele limbajului pentru fiecare sesiune? Este greoaie.
Scrieți o funcție care returnează ziua săptămânii, indiferent de setările de limbă, beneficiul algoritmului nu este dificil? Probabil ar fi fost așa, dar trebuie să existe o soluție normală!

Probabil, în viața fiecărui dezvoltator există momente în care, după mai mulți ani de folosire constantă a cevaului, aflați brusc ceva nou pe care l-ați lipsit întotdeauna și că cea mai ofensivă a fost aproape la suprafață. Am văzut (citit) reacția lui Stephen Furstein la comanda @@ în sqlplus și asta după ce a scris versiunea inițială a PL / Vision. În cazul meu, o furtună de emoție a fost cauzată de capacitățile funcției TO_CHAR.

Cheia soluției a fost atât de simplă, în măsura în care inițial această problemă părea insolvabilă. Se pare că funcția TO_CHAR are un al treilea parametru care vă permite să setați limba în care ar trebui returnată data! Acesta va întoarce întotdeauna MON pentru luni, indiferent de setările de utilizator NLS.

Apropo, știi ce ar trebui să se întoarcă expresia logică: cu condiția ca my_date să fie luni?

Așa e, FALSE!
De ce? Deoarece funcția TO_CHAR în acest caz se va întoarce cu spațiile libere la cea mai lungă (din punct de vedere scris) zi a săptămânii Miercuri. În consecință, dacă puneți NLS_DATE_LANGUAGE în limba rusă, atunci toate zilele întregi ale săptămânii vor fi aliniate la 11 caractere (până luni).
Pentru utilizarea corectă a întregii zile a săptămânii, trebuie să adăugați modificatorul fm în masca de format DAY:

La sfârșitul discuțiilor despre zilele săptămânii, vreau să spun că există multe aplicații care, deși au fost dezvoltate în Rusia (sau adaptate pentru Rusia), dar folosesc engleza ca limbă pentru afișarea datei. Este probabil ca determinarea incorectă a zilelor din săptămână să fie unul dintre motivele.

Deseori în diverse teleconferințe puteți auzi întrebarea cum să construiți un raport de matrice. Și, de preferință, o comandă SELECT.

Luați în considerare această problemă în tabelul preferat (cel puțin eu) EMP. Pentru a obține suma totală a salariilor în contextul posturilor este destul de ușoară:







Dar dacă vrem să vedem aceste informații și în cadrul departamentelor? Se pare că este necesară coloana SUM_SAL:
  • împărțit în mai multe coloane (după numărul de departamente)
  • distribuie datele între aceste coloane
Al doilea este rezolvat cu ajutorul funcției DECODE. De exemplu, pentru a obține suma salariului pentru un departament cu un număr (deptno) 10 puteți utiliza: Cu primul un pic mai complicat. În forma cea mai simplă, dacă cunoaștem în prealabil toate departamentele disponibile, atunci ele pot fi pur și simplu enumerate: Se pare că situația în care știm în avans câți coloane ar trebui să avem nu este atât de rară. Și această metodă este suficientă pentru a construi un așa-numit raport pseudo-matrice. Acest lucru este în mod special obișnuit în rapoartele financiare, în care trebuie să primiți date în termen de trimestre, luni. Știm în avans că există sferturi - 4, luni - 12. Chiar și numele acestora știm :-) Deci, în cazul nostru, revenind la calendar, știm în prealabil că trebuie să ne rupem singura coloană cu 7, cu numărul de zile din săptămână. Cum să determinăm ziua din săptămână, am aflat și în secțiunea anterioară. Deci, acum nimic nu împiedică să ia următorul pas în vederea atingerii acestui obiectiv: În rezultatul acestei interogări, vedeți în secțiunea următoare, dar acum vreau să atrag atenția asupra faptului că am făcut cererea de bază atașat (transferat in fraza din - vizualizare inline). Există mai multe motive pentru aceasta:
  • Îmbunătățirea lizibilității interogării.
    Funcția lungă TO_CHAR în ortografie are un alias (ziua_dimensional), care descrie în mod clar valoarea returnată. Fără un alias, nu toată lumea va determina imediat că această funcție revine. Acesta este un exemplu al așa-numitului cod de auto-documentare.
    În plus, acum putem duplica săptămâna scurtă de șapte ori în interogarea principală, în loc de TO_CHAR lung. Încearcă să transferi TO_CHAR din subdotare în partea de sus în DECODĂ și să încerci să dai seama de hash-ul rezultat.
  • Performanță îmbunătățită.
    Funcția TO_CHAR este executată o singură dată pentru fiecare zi de întoarcere a lunii. Dacă am folosi o interogare, atunci ar fi executată de șapte ori pentru fiecare zi. Da, probabil, în acest exemplu, modificarea performanței nu va fi deloc vizibilă, dar dacă în loc de TO_CHAR ar exista o funcție definită de utilizator și înregistrările returnate ar depăși cu mult 30, efectul ar fi puternic.

Sunt bine cu rapoartele matrice "împușcat"! Odată ajuns în tufișuri.
Și ce ar trebui să fac dacă trebuie să obțin un raport real de matrice atunci când numărul de coloane nu este cunoscut în prealabil?

Doar doriti sa dezamagiti pe cei care doresc sa obtina aceasta singura cerere. Nu cunosc o astfel de metodă. Dacă cineva știe - anunțați-mă. Soluția pe care o propun se bazează pe faptul că, din moment ce numărul de coloane necesare pentru interogare nu este cunoscut în prealabil, înseamnă că trebuie definit mai întâi și apoi generat dinamic și executat comanda SELECT necesară.

O implementare particulară va depinde de timpul de execuție al raportului. Vă voi arăta două moduri, așa cum se face în SQL * Plus, pentru că cu excepția cazului în care și Oracle Reports (care acceptă construirea rapoartelor matriceale) cu alte mijloace de elaborare a rapoartelor nu sunt familiare.

Deci, înapoi la calendar. Iată rezultatul interogării anterioare.

Prima impresie este dublă. Pe de o parte, s-au dovedit într-adevăr șapte coloane și data de zi a săptămânii este distribuită corect, iar pe de altă parte nu este ceea ce avem nevoie. Avem nevoie de toate datele unei săptămâni pentru a fi pe o linie, și aici.

Și ceea ce am vrut, deoarece adăugarea mai multor coloane la interogare nu afectează numărul de înregistrări returnate. La 30 de ani, rămâne. Trebuie să vină cu un fel, care în loc de 30 de înregistrări vor rămâne 5 dorite.

Primul lucru care vine în minte este adăugarea unei grupări (GROUP BY) la interogare. Dar pentru ao adăuga trebuie să determinați:
  • Expresia pentru grupare (care este scrisă în GROUP BY)
  • Cum vom converti mai multe înregistrări într-una (care funcția agregată de utilizat)

Este evident că trebuie să vă grupați săptămânal. Dar cum de a forma o expresie care se întoarce în această săptămână? Și din nou, TO_CHAR ne va ajuta. Această funcție are o altă mască de format IW, care returnează numărul ordinal al săptămânii într-un an. Acesta este exact ceea ce avem nevoie!

Care este funcția agregată de aplicat?
Dacă te uiți la înregistrările care vor fi supuse grupare, este ușor de observat că în fiecare grup de înregistrări (săptămână) pentru fiecare coloană (zi) va fi umplut cu o singură intrare (numărul), iar restul va fi gol (NULL). Avem nevoie de funcția de grup pentru a returna această singură valoare. Pentru a face acest lucru, puteți utiliza diferite funcții, am ales MAX.

Principiile programării structurate fac necesară evitarea reutilizării codului. Prin urmare, o nevoie urgentă de a crea o reprezentare (vizualizare) cu textul cererii, atâta timp cât dezvoltatorii nu au timp „ponavtykat“, aceasta în programele lor. Da, dar cum obții calendarele pentru alte luni? În timp ce utilizați o singură interogare, puteți înlocui pur și simplu SYSDATE la o altă dată. Și cum să faceți acest lucru cu prezentarea?

Aici ne întoarcem la subiectul atins de la început despre împărțirea sarcinii în părți. Am prevăzut deja că interogarea finală ar trebui să fie plasată în vedere. Acum este timpul să decideți cum să parametrizați această vizualizare.

Având în vedere că prezentarea textului (spre deosebire de textul unei declarații SELECT), nu putem schimba de la cerere, pentru a solicita (sau mai degrabă ar trebui să nu), se pare că trebuie să o facă așa cum este în mod indirect.
Tehnica standard este de a folosi o reprezentare a funcției personalizate în text. Această funcție returnează o valoare pe care o putem specifica apelând o altă procedură. Lucrul cu o astfel de vizualizare parametrizată este după cum urmează. Ați specificat valoarea dorită cu procedura, apoi ați executat interogarea la vizualizare. Au setat o altă valoare, au executat interogarea și aceeași afișare returnează alte date.

Principalul lucru este că valoarea specificată de procedură este păstrată în timpul sesiunii de utilizator. Pentru a implementa acest lucru, pachetul PL / SQL este ideal. În corpul pachetului, vom crea o variabilă de lot care își păstrează valoarea pe întreaga sesiune a utilizatorului. În specificație, definim o funcție care returnează valoarea variabilei de lot și procedura specificată de ea.

Acum puteți afișa calendare pentru o lună, și dacă încă nu specifică, implicit este de a utiliza luna curentă, ceea ce pare destul de logic: Ca postkriptuma din această secțiune, vreau să spun că, dacă lucrați cu Oracle Portal, nu se poate Utilizați variabilele de lot pentru a stoca valori în timpul sesiunii. Oracle Portal folosește sesiunile sale, și nu este asociat cu ceea ce suntem obișnuiți să înțelegem prin sesiunea de utilizatori. Alternativ, trebuie să utilizați API-ul oferit de tip obiect WWSTO_API_SESSION, care se află într-un circuit-portal și proprietarul. Puteți afla detalii despre lucrul cu acest tip în caietul de sarcini.

Îți place să-ți testezi programele?
Zambetul? Sau răsucit? De asemenea, nu-mi place și nu am mai văzut pe cei care iubesc. Unii dezvoltatori, ca scuză, spun că dezvoltatorul însuși nu poate testa în mod corespunzător programul său, ce ar trebui să facă ceilalți oameni.

Aici totul trebuie aranjat în locul lui. Test - testul este diferit. Există o așa-numită încercare a unui modul separat (unitate de testare), pe care dezvoltatorul însuși trebuie să o efectueze. Acesta este un test al procedurilor individuale, rapoartelor, formularelor de ecran. Și există un test de sistem în care este necesară testarea interacțiunii în sistemul de module individuale. Aici testul de sistem ar trebui să fie făcut nu de dezvoltatori, ci de străini (un grup ideal de exploatare).

Instrucțiunea CASE introdusă în versiunea 8.1.6 este foarte potrivită pentru descrierea acestor condiții:

Ei bine, acum se pare totul. A funcționat!

Nu este totul. Toate - pentru cei care au versiunea Oracle 8.1.6 și mai în vârstă, dar dacă nu?
Desigur, puteți scrie o funcție personalizată, dar nu aruncați DECODĂ. Această funcție veche bună poate servi, de asemenea, în acest caz.

Mai ales pentru fanii decodifica și cei cu mai puțin de Oracle versiunea 8.1.6, voi arăta cum să se uite coloana WEEK_NUM folosind DECODE: uite voluminoase, cred că CASE în acest loc pare mai de preferat. Cu toate acestea, acest lucru nu înseamnă că ai nevoie de DECODE universal refuza CASE. În acest punct de vedere, există o altă funcție DECOFIDICAREA: care este, în opinia mea, arată foarte concis și ușor de înțeles.
Rescriind această funcție DECODARE pe CASE, mi se pare că vom pierde doar.

Mai mult decât atât, decizia finală este inclusă cu versiunea DECOFIDICAREA (pentru o acoperire mai mare versiuni Oracle). Deci, dacă preferați CASE, utilizați V_CALENDAR reprezentare text din secțiunea anterioară.

Înainte de a utiliza soluția de mai jos, recomandăm cu insistență să citiți din nou recenziile articolului. acestea conțin observații foarte importante și utile, precum și două soluții alternative.







Articole similare

Trimiteți-le prietenilor: