Studii de Caz Access 2007

206
Baze de date Access 2007 - Studii de caz – Editura 2009

Transcript of Studii de Caz Access 2007

Page 1: Studii de Caz Access 2007

Baze de date Access 2007 - Studii de caz –

EEddiittuurraa

22000099

Page 2: Studii de Caz Access 2007

22000099 EEddiittuurraa IInnffooMMeeggaa

Toate drepturile rezervate. Reproducerea materialelor din această lucrare se poate face doar cu acordul scris al editurii. Autorii îşi asumă răspunderea asupra materialelor publicate.

Editură acreditată de C.N.C.S.I.S. � ee--mmaaiill:: ooffffiiccee@@iinnffoommeeggaa..rroo � hhttttpp::////wwwwww..iinnffoommeeggaa..rroo

CIP Nr. 6275/27.03.2009

Descrierea CIP a Bibliotecii Naţionale Baze de date Access 2007 : studii de caz / Stanciu Andrei (coord.), Mihai Florin, Mangiuc Dragoş, … - Bucureşti : InfoMega, 2009 Bibliogr. ISBN 978-973-7853-41-7 I. Stanciu, Andrei (coord.) II. Mihai, Florin III. Mangiuc, Dragoş

004.65

Microsoft Excel, Microsoft Word şi Microsoft Access 2007 sunt mărci înregistrate ale Microsoft Corporation

Page 3: Studii de Caz Access 2007

Cuvânt înainteCuvânt înainteCuvânt înainteCuvânt înainte

Rod al colaborării unui grup de tineri autori, cadre didactice universitare în Academia de Studii Economice Bucureşti, cartea se adresează tuturor celor pasionaţi de informatica de gestiune în general şi de dezvoltarea aplicaţiilor informatice cu baze de date în particular.

Obiectivul principal al lucrării este acela de a oferi studenţilor un sprijin în realizarea proiectelor proprii, de a le oferi idei şi soluţii pentru dezvoltarea aplicaţiilor şi de a le deschide interesul spre domeniul bazelor de date.

Cartea conţine 11 studii de caz ce tratează operaţii de gestiune în cadrul diferitor entităţi organizaţionale. Urmărind scopul didactic al lucrării, autorii au încercat să reflecte într-o măsură cât mai mare realitatea economică dar, în unele situaţii, din considerente didactice, studiile de caz au fost simplificate în sensul formulării regulilor de gestiune şi a limitării numărului de atribute, pentru a face modelele cât mai accesibile.

Proiectarea modelelor relaţionale pentru bazele de date este realizată pe baza teoriei normalizării şi, pentru fiecare studiu de caz, sunt exemplificate cereri de interogare a datelor şi propuneri privind proiectarea elementelor de interfaţă şi a situaţiilor de raportare prin facilităţile existente în Microsoft Access 2007.

În speranţa că cititorii vor găsi utile exemplele prezentate şi vor avea curiozitatea să testeze şi, de ce nu, să îmbunătăţească aceste soluţii, fiecare studiu de caz oferă câteva propuneri de extindere a modelelor şi idei de exerciţii a căror rezolvare este lăsată la latitudinea cititorilor.

Încheiem această scurtă introducere mulţumind pentru sprijinul acordat pe tot parcursul colaborării în cadrul colectivului de baze de date din catedra de Informatică de Gestiune, profesorilor Pavel Năstase, Vasile Florescu şi doamnei profesoare Florentina Berbec.

Autorii

Page 4: Studii de Caz Access 2007
Page 5: Studii de Caz Access 2007

CuprinsCuprinsCuprinsCuprins

I. Bază de date pentru evidenţa împrumuturilor de cărţi în cadrul unei biblioteci…………………………….………………. 7

Autor: Asistent univ. drd. Rădulescu Cristina

II. Bază de date pentru evidenţa contractelor încheiate de o agenţie de turism………………………………..... 28

Autor: Conferenţiar univ. dr. Oancea Mirela

III. Bază de date pentru evidenţa testărilor la un centru de certificare a aptitudinilor de operare pe calculator ……… 45

Autor: Asistent univ. drd. Geambaşu Cristina

IV. Bază de date pentru gestiunea aprovizionărilor cu materiale la o firmă………………………………………………… 70

Autor: Lector univ. dr. Stanciu Andrei

V. Bază de date pentru evidenţa poliţelor de asigurare, la o societate de profil………………………………………………… 89

Autor: Asistent univ. drd. Rădulescu Cristina

VI. Bază de date pentru evidenţa operaţiunilor efectuate prin casierie……………………………………………... 111

Autor: Lector univ. drd. Aleca Ofelia

VII. Bază de date pentru gestiunea costurilor proiectelor……………………………………………… 128

Autor: Lector univ. drd. Aleca Ofelia

VIII. Bază de date pentru evidenţa personalului………………. 146

Autor: Conferenţiar univ. dr. Mihai Florin

IX. Bază de date pentru evidenţa contractelor cu clienţii la o firmă de consultanţă………………………………………… 162

Autor: Lector univ. dr. Stanciu Andrei

Page 6: Studii de Caz Access 2007

X. Bază de date pentru evidenţa activităţii unei clinici medicale ………………………………………………… 176

Autor: Lector univ. dr. Mangiuc Dragoş

XI. Bază de date pentru evidenţa comenzilor primite de către un studio foto………………………………… 192

Autor: Lector univ. dr. Mangiuc Dragoş

Page 7: Studii de Caz Access 2007

Baze de date Access 2007

7

Bază de date pentru evidenţa împrumuturilor de cărţi în cadrul unei biblioteci

O bibliotecă urmează să implementeze o bază de date pentru evidenţa informatizată a împrumuturilor de cărţi. Pentru fiecare titlu ce poate constitui obiectul împrumuturilor, alături de numele propriu-zis (titlul cărţii) sunt întregistrate următoarelor informaţii: autorii, editura şi anul publicării, genul căruia îi aparţine, precum şi numărul exemplarelor pe care biblioteca le deţine; fiecărui titlu i se atribuie un cod unic, cunoscut sub numele de cotă. Pentru evidenţa autorilor se consemnează: codul, numele, prenumele şi opţional, ţara de provenienţă. Abonaţii bibliotecii sunt înregistraţi în sistem pe baza următoarelor date: cod abonat, nume, prenume, dată naştere, seria şi numărul actului de identitate, adresă, telefon. Aceştia pot opta pentru diverse tipuri de abonamente, fiecare tip fiind caracterizat de un cod unic, denumire, durata de valabilitate a abonamentelor (exprimată în număr de luni), limită cărţi (numărul maxim de cărţi ce pot fi împrumutate la un moment dat), limită timp (durata maximă, ca număr de zile, a împrumuturilor) şi tarif. Pentru fiecare abonament se atribuie un cod unic şi se indică tipul de abonament, perioada de valabilitate (data de debut şi cea de expirare) şi titularul (abonatul). Împrumuturile pot fi efectuate doar în baza unor abonamente valabile şi sunt înregistrate prin intermediul bonurilor de împrumut. Alături de abonamentul în baza căruia a fost întocmit, un astfel de bon trebuie să specifice data împrumutului, cărţile împrumutate şi data limită la care acestea trebuie returnate (în funcţie de tipul abonamentului); la înregistrarea în sistem, fiecare bon primeşte un număr unic. Cărţile împrumutate prin intermediul aceluiaşi bon pot fi restituite la date diferite, pentru fiecare carte indicându-se data returnării. Fiecare abonament valabil este caracterizat de o limită efectivă de împrumut, iniţial egală cu limita specifică tipului de abonament (limită cărţi), dar care se diminuează odată cu fiecare carte împrumutată (-1), urmând să se refacă (+1) la momentul restituirii ei.

Reguli de gestiune:

• Un titlu poate fi publicat de un autor sau, în colaborare, de un colectiv de autori.

• Un abonament are un singur titular.

• Un bon de împrumut are la bază un abonament unic.

• Un bon de împrumut poate viza mai multe titluri, cu condiţia ca numărul acestora să se încadreze în limita specifică tipului de abonament.

I. Realizaţi modelul relaţional al bazei de date şi implementaţi în MS Access Pe baza informaţiilor care descriu activitatea bibliotecii, se poate constitui dicţionarul atributelor şi se pot deduce relaţiile dintre acestea. Ambele aspecte sunt redate sintetic prin intermediul matricei dependenţelor funcţionale, prezentată în continuare:

I

Page 8: Studii de Caz Access 2007

Studii de caz

8

Observaţii:

• Anterior realizării matricei au fost eliminate atributele derivate: DataExpirareAbonament (se determină în funcţie de DataDebut şi DurataValabilitate), DataLimitaRestituireImprumut (depinde de DataBon şi LimitaDurata), LimitaEfectivaImprumut (se calculează deducând numărul cărţilor împrumutate şi nerestituite din LimitaNrCarti).

• Pentru simplificare, pe primul rând al matricei au fost dispuse doar atributele sau perechile de atribute cu rol de determinant, în raport cu alte atribute.

• Dependenţele funcţionale au fost marcate cu simbolul 1, iar cele tranzitive cu 1t.

Page 9: Studii de Caz Access 2007

Baze de date Access 2007

9

Din analiza matricei dependenţelor funcţionale, se deduce următorul model relaţional al bazei de date:

TipAbonament (CodTipAbonament, DenumireTipAbonament,

DurataValabilitate, LimitaNrCarti, LimitaDurata, TarifAbonament)

Abonat (CodAbonat, NumeAbonat, PrenumeAbonat, DataNastere, SerieCI, NrCI, Adresa, Telefon)

Autor (CodAutor, NumeAutor, PrenumeAutor, Tara)

Carte (Cota, Titlu, Editura, AnPublicare, Gen, NrExemplare)

Abonament (CodAbonament, DataDebut, CodTipAbonament, CodAbonat)

BonImprumut (NrBon, DataBon, CodAbonament)

CarteImprumutata (NrBon, Cota, DataRestituire)

AutorCarte (Cota, CodAutor)

Observaţii:

• Întrucât printr-un bon de împrumut pot fi împrumutate mai multe cărţi, care pot fi restituite pe rând, la date diferite (şi în plus, în mod firesc, aceeaşi carte poate face, în timp, obiectul mai multor împrumuturi), atributul DataRestituire necesită un determinant compus (NrBon+Cota), ce va constitui cheia primară a unei tabele distincte (CarteImprumutata). Totodată, la nivelul acestui tabel, atributele NrBon şi Cota sunt, în mod individual, chei externe în raport cu cheile primare din tabelele BonImprumut, respectiv Carte.

• Tabela AutorCarte este consecinţa dependenţelor multiple reciproce dintre atributele Cota şi CodAutor. În această situaţie se impune constituirea unei noi tabele, cu o cheie primară compusă din ambele atribute, care sunt totodată, în mod individual, chei externe în raport cu cheile primare Cota şi CodAutor, din tabelele asociate.

• În vederea realizării modelului relaţional au fost eliminate dependenţele tranzitive, astfel încât tabelele rezultate se află deja în forma normală 3 (FN3) şi pot face obiectul implementării. Rezultatul implementării modelului relaţional în Microsoft Access 2007 este următorul:

Page 10: Studii de Caz Access 2007

Studii de caz

10

Studiu individual:

Întrucât biblioteca este implicată în schimburi culturale cu alte instituţii de profil, se impune evidenţa cărţilor primite în custodie de la alte biblioteci, respectiv a cărţilor date în custodie. În acest scop, trebuie preluate în sistem atât datele aferente cărţilor vizate (într-o manieră identică celei descrise în prezentarea aplicaţiei), cât şi cele privitoare la bibliotecile partenere (codul, denumirea, adresa, localitatea şi telefonul). Pentru fiecare titlu ce face obiectul transferului se va consemna numărul exemplarelor transferate, data de început, respectiv de sfârşit a perioadei în care operează transferul, precum şi biblioteca parteneră. Cărţile primite în custodie vor fi evidenţiate separat de cele date în custodie. Adăugaţi modelului relaţional tabelul, sau tabelele, ce permit memorarea datelor privind schimburile descrise.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) În cazul oricărui bon de împrumut, data întocmirii trebuie înregistrată în mod obligatoriu. Aceasta nu poate fi ulterioară datei curente şi nici anterioară datei la care biblioteca a fost înfiinţată (5 februarie 1999); de asemenea, data curentă va fi utilizată ca valoare implicită pentru data împrumutului.

La nivelul câmpului NrBon, din tabela BonImprumut, vor fi specificate următoarele proprietăţi:

- Default Value: DATE()

- Required: Yes

- Validation Rule: BETWEEN #5/2/1999# AND DATE()

- Validation Text: Data împrumutului nu poate fi ulterioară datei curente, sau anterioară datei de înfiinţare a bibliotecii!

II.b) Presupunând că biblioteca oferă spre împrumut doar titluri publicate de un număr limitat de edituri, se cere ca denumirile acestora să fie afişate în cadrul unei liste derulante, introducerea editurii care a publicat un anumit titlu putând fi realizată prin selectarea unui articol din listă.

În acest scop, este necesar ca în tabela Carte, la nivelul câmpului Editura să se seteze următoarele proprietăţi:

- Display Control: Combo Box

- Row Source Type: Value List - Row Source: “Astra”; “Guliver”; “Atlas” (sunt enumerate denumirile editurilor) - Limit To List: Yes

Page 11: Studii de Caz Access 2007

Baze de date Access 2007

11

II.c) La nivelul oricărui tip de abonament, limita de durată a împrumuturilor (exprimată în număr de zile) nu poate depăşi durata de valabilitate a abonamentelor de tipul respectiv (exprimată în număr de luni); de asemenea, nu se pot încheia abonamente pe perioade mai scurte de o lună.

În tabela TipAbonament, la nivelul câmpului DurataValabilitate vor fi specificate următoarele proprietăţi :

- Validation Rule: >=1

- Validation Text: Nu se pot încheia abonamente pe perioade mai scurte de o lună!

Restricţia privind relaţia dintre limita de durată a împrumuturilor şi durata de valabilitate a abonamentelor implică două atribute ale tabelului TipAbonament, prin urmare trebuie implementată prin intermediul unei reguli de validare definită la nivel de tabel:

- Table Properties / Validation Rule:

([DurataValabilitate] * 30) >= [LimitaDurata]

- Table Properties / Validation Text: Limita de durată a împrumuturilor nu poate depăşi durata de valabilitate a abonamentului!

Observaţie: Pentru a se putea face distincţia între valori (constante) de tip text şi atribute, numele atributelor trebuie delimitate prin paranteze drepte ([DurataValabilitate], [LimitaDurata]).

Studiu individual:

Definiţi proprietăţile care permit implementarea următoarelor restricţii la nivelul bazei de date: a) Durata de valabilitate a unui abonament, indiferent de tipul său, nu poate depăşi 3 ani. b) Abonaţii bibliotecii trebuie să aibă cel puţin 18 ani. c) Pentru toate abonamentele cu durata mai mică de un an, durata maximă a împrumuturilor va fi limitată la 30 de zile, iar numărul de maxim al cărţilor ce pot fi împrumutate la un moment dat va fi limitat la 5.

Page 12: Studii de Caz Access 2007

Studii de caz

12

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afişeze în ordine alfabetică toate titlurile ce aparţin genurilor Artă şi Beletristică, publicate în ultimii 5 ani, de o anumită editură, indicată la execuţie.

III.b) Să se identifice tipurile de abonamente cu durata de valabilitate mai mare de un an, ce au fost solicitate în anul precedent de abonaţi care nu provin din Bucureşti.

Observaţie: Având în vedere natura relaţiei dintre tabelele TipAbonament şi Abonament – un tip de abonament poate fi asociat cu mai multe abonamente), dar şi faptul că se urmăreşte obţinerea unei liste cu tipurile de abonamente care se conformează restricţiilor din cerinţă, nu şi a datelor privitoare la abonamentele propriu-zise, este posibil ca la nivelul câmpurilor afişabile, anumite combinaţii CodTipAbonament + DenumireTipAbonament să apară în mod repetat. Din acest motiv, se va solicita ca din setul de rezultate returnat de interogare, să fie eliminte duplicatele (Query Properties / Unique Values: Yes).

Page 13: Studii de Caz Access 2007

Baze de date Access 2007

13

III.c) În cazul fiecărui abonament valabil la data curentă, să se determine numărul total al cărţilor împrumutate.

Observaţie: Data expirării unui abonament se calculează cumulând durata de valabilitate (exprimată în luni, conform enunţului) la data de la care abonamentul este valabil (DataDebut) şi deducând apoi o zi; spre exemplu, un abonament cu durata de 1 an şi cu data de debut 7 mai 2009 expiră la 6 mai 2010 (aceasta este ultima zi de valabilitate). În cazul de faţă, pentru a determina data expirării, s-a utilizat funcţia calendaristică DATEADD (tip_unitate_timp, nr_unităţi_timp, debut_interval), care permite aflarea datei de sfârşit a unui interval pentru care se specifică data de început şi durata, exprimată prin numărul unităţilor de timp de un anumit tip, indicat sub forma unor constante text, predefinite (“d”- zile, “m” - luni, “yyyy” - ani etc.).

III.d) Să se reducă cu 20% tariful abonamentelor cu durata de 2 ani, care nu au fost solicitate de clienţii bibliotecii.

Observaţii:

• Cererea este rezolvată prin intermediul unei introgări de acţiune, de actualizare (Update Query).

• Pentru a identifica tipurile de abonamente pentru care nu există solicitări, trebuie căutate înregistările tabelei TipAbonament, fără corespondent în tabela Abonament. În acest scop, cele două tabele au fost relaţionate prin intermediul unei joncţiuni externe (Left Join, în cazul de faţă), impunându-se condiţia ca

Page 14: Studii de Caz Access 2007

Studii de caz

14

în setul de rezultate obţinut, atributele ce provin din tabela Abonament, inclusiv câmpul-cheie primară, CodAbonament, să aibă valori nule.

IV. Realizaţi interogări SQL pentru următoarele cerinţe: IV.a) Să se identifice editurile care au publicat titluri din genurile „Beletristică” şi „Timp liber”, ce au fost împrumutate în perioada 10 octombrie 2008 – 10 octombrie 2009.

SELECT DISTINCT Editura FROM Carte INNER JOIN (CarteImprumutata INNER JOIN BonImprumut ON CarteImprumutata.NrBon = BonImprumut.NrBon) ON Carte.Cota = CarteImprumutata.Cota WHERE Gen IN ("Beletristica", "Timp liber") AND DataBon BETWEEN #10/10/2008# AND #10/10/2009#;

Observaţie: Datorită faptului că aceleaşi titluri pot figura în mai multe bonuri de împrumut, editurile care le-au publicat pot apărea în mod repetat la nivelul setului de înregistări returnat de interogare. În cazul de faţă, unicul câmp afişabil este cel care conţine denumirile editurilor, astfel încât se impune eliminarea duplicatelor prin intermediul specificatorului DISTINCT.

IV.b) Să se obţină lista abonaţilor cu vârsta de peste 70 ani (ordonaţi după vârstă, în sens descrescător), care au încheiat abonamente în luna curentă; numele şi prenumele vor fi afişate într-o coloană unică.

SELECT DISTINCT NumeAbonat & " " & PrenumeAbonat AS [Nume si Prenume], DATEDIFF("yyyy", DataNastere, DATE()) AS Varsta FROM Abonat INNER JOIN Abonament ON Abonat.CodAbonat = Abonament.CodAbonat WHERE DATEDIFF("yyyy", DataNastere, DATE()) >70 AND MONTH(DataDebut) = MONTH(DATE()) AND YEAR(DataDebut) = YEAR(DATE()) ORDER BY 2 DESC;

Observaţie: Întrucât este reprezentat de un câmp afişabil (Varsta), criteriul de sortare poate fi specificat atât prin intermediul expresiei ce stă la baza sa (DATEDIFF("yyyy",

DataNastere, DATE())), cât şi prin indicarea poziţiei pe care o ocupă în cadrul listei câmpurilor afişabile (ORDER BY 2). Funcţia DATEDIFF(tip_unitate_timp, data1, data2) returnează diferenţa dintre două date, exprimată în numărul unităţilor de timp de un anumit tip (specificat prin intermediul aceloraşi constante text predefinite, ca şi în cazul funcţiei DATEADD).

IV.c) Să se identifice cărţile împrumutate şi nerestituite, deşi perioada de împrumut a expirat, precum şi bonurile de împrumut asociate. Rezultatele vor fi sortate după numărul zilelelor de întârziere, în ordine descrescătoare şi după titlurile cărţilor, în ordine alfabetică.

Page 15: Studii de Caz Access 2007

Baze de date Access 2007

15

SELECT Carte.Cota, Titlu, BonImprumut.NrBon, (DATE() - (DataBon + LimitaDurata-1)) AS Intarziere FROM TipAbonament INNER JOIN (Abonament INNER JOIN (BonImprumut INNER JOIN (CarteImprumutata INNER JOIN Carte ON CarteImprumutata.Cota = Carte.Cota) ON BonImprumut.NrBon = CarteImprumutata.NrBon) ON Abonament.CodAbonament = BonImprumut.CodAbonament) ON TipAbonament.CodTipAbonament = Abonament.CodTipAbonament WHERE DataRestituire IS NULL AND (DataBon + LimitaDurata - 1) < DATE() ORDER BY (DATE() - (DataBon + LimitaDurata - 1)) DESC, Titlu;

Observaţie: Ţinând cont de faptul că limita de durată a unui împrumut este exprimată în număr de zile, rezultă ca trebuie determinate următoarele:

• Data limită a unui împrumut: (DataBon + LimitaDurata -1), sau, expresia echivalentă (DATEADD(“d”, LimitaDurata, DataBon)-1)

• Numărul zilelor de întârziere: (DATE() - (DataBon + LimitaDurata-1)) .

IV.d) Să se determine numărul şi valoarea totală a abonamentelor cu durata de un an, care au fost achiziţionate în fiecare lună a anului anterior; sortare după numărul abonamentelor, în ordine descrescătoare.

SELECT MONTH(DataDebut) AS Luna, COUNT(*) AS NrAbonamente, SUM(TarifAbonament) AS ValoareTotala FROM Abonament INNER JOIN TipAbonament ON Abonament.CodTipAbonament = TipAbonament.CodTipAbonament WHERE YEAR(DataDebut) = YEAR(DATE())-1 AND DurataValabilitate = 12 GROUP BY MONTH(DataDebut) ORDER BY COUNT(*) DESC;

IV.e) Pe baza numărului de cărţi împrumutate, să se realizeze un clasament al primelor 3 genuri solicitate de cititori, la nivelul unei perioade ce va fi specificată la execuţie.

PARAMETERS [Inceput interval] Date, [Sfarsit interval] Date; SELECT TOP 3 Gen, COUNT(*) AS NrCarti FROM BonImprumut INNER JOIN (CarteImprumutata INNER JOIN Carte ON CarteImprumutata.Cota = Carte.Cota) ON BonImprumut.NrBon = CarteImprumutata.NrBon WHERE DataBon BETWEEN [Inceput interval] AND [Sfarsit interval] GROUP BY Gen ORDER BY COUNT(*) DESC;

IV.f ) Să se obţină lista titlurilor (sortate alfabetic) pentru care, temporar, nu există nici un exemplar disponibil (toate exemplarele sunt împrumutate şi nereturnate).

Page 16: Studii de Caz Access 2007

Studii de caz

16

SELECT Carte.Cota, Titlu, NrExemplare FROM CarteImprumutata INNER JOIN Carte ON CarteImprumutata.Cota = Carte.Cota WHERE DataRestituire IS NULL GROUP BY Carte.Cota, Titlu, NrExemplare HAVING COUNT(*) = NrExemplare ORDER BY Titlu;

IV.g) Să se obţină o listă a tipurilor de abonamente cu cel puţin 100 solicitări, respectiv a celor fără nici o solicitare, la nivelul unui an indicat la execuţie.

PARAMETERS [Introduceti anul vizat] Integer; SELECT TipAbonament.CodTipAbonament, DenumireTipAbonament, COUNT(*) AS NrSolicitari FROM TipAbonament INNER JOIN Abonament ON TipAbonament.CodTipAbonament = Abonament.CodTipAbonament WHERE YEAR(DataDebut) = [Introduceti anul vizat] GROUP BY TipAbonament.CodTipAbonament, DenumireTipAbonament HAVING COUNT(*) >=100 UNION SELECT TipAbonament.CodTipAbonament, DenumireTipAbonament, 0 AS NrSolicitari FROM TipAbonament LEFT JOIN Abonament ON TipAbonament.CodTipAbonament = Abonament.CodTipAbonament WHERE Abonament.CodTipAbonament IS NULL AND YEAR(DataDebut) = [Introduceti anul vizat];

Observaţii:

• Pentru a identifica tipurile de abonamente pentru care nu există solicitări, la nivelul tabelului TipAbonament trebuie căutate înregistrările fără corespondent în tabelul Abonament, recurgându-se la o jocţiune externă - a se revedea explicaţiile de la punctul III.d)

• Întrucât operatorul UNION permite reunirea într-un set de înregistrări unic, a rezultatelor produse de cereri de selecţie distincte, dar cu o structură identică sub aspectul câmpurilor afişabile, pentru a uniformiza structura seturilor de înregistrări, în cazul cererii care vizează tipurile de abonamente fără solicitări, a fost introdus un câmp ce conţine o valoare constantă, 0, indicând absenţa abonamentelor.

IV.h) Să se identifice titlurile din genul „IT”, pentru care durata medie de împrumut este superioară duratei medii a împrumuturilor, calculată la nivelul genului de care aparţin; rezultatele vor fi salvate într-un nou tabel (Statistica-IT). Ulterior, în tabelul nou creat, vor fi adăugate cărţile din acelaşi gen, fără nici un împrumut.

- Creare tabel: SELECT Carte.Cota, Titlu, AVG(DataRestituire - DataBon) AS [Durata medie împrumut] INTO [Statistica-IT] FROM Carte INNER JOIN (CarteImprumutata INNER JOIN BonImprumut ON CarteImprumutata.NrBon = BonImprumut.NrBon) ON Carte.Cota = CarteImprumutata.Cota

Page 17: Studii de Caz Access 2007

Baze de date Access 2007

17

WHERE DataRestituire IS NOT NULL AND Gen LIKE "IT" GROUP BY Carte.Cota,Titlu HAVING AVG(DataRestituire - DataBon) > (SELECT AVG(DataRestituire - DataBon) FROM Carte INNER JOIN (CarteImprumutata INNER JOIN BonImprumut ON CarteImprumutata.NrBon = BonImprumut.NrBon) ON Carte.Cota = CarteImprumutata.Cota WHERE DataRestituire IS NOT NULL AND Gen LIKE "IT");

- Adăugare înregistrări: INSERT INTO [Statistica-IT] ( Cota, Titlu, [Durata medie împrumut] ) SELECT Carte.Cota, Carte.Titlu, 0 FROM Carte WHERE Cota Not In (SELECT Cota FROM CarteImprumutata);

IV.i) Să se elimine din baza de date cărţile publicate de editurile Coral şi Astoria, cu peste 10 ani în urmă, care nu au făcut obiectul nici unui împrumut.

DELETE * FROM Carte WHERE Editura IN ("Coral", "Astoria") AND AnPublicare < (YEAR(DATE()) - 10) AND Cota <> ALL (SELECT Cota FROM CarteImprumutata);

IV.j) Biblioteca decide să achiziţioneze câte 50 de exemplare din titlurile cu cel puţin 100 de solicitări în ultimile 6 luni; să se opereze această modificare la nivelul bazei de date.

UPDATE Carte SET NrExemplare = (NrExemplare + 50) WHERE Cota = ANY (SELECT Cota FROM CarteImprumutata INNER JOIN BonImprumut ON CarteImprumutata.NrBon = BonImprumut.NrBon WHERE DATEDIFF("m", DataBon, DATE()) <= 6 GROUP BY Cota HAVING COUNT(*) >= 100);

Studiu individual:

a) Să se identifice editurile care în anul curent au publicat lucrări din genul „Politică”, scrise de autori britanici sau americani. b) Să se calculeze valoarea totală a încasărilor aferente abonamentelor achiziţionate în ultimile 2 săptămâni, de clienţi din Braşov şi Sibiu. c) Să se determine vârsta medie a clienţilor care deţin abonamente valabile. d) Să se identifice editurile de la care provin cele mai multe, respectiv cele mai puţine titluri. e) Să se reducă cu 10% tariful şi să se extindă cu 3 luni durata de valabilitate, în cazul tipurilor de abonamente pentru care nu au mai existat solicitări ulterioare datei de 1 noiembrie 2008.

Page 18: Studii de Caz Access 2007

Studii de caz

18

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular pentru consultarea şi actualizarea datelor privind fondul de carte aflat în gestiunea bibliotecii.

Având în verere că o carte poate avea mai mulţi autori, pentru rezolvarea acestei cerinţe s-a creat un formular bazat pe tabela Carte, în cadrul căruia a fost plasat un subformular (numit AutoriCarti) ce permite evidenţa autorilor. Rezultatul este următorul:

Observaţii:

• Sursa de date (proprietatea Record Source) a formularului este reprezentată de tabela Carte, în timp ce subformularul are la bază următoarea cerere SQL:

SELECT AutorCarte.CodAutor, NumeAutor, PrenumeAutor, Cota FROM Autor INNER JOIN AutorCarte ON Autor.CodAutor = AutorCarte.CodAutor;

• Sincronizarea dintre cele sursele de date ale celor două formulare este realizată pe baza atributului comun Cota. Drept urmare, în cadrul formularului principal, vor fi setate următoarele proprietăţi ale obiectului subformular AutoriCarti:

- Link Master Fields: Cota - Link Child Fields: Cota

• Butoanele de comandă care permit deplasarea de la o înregistrare la alta, adăugarea sau ştergerea de înregistrări, precum şi anularea modificărilor efectuate asupra înregistrării curente, au fost realizate prin utilizarea asistentului (wizard) specializat, disponibil în MS Access 2007. Butonul de comandă pentru editarea înregistării curente (cmdEditeaza) determină, prin procedura ataşată evenimentului Click (pe care, din motive de spaţiu, nu o redăm aici), „comutarea” formularului din modul „consultare” în modul „editare”, inhibând sau activând, în mod alternativ, anumite controale, în funcţie de valoarea proprietaţii Enabled (True sau False): în modul „editare”, câmpurile formularului, ca şi butoanele pentru salvarea sau anularea modificărilor sunt active (Enabled = True), în timp ce butoanele pentru navigare, adăugare,

Page 19: Studii de Caz Access 2007

Baze de date Access 2007

19

ştergere, ca şi cmdEditeaza, sunt inactive (Enabled = False); desigur, situaţia se inversează în modul „consultare”, proprietatea Enabled a fiecărui control fiind setată la valoarea opusă celei din modul „editare”.

• Caseta combinată cboCota permite regăsirea rapidă a datelor privitoare la titlul a cărui cotă a fost selectată. Proprietăţi:

- Control Source: “ ” (Unbound) - Row Source Type: Table/Query; - Row Source: SELECT Cota, Titlu FROM Carte; - Procedura asociată evenimentului AfterUpdate: Private Sub cboCota_AfterUpdate()

'Este creata o copie a setului de inregistrari din tabelul-sursa al formularului

Dim rsCarti As Recordset

Set rsCarti = Me.RecordsetClone 'Se avanseaza la inregistrarea care contine cota selectata

rsCarti.FindFirst "[Cota]='" & Me.cboCota.Value & "'"

Me.Bookmark = rsCarti.Bookmark End Sub

• Butonul de comandă cmdSalveaza permite salvarea modificărilor aduse titlului vizat de înregistrarea curentă, ţinînd-se seama de faptul că trebuie specificat cel puţin un autor. Procedura asociată evenimentului Click:

Private Sub cmdSalveaza_Click() On Error Resume Next 'Se verifica existenta inregistrarilor la nivelul subformularului AutoriCarti

If Me.AutoriCarti.Form.Recordset.RecordCount = 0 Then

MsgBox "Nu au fost specificati autorii! " & vbCrLf & "Inregistrarea nu a fost salvata!", vbCritical

Else

DoCmd.RunCommand acCmdSaveRecord ' In caseta combinata cboCota sunt actualizate datele privitoare la titlurile disponibile

Me.cboCota.Requery

MsgBox "Inregistrarea a fost salvata!", vbInformation

End If

End Sub

Page 20: Studii de Caz Access 2007

Studii de caz

20

V.b) Realizaţi un formular pentru consultarea şi actualizarea datelor privitoare la împrumuturi.

Întrucât datele privind împrumuturile trebuie corelate cu cele aferente abonamentelor (valabilitate, numărul maxim de cărţi ce pot fi împrumutate etc.) şi cele legate de cărţile care fac obiectul împrumuturilor, s-a optat pentru realizarea unui formular cu următoarea structură:

După cum se poate observa, formularul include un subformular (CartiImprumutate), care permite evidenţa cărţilor împrumutate şi eventual, restituite. Iată câteva precizări privind soluţia prezentată:

- Sursa de date (proprietatea Record Source) a formularului este reprezentată de următoarea cerere SQL:

SELECT BonImprumut.NrBon, BonImprumut.DataBon, BonImprumut.CodAbonament, DataDebut, Abonament.CodTipAbonament, Abonament.CodAbonat, DenumireTipAbonament, DurataValabilitate, LimitaNrCarti, LimitaDurata, TarifAbonament, NumeAbonat, PrenumeAbonat, DATEADD("m", DurataValabilitate,DataDebut) -1 AS DataExpirare, IIF((LimitaDurata + DataBon)<=DataExpirare, LimitaDurata+DataBon, DataExpirare) AS LimitaRestituire FROM TipAbonament INNER JOIN (Abonat INNER JOIN (Abonament INNER JOIN BonImprumut ON Abonament.CodAbonament = BonImprumut.CodAbonament) ON Abonat.CodAbonat = Abonament.CodAbonat) ON TipAbonament.CodTipAbonament = Abonament.CodTipAbonament;

Observaţie: Data limită pentru restiturea cărţilor se determină luând în calcul numărul zilelor de împrumut la care dă dreptul tipul de abonament, sau, dacă în acest interval abonamentul expiră, data limită coincide cu ultima zi de valabilitate a abonamentului.

Page 21: Studii de Caz Access 2007

Baze de date Access 2007

21

În cazul subformularului, valoarea proprietăţii Record Source este reprezentată de interogarea următoare:

SELECT CarteImprumutata.NrBon, CarteImprumutata.Cota, Titlu, DataRestituire, DataBon + LimitaDurata AS LimitaRestituire, IIF(IIF(ISNULL(DataRestituire), DATE(), DataRestituire) < LimitaRestituire, 0, IIF(ISNULL(DataRestituire), DATE(), DataRestituire) - LimitaRestituire) AS Intarziere FROM TipAbonament INNER JOIN (Carte INNER JOIN ((Abonament INNER JOIN BonImprumut ON Abonament.CodAbonament = BonImprumut.CodAbonament) INNER JOIN CarteImprumutata ON BonImprumut.NrBon = CarteImprumutata.NrBon) ON Carte.Cota = CarteImprumutata.Cota) ON TipAbonament.CodTipAbonament = Abonament.CodTipAbonament;

Observaţie: Numărul zilelor de întârziere se calculează comparând data limită la care cărţile trebuie înapoiate bibliotecii cu data restituirii efective, în cazul cărţilor returnate, sau cu data curentă, în cazul celor nerestituite.

• Sincronizarea dintre sursele de date ale celor două formulare este realizată pe baza atributului comun NrBon. Drept urmare, în cadrul formularului principal, vor fi setate următoarele proprietăţi ale obiectului subformular CartiImprumutate:

- Link Master Fields: NrBon - Link Child Fields: NrBon

• După cum se poate observa, codul abonamentului în baza căruia se efectuează

împrumutul este selectat din lista de valori a unui control ComboBox, cu următoarele proprietăţi:

- Control Source: CodAbonament - Row Source Type: Table/Query - Row Source: SELECT Abonament.CodAbonament, NumeAbonat & " " & PrenumeAbonat AS Titular, LimitaNrCarti - NrCartiNerestituite AS LimitaEfectivaNrCarti FROM Abonat, Abonament, TipAbonament, (SELECT Abonament.CodAbonament, COUNT(CarteImprumutata.Cota) - COUNT(DataRestituire) AS NrCartiNerestituite FROM (Abonament LEFT JOIN BonImprumut ON Abonament.CodAbonament = BonImprumut.CodAbonament) LEFT JOIN CarteImprumutata ON BonImprumut.NrBon = CarteImprumutata.NrBon GROUP BY Abonament.CodAbonament) AS Tmp WHERE Abonat.CodAbonat = Abonament.CodAbonat

Page 22: Studii de Caz Access 2007

Studii de caz

22

AND Abonament.CodTipAbonament = TipAbonament.CodTipAbonament AND Tmp.CodAbonament = Abonament.CodAbonament;

Observaţie: Interogarea determină numărul cărţilor ce pot fi împrumutate de abonaţii bibliotecii ca diferenţă între numărul maxim de cărţi asociat abonamentelor pe care le deţin şi cel al cărţilor împrumutate şi nerestituite.

- Procedura asociată evenimentului AfterUpdate:

Private Sub CodAbonament_AfterUpdate() txtLimitaEfectivaCarti.Value = _ IIf(CodAbonament.ListIndex > -1, CodAbonament.Column(2, CodAbonament.ListIndex), "")

End Sub

Observaţie: Procedura permite ca în caseta text txtLimitaEfectivaCarti să fie afişat numărul maxim de cărţi ce pot fi împrumutate. După cum s-a arătat mai sus, acesată informaţie este disponibilă la nivelul casetei combinate CodAbonament în coloana LimitaEfectivaNrCarti. Drept urmare, în condiţiile în care a codul abonamentului a fost selectat (CodAbonament.ListIndex > -1), din sursa de date a controlului CodAbonament va fi preluată valoarea cu coordonatele reprezentate de rândul corespunzător selecţiei curente şi coloana cu indexul 2 (LimitaEfectivaNrCarti are numărul de ordine 3, însă indexarea începe de la 0).

• În plus, datorită faptului că formularul are ca sursă o interogare, odată cu selectarea codului aferent abonamentului, se actualizează în mod automat conţinutul tuturor câmpurilor care depind de acesta: DataDebut, CodTipAbonament (şi implicit, DenumireTipAbonament, DurataValabilitate, LimitaNrCarti, LimitaDurata şi TarifAbonament), CodAbonat (şi implicit, NumeAbonat şi PrenumeAbonat), DataExpirare, LimitaRestituire. Din acest motiv, toate controalele ce au ca sursă câmpurile amintite (proprietatea Control Source) au fost dezactivate, servind doar la afişarea datelor, nu şi la editarea acestora (proprietatea Enabled = False).

• Butoanele de comandă au fost realizate prin utilizarea asistentului (wizard) specializat disponibil în MS Access 2007 şi, exceptând butonul cmdSalveaza, au funcţii similare celor descrise în cazul cerinţei precedente.

- Butonul de comandă cmdSalveaza permite salvarea modificărilor aduse unui bon de împrumut, luând în calcul resticţiile legate de numărul de cărţi ce pot fi împrumutate şi perioada în care poate fi efectuat împrumutul. Procedura asociată evenimentului Click este următoarea:

Private Sub cmdSalveaza_Click() On Error Resume Next Dim msg_eroare As String 'Se verifica existenta inregistrarilor la nivelul subformularului CartiImprumutate

Dim nr_carti As Byte

Page 23: Studii de Caz Access 2007

Baze de date Access 2007

23

nr_carti = Me.CartiImprumutate.Form.Recordset.RecordCount

If nr_carti = 0 Then msg_eroare = "Nu exista carti imprumutate!" & vbCrLf

ElseIf nr_carti > Me.txtLimitaEfectivaCarti Then

msg_eroare = "Numarul de carti ce pot fi imprumutate a fost depasit!" & vbCrLf

End If If Me.DataBon > Me.DataExpirare Or Me.DataBon < Me.DataDebut Or _

Me.LimitaRestituire > Me.DataExpirare Then _ msg_eroare = msg_eroare & "Perioada de valabilitate abonament depasita!" & vbCrLf

If msg_eroare <> "" Then MsgBox msg_eroare & "Inregistrarea nu a fost salvata!", vbCritical

Else DoCmd.RunCommand acCmdSaveRecord 'Se actualizeaza numarul max. de carti ce pot fi imprumutate

Me.CodAbonament.Requery MsgBox "Inregistrarea a fost salvata!"

End If

End Sub

• La nivelul subformularului, cotele aferente titlurilor ce fac obiectul unui împrumut sunt selectate din lista de valori a unui control ComboBox, cu următoarele proprietăţi:

- Control Source: Cota - Row Source Type: Table/Query - Row Source: SELECT Carte.Cota, Titlu, NrExemplare AS NrTotalExemplare, NrExemplare - COUNT(CarteImprumutata.Cota) AS ExemplareDisponibile FROM Carte LEFT JOIN CarteImprumutata ON Carte.Cota = CarteImprumutata.Cota WHERE DataRestituire IS NULL GROUP BY Carte.Cota, Titlu, NrExemplare HAVING (NrExemplare - COUNT(CarteImprumutata.Cota)) > 0;

Observaţie: Interogarea identifică titlurile pentru care există exemplare disponibile pentru împrumut, determinând totodată şi numărul acestora, ca diferenţă între numărul total al exemplarelor aflate în gestiunea bibliotecii şi cel al exemplarelor împrumutate şi nerestituite.

Studiu individual:

Să se realizeze formularele (şi eventualele subformulare asociate acestora) care îndeplinesc următoarele funcţii: a) Consultarea şi actualizarea tabelei TipAbonament; b) Gestiunea clienţilor şi a abonamentelor aferente acestora.

Page 24: Studii de Caz Access 2007

Studii de caz

24

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Să se afişeze abonamentele încheiate într-o anumită perioadă, ce urmează a fi precizată la deschiderea raportului. Datele vor fi prezentate grupat, pe ani, luni, respectiv tipuri de abonamente, determinându-se totalul încasărilor şi numărul abonamentelor pentru fiecare din nivelurile indicate.

Întrucât datele necesare rezolvării acestei cerinţe se află nu doar în tabelul Abonament, ci şi în tabelele asociate (spre exemplu, numele titularului în tabela Abonat, durata de valabilitate şi tariful în tabela TipAbonament etc.), sursa raportului (proprietatea Record Source) este în mod necesar, o interogare, al cărei cod SQL este următorul:

SELECT TipAbonament.CodTipAbonament, DenumireTipAbonament, DurataValabilitate, TarifAbonament, CodAbonament, [NumeAbonat] & " " & [PrenumeAbonat] AS Titular, DataDebut, DATEADD("m", DurataValabilitate, DataDebut) -1 AS DataExpirare FROM TipAbonament INNER JOIN (Abonat INNER JOIN Abonament ON Abonat.CodAbonat = Abonament.CodAbonat) ON TipAbonament.CodTipAbonament = Abonament.CodTipAbonament WHERE DataDebut BETWEEN [Data Inceput] AND [Data Sfarsit];

Structura raportului, în modul Design, este următoarea:

Observaţii:

• Informaţiile de detaliu, privitoare la abonamentele propriu-zise, au fost plasate în secţiunea Detail, gruparea acestora în vederea prezentării şi centralizării fiind realizată după criteriile menţionate în cerinţă: anul, luna şi tipul abonamentului. Cele două expresii centralizatoare, care returnează returnează numărul de

Page 25: Studii de Caz Access 2007

Baze de date Access 2007

25

abonamente şi valoarea acestora, sunt incluse în antetul fiecărui grup şi în cel al raportului, valorile returnate având semnificaţii diferite, în funcţie de nivelul pe care ne plasăm: 1.total lunar pentru un anumit tip de abonament, 2.total lunar general (pentru toate tipurile de abonamente), 3. total anual (pentru toate tipurile de abonamente), 4. total general multianual, aferent perioadei vizate (presupunând că aceasta acoperă mai mulţi ani), la nivel de raport.

• Pentru a ataşa fiecărui abonament un număr curent, la nivelul grupului de înregistări din care face parte (în funcţie de combinaţia an + lună + tip de abonament, care îi este caracteristică) pentru contolul TextBox ce afişează acest număr, au fost setate proprietăţile Control Source (=1) şi Running Sum (Over Group). Drept urmare, la nivelul grupului, se calculează o sumă care, pentru fiecare înregistrare, este incrementată cu 1, astfel că pentru orice abonament, valoarea rezultată va corespunde numărului curent al înregistrării în cadrul grupului de care aparţine. La trecerea la un nou grup de înregistrări (alt tip de abonament, şi/sau o altă luna, şi/sau un alt an) valoarea aferentă numărului curent este resetată şi numărătoarea reîncepe de la 1.

• Prin intermediul unor casete text plasate în secţiunile de subsol, asociate raportului (Report Footer) şi paginii (Page Footer) sunt afişate data la care raportul este consultat, respectiv numărul paginii curente - [Page] - din numărul total de pagini - [Pages].

• După cum se poate observa, în secţiunea Report Header, în expresia ce reprezintă sursa de date a controlului TextBox aferent perioadei, au fost utilizaţi parametrii din interogarea ce stă la baza raportului, astfel încât perioada afişată să coincidă cu cea la care se referă datele din conţinutul raportului. La deschiderea raportului, se solicită specificarea intervalul vizat, prin furnizarea valorilor aferente celor 2 parametrii. Spre exemplu, figura următoare prezintă conţinutul raportului, în cazul în care interesează abonamentele emise în perioada 2 februarie – 2 mai 2009 (a fost redată partea superioară a primei pagini din raport).

Page 26: Studii de Caz Access 2007

Studii de caz

26

VI.b) Să se prezinte situaţia fondului de carte de care dispune biblioteca, prin furnizarea datelor de detaliu privind fiecare titlu (cotă, titlu, autori, număr exemplare) şi determinarea numărului titlurilor şi exemplarelor aferente fiecărui gen, edituri, respectiv an de editare.

Deşi datele necesare rezolvării cerinţei provin din mai multe tabele (Autor, Carte, AutorCarte), sursa raportului (proprietatea Record Source) nu poate fi reprezentată de o interogare ce implică tabelele amintite. Aceasta deoarece, datorită relaţiilor dintre tabele (între atributul CodAutor şi atributul Cota există o relaţie de dependenţă multiplă reciprocă), în cazul unei cărţi cu mai mulţi autori, aplicarea operatorului INNER JOIN determină rezultate eronate ale centralizării numărului de titluri, respectiv de exemplare. Din acest considerent, s-a optat pentru o soluţie care include un raport principal, a cărui sursă de date o reprezintă tabelul Carte şi un subraport, ce are la bază următoarea interogare:

SELECT Autor.CodAutor, NumeAutor & " " & PrenumeAutor AS Autor, Cota FROM Autor INNER JOIN AutorCarte ON Autor.CodAutor = AutorCarte.CodAutor;

Utilizarea acestei interogări ca sursă a subraportului permite nu doar obţinerea datelor necesare, cele despre autori (dacă se urmărea exclusiv acest lucru, era suficient să se indice drept sursă tabelul Autor), dar şi corelarea înregistrărilor din raport cu cele din subraport, câmpul de legătură fiind reprezentat de Cota. Drept urmare, în cadrul raportului principal, vor fi setate următoarele proprietăţi ale obiectului subraport:

- Link Master Fields: Cota - Link Child Fields: Cota

Figura următoare, redă structura celor două rapoarte, în modul Design, precum şi relaţia dintre acestea.

Observaţii:

• Informaţiile de detaliu, privitoare la titlurile disponibile şi autorii acestora au fost plasate în secţiunea Detail, gruparea acestora în vederea prezentării şi centralizării fiind realizată după criteriile menţionate în cerinţă: genul, editura şi

Page 27: Studii de Caz Access 2007

Baze de date Access 2007

27

anul publicării. Cele două expresii centralizatoare, care returnează numărul titlurilor şi al exemplarelor, sunt incluse în antetul fiecărui grup şi în subsolul raportului, valorile returnate având semnificaţii diferite, în funcţie de nivelul pe care ne plasăm: 1.total anual pentru o anumită editură şi un anumit gen, 2. total multianual pentru o anumită editură şi un anumit gen, 3. total aferent unui anumit gen (făcând abstracţie de editură şi an), 4. total general, la nivel de raport.

• În cadrul subraportului a fost inclusă o casetă-text ce permite afişarea numărului înregistrării curente la nivelul sursei de date a subraportului ([CurrentRecord]), astfel că numele autorilor fiecărei cărţi vor fi precedate de câte un număr de ordine (1,2,3...)

Figura următoare prezintă maniera în care este afişat raportul, atunci când este deschis în vederea consultării sau listării (a fost redată partea superioară a primei pagini din raport).

Studiu individual:

Să se realizeze rapoartele (cu eventualele subrapoarte asociate) care permit afişarea următoarelor informaţii: a) Împrumuturile efectuate în baza unui anumit abonament, specificat la deschiderea raportului. b) Cărţile împrumutate şi nerestituite, aferente abonamentelor exprirate; datele vor fi organizate pe abonamente şi categorii de abonamente, calculându-se durata efectivă a întârzierii (pentru fiecare carte în parte), respectiv durata medie a întârzierii (la nivel abonament, tip de abonament şi pe ansamblu).

Page 28: Studii de Caz Access 2007

Studii de caz

28

Bază de date pentru evidenţa contractelor încheiate de o agenţie de turism

O agenţie de turism doreşte să-şi informatizeze activitatea de gestionare a contractelor încheiate pentru pachetele de servicii pe care le oferă. Turiştii sunt persoane fizice care se identifică printr-un cod unic, nume prenume, CNP, serie şi număr CI, data naşterii, telefon, număr paşaport. Agenţia oferă mai multe categorii de servicii (excursii, cazare, bilete avion); fiecare categorie de servicii include tipuri de servicii (excursii – circuit sau sejur; cazare – all-inclusive sau demi-pensiune; bilete avion – dus, întors, dus–întors) pentru care se memorează un cod unic şi denumirea serviciului. Indiferent de natura serviciului, se impune specificarea ţării destinaţie – identificată prin cod şi denumire; pentru ţara destinaţie se precizează localitatea destinaţie, pentru care se reţine codul şi numele.

Pentru ca oferta să fie cât mai atractivă, agenţia acordă anumite reduceri în funcţie de vârsta turiştilor; asfel, pentru turiştii care care au vârsta mai mică sau egală cu 12 ani, se acordă o reducere de 40% din tariful standard aferent fiecărui serviciu, iar copii care nu au împlinit încă 2 ani beneficiază de gratuitate.

Fiecare prestator de servicii se identifică printr-un un cod unic, denumire, numărul de telefon, categoria în care se încadrează (companie aeriană, firmă de transport terestru, unitate cazare).

Pentru serviciile prestate, agenţia încheie un contract de care pot beneficia mai multi turişti (de exemplu, o familie). În cadrul contractului, pe lângă numărul şi data încheierii acestuia, se precizează turistul/turiştii beneficiar(i), clauzele contractuale (drepturile/obligaţiile părţilor contractante), avans-ul, data până la care se poate achita valoarea integrală a contractului, tariful standard aferent serviciului respectiv, data plecării şi data de sosire. Dacă turistul renunţă din vina sa la serviciile care face obiectul respectivului contract, el datorează agenţiei despăgubiri diferenţiate în funcţie de momentul renunţării (mai exact, numărul de zile înainte de data plecării).

Reguli de gestiune:

• un contract poate avea unul sau mai mulţi beneficiari (turişti), un turist poate încheia unul sau mai multe contracte.

• oricare dintre beneficiarii contractului poate renunţa la serviciile contractate la o anumită dată (situaţii critice: accidente, boli sau alte motive întemeiate).

• un contract conţine un singur tip de servicii.

• o categorie de servicii include mai multe servicii.

• fiecare serviciu poate fi realizat de mai mulţi prestatori de servicii.

• fiecare categorie de prestatori servicii include mai mulţi prestatori, dar un prestator nu poate să facă parte decât dintr-o singură categorie.

• fiecare ţară destinaţie are mai multe localităţi.

II

Page 29: Studii de Caz Access 2007

Baze de date Access 2007

29

• în cadrul unei localităţi se pot presta mai multe servicii, un serviciu poate fi contractat în mai multe localităţi.

I. Realizaţi modelul realizaţi al bazei de date şi implemenaţi în MS Access Pentru obţinerea modelului relaţional se parcurg următoarele etape:

I.a) Inventarierea atributelor Pe baza informaţiilor referitoare la activitatea de gestionare a contractelor încheiate de agenţia de turism, se poate întocmi dicţionarul de atribute:

CodTurist, CNPTurist, NumePrenume, SerieNrCI, DataNaşterii, TelefonTurist, NrPasaport, CodCategorieServicii, DenumireCategorie, CodServiciu, DenumireServiciu, CodPrestatorServicii, DenumirePrestatorServicii, CodCategoriePrestator, DenumireCategoriePrestator, CodŢară, DenumireŢară, CodLocalitate, NumeLocalitate, CodPartener, NrContract, DataIncheiereContract, ClauzeContractuale, Avans, DataLimitaPlataContract, DataAnulareContract, DataPlecare, DataSosire, Tarif, Vârsta, Reducere, Despăgubiri, TarifRecalculat, ValoareaTotalăContracte.

I.b) Specificarea regulilor de gestiune (sunt prezentate anterior) şi precizarea algoritmilor de calcul pentru atributele care pot fi determinate prin calcul:

Vârsta (ani) AnulCurent – AnulNasterii

Reducere:

• pentru turiştii cu vârsta <= 2 ani, reducerea este de

100% (aplicată la tariful standard);

• pentru turiştii cu vârsta > 2 ani <= 12 ani, reducerea este de 40%;

• pentru turiştii cu vârsta > 12 ani, nu se acordă reducere.

Tarif Recalculat TarifStandard – Reducere

Despăgubiri:

• 30% din tariful standard, dacă renunţarea se face cu

mai mult de 30 de zile calendaristice înainte de data plecării;

• 50% din tariful standard, dacă renunţarea se face în intervalul 16-30 de zile înainte de data plecării;

• 95% din tariful standard, dacă renunţarea se face într-un interval mai mic de 16 zile înainte de data plecării.

ValoareaTotalaContracte Suma valorică a fiecărui contract

I.c) Întocmirea diţionarului de date pe baza următoarelor reguli:

• fiecare atribut este înscris o singură dată

Page 30: Studii de Caz Access 2007

Studii de caz

30

• sunt eliminate atributele sinonime (în exemplul prezentat, CodPrestatorServicii şi CodPartener sunt sinonime, deci se va reţine doar unul dintre acestea – CodPrestatorServicii).

• nu sunt preluate atribute calculate (Vârsta, Reducere, TarifRecalculat, Despagubiri, ValoareaTotalăContracte).

Dicţionar de date (DD)

CodTurist, CNPTurist, NumePrenume, SerieNrCI, DataNaşterii, TelefonTurist, NrPasaport, CodCategorieServicii, DenumireCategorie, CodServiciu, DenumireServiciu, CodPrestatorServicii, DenumirePrestatorServicii, CodCategoriePrestator, DenumireCategoriePrestator, CodŢară, DenumireŢară, CodLocalitate, NumeLocalitate, NrContract, DataIncheiereContract, ClauzeContractuale, Avans, DataLimitaPlataContract, DataPlecare, DataSosire, Tarif, DataAnulareContract.

I.d) Stabilirea dependenţelor funcţionale dintre atribute – acestea sunt prezentate în mod sintetic prin matricea dependenţelor funcţionale (forma simplificată – dependenţele funcţionale sunt marcate cu 1, iar cele tranzitive cu 1T).

Matricea este prezentată în figura din pagina următoare.

Observaţii:

• pentru fiecare cheie primară şi atributele determinate netranzitiv de aceasta se formează o tabelă.

• deoarece un contract poate fi încheiat pentru mai mulţi turişti, iar un turist poate să încheie cu agenţia mai multe contracte se apelează la un determinant compus format din NrContract şi CodTurist care va deveni cheia primară a tabelei ContracteTurişti (obţinută datorită dependenţelor multiple reciproce dintre cele două atribute specificate);

• întrucât oricare dintre beneficiarii contractului poate să renunţe la serviciul contractat la o anumită dată, pentru atributul izolat DataAnulareContract se asociază ca determinant cheia compusă NrContract şi CodTurist.

• agenţia oferă servicii în localităţi diferite, iar un serviciu poate fi contractat în mai multe localităţi; datorită dependenţelor multiple reciproce dintre cele două atribute se impune crearea unei tabele intermediare care va avea drept cheie primară grupul CodLocalitate şi CodServiciu.

Page 31: Studii de Caz Access 2007

31

Matricea dependenţelor funcţionale

Page 32: Studii de Caz Access 2007

Studii de caz

32

Modelul relaţional obţinut cu ajutorul matricei dependenţelor funcţionale este următorul:

CategorieServicii(CodCategorieServicii, DenumireCategorie)

OfertaServicii(CodServiciu, DenumireServiciu, CodCategorieServicii)

CategoriePrestatorServicii(CodCategoriePrestator, DenumireCategoriePrestator)

PrestatoriServicii(CodPrestatorServicii, DenumirePrestatorServicii,

CodCategoriePrestator,CodServiciu)

Ţara(CodŢară, DenumireŢară)

Localitate(CodLocalitate, NumeLocalitate, CodŢară)

OferteLocalitati(CodServiciu, CodLocalitate)

Contracte(NrContract, DataIncheiereContract, ClauzeContractuale, Avans,

DataLimitaPlataContract, DataPlecare, DataSosire, Tarif)

Turisti(CodTurist, CNPTurist, NumePrenume, SerieNrCI, DataNaşterii,

TelefonTurist)

ContracteTuristi(NrContract, CodTurist, DataAnulareContract)

Implementarea modeluluiu in Access este prezentată în figura următoare:

Studiu individual:

Pentru fiecare contract încheiat, agenţia emite o factură pe care se precizează numărul acesteia, data emiterii, valoarea, TVA şi alte detalii; achitarea facturii se realizează printr-un document de plată pe care se regăsesc numărul documentului de plată, data, tipul documentului de plată, suma plătită.

Page 33: Studii de Caz Access 2007

Cu un document de plată se poate achita o singură factură, dar o factură poate fi plătită în mod eşalonat. Pot exista mai multe documente de plată cu acelaşi număr, dar de tipuri diferite. Adăugaţi modelului relaţional tabelul sau tabelele necesare pentru a permite memorarea datelor aferente achitării facturilor emise pentru serviciile contractate.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) În cadrul tabelei CategorieServicii, câmpul DenumireCategorie poate lua valorile „excursii”, „bilete avion”, „cazare”. Rezolvarea acestei cerinţe se poate realiza:

• fie prin specificarea unei reguli de validare la rubrica Validation Rule din zona de proprietăţi asociată câmpului respectiv, fişa de lucru General:

• fie prin definirea unei liste

derulante cu valorile respective şi selectarea opţiunilor corespunzătoare în fişa Lookup din caseta Field Properties aferentă câmpului DenumireCategorie.

II.b) La nivelul tabelei Contracte, data la care se încheie contractul se consideră ca fiind implicit data curentă; de asemenea, data limită până la care se poate realiza achitarea integrală a contractului trebuie să fie ulterioară (sau cel mult aceeaşi) momentului în care s-a încheiat contractul.

În acelaşi timp, data limită pentru plata contractului trebuie să fie anterioară datei plecării, fapt care impune definirea unei reguli de validare în caseta de proprietăţi asociată tabelei Contracte:

Page 34: Studii de Caz Access 2007

Studii de caz

34

:

II.c) În tabela Turişti se impun următoarele restricţii:

• Câmpul CNPTurist va fi de tip text şi va admite obligatoriu 13 caractere numerice (pentru definirea unui şablon de afişare, la rubrica Input Mask se foloseşte caracterul 0, care impune introducerea unei valori numerice).

• Dacă turistul nu are încă vârsta de 14 ani, câmpul SerieNrCI va rămâne necompletat; în acest context, se verifică relaţia dintre două atribute ale tabelei Turişti prin definirea unei reguli de validare la nivel de tabelă:

Studiu individual:

a) Tipul documentelor de plată pentru achitarea facturilor aferente contractelor încheiate poate lua valorile: „ordin de plată”, „chitanţă”, „foaie de vărsământ”. Data facturii va fi implicit data curentă. b) Data plecării trebuie să fie anterioară datei de sosire; avansul achitat nu poate depăşi valoarea tarifului standard. c) Suma plătită prin documentul de plată trebuie să fie permanent pozitivă.

Page 35: Studii de Caz Access 2007

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afişeze lista prestatorilor de servicii pe care agenţia îi are parteneri în Spania; fiecare prestator va fi afişat o singură dată, înregistrările fiind afişate în ordine alfabetică în funcţie de numele prestatorilor.

Observaţie: fiecare prestator poate să apară în mod repetat în listă: agenţia poate avea unul sau mai mulţi parteneri pentru acelaşi tip de serviciu, dar poate să încheie mai multe contracte cu acelaşi prestator – în acest caz, prestatorul respectiv de servicii ar fi afişat de mai multe ori în rezultatul interogării. Pentru eliminarea duplicatelor se impune setarea opţiunii Unique Values: Yes în caseta Query Properties.

III.b) Să se calculeze tariful mediu pe fiecare tip de serviciu pentru care data de plecare a fost o zi de week-end.

Page 36: Studii de Caz Access 2007

Studii de caz

36

Observaţie: pentru identificarea zilelor de week-end s-a folosit funcţia WEEKDAY(data, paramentru) care returnează numărul corespunzător fiecărei zile a săptămânii. Argumentul paramentru este o constantă a cărei valoare diferă în raport cu formatul de afişare al datei calendaristice; valorile folosite cel mai frecvent sunt:

• 1- formatul american, caz în care funcţia WEEKDAY returnează 1 pentru dumincă şi 7 pentru sâmbătă;

• 2- formatul european (utilizat şi în exemplul curent), variantă în care funcţia WEEKDAY returnează 1 pentru luni şi 7 pentru duminică.

III.c) Să se calculeze valoarea totală a contractelor pe fiecare tip de serviciu şi pe fiecare trimestru al anului 2008; înregistrările vor fi sortate alfabetic în funcţie de numele serviciului prestat.

III.d) Să se mărească cu 10 % tariful serviciilor contractate în anul curent; majorarea operează numai pentru serviciile al căror cod va fi specificat de către utilizator.

Page 37: Studii de Caz Access 2007

IV. Realizaţi interogări SQL pentru următoarele cerinţe:

IV.a) Să se afişeze categoriile de servicii contractate de agenţie în anul 2008; fiecare categorie de servicii va fi afişată o singură dată, înregistrările fiind ordonate alfabetic în funcţie de categoria de servicii.

SELECT DISTINCT CategorieServicii.CodCategorieSevicii, CategorieServicii.DenumireCategorie FROM (CategorieServicii INNER JOIN OfertaSevicii ON CategorieServicii.CodCategorieSevicii = OfertaSevicii.CodCategorieServicii) INNER JOIN Contracte ON OfertaSevicii.CodServiciu = Contracte.CodServiciu WHERE YEAR([DataIncheiereContract]))=2008 ORDER BY CategorieServicii.DenumireCategorie;

Observaţie: existenţa specificatorului DISTINCT în cadrul frazei SELECT se justifică prin faptul că pe aceeaşi categorie de servicii (de exemplu - excursii) se pot afişa mai multe înregistrări care se repetă în combinaţia CodCategorie – DenumireCategorie; scopul interogării este de a afişa doar tipurile de categorii de servicii (excursii, bilete avion, cazare).

IV.b) Să se calculeze şi afişeze despăgubirile percepute de agenţie în cazul în care turistul renunţă din vina sa la serviciile contractate. Agenţia aplică penalizări diferenţiate în funcţie de momentul la care care se reziliază contractul (raportat la data plecării); astfel:

*) 30% din tariful serviciului dacă renunţarea se face cu mai mult de 30 de zile înainte de data plecării;

*) 50% din tariful serviciului dacă renunţarea se face în intervalul 16-30 de zile înainte de data plecării;

*) 95% din tariful serviciului dacă renunţarea se face într-un intervalul mai mic de 16 zile înainte de data plecării.

SELECT ContracteTuristi.CodTurist, Contracte.NrContract, ContracteTuristi.DataAnulareContract, Contracte.DataPlecare, IIF([DataAnulareContract] IS NULL,0, DATEDIFF("d",[DataAnulareContract],[DataPlecare])) AS NrZile, Contracte.Tarif, IIF(NrZile=0,0,IIF(NrZile<=16,Tarif*95/100,IIF(NrZile<=30,Tarif*50/100,Tarif*30/100))) AS Despagubiri FROM Contracte INNER JOIN ContracteTuristi ON Contracte.NrContract = ContracteTuristi.NrContract;

Observaţie: funcţia DATEDIFF (tip_interval, DataDebut, DataSfârşit) returnează diferenţa dintre două date calendaristice, exprimată în intervale de timp prin intermediul unor formate predefinite ( “d”- zile, “m” - luni, “y” - ani).

IV.c) Să se determine numărul de parteneri (prestatori servicii) pe care îi are agenţia în fiecare ţară; rezultatele vor fi ordonate alfabetic în funcţie de ţara destinaţie.

SELECT Tara.CodTara, Tara.DenumireTara, COUNT(PrestatorServicii.CodPrestatorservicii) AS NrParteneri

Page 38: Studii de Caz Access 2007

Studii de caz

38

FROM (OfertaServicii INNER JOIN ((Tara INNER JOIN Localitate ON Tara.CodTara = Localitate.CodTara) INNER JOIN OferteLocalitati ON Localitate.CodLocalitate = OferteLocalitati.CodLocalitate) ON OfertaServicii.CodServiciu = OferteLocalitati.CodServiciu) INNER JOIN PrestatorServicii ON OfertaServicii.CodServiciu = PrestatorServicii.CodServiciu GROUP BY Tara.CodTara, Tara.DenumireTara ORDER BY Tara.DenumireTara;

IV.d) Să se calculeze şi afişeze numărul de turişti de de gen masculin şi feminin care au anulat contractele în ultimul an.

SELECT IIF(VAL(LEFT([CNPTurist],1))=1,"M","F") AS Gen, COUNT(ContracteTuristi.CodTurist) AS NrTotalTuristi FROM Turisti INNER JOIN ContracteTuristi ON Turisti.CodTurist=ContracteTuristi.CodTurist WHERE YEAR([DataAnulareContract])>=YEAR(Date())-1 GROUP BY VAL(LEFT([CNPTurist],1));

Observaţie: pentru a determina genul turiştilor (masculin sau feminin) se aplică funcţia LEFT(argument, n) unde „n” reprezintă numărul de caractere care urmează a fi extrase începând din partea stângă a argumentului specificat (pe exemplul anterior, funcţia LEFT se aplică pe câmpul CNPTurist şi care are drept efect extragerea primei cifre aferentă acestuia). În mod implicit, funcţiile LEFT, RIGHT, MID returnează rezultatele sub formă de text; pentru convertirea acestora în valori numerice se recomandă utilizarea funcţiei VALUE

IV.e) Să se afişeze primele 3 servicii pentru care tariful standard este mai mare decât media valorică a tarifelor aferente tuturor serviciilor oferite de agenţie.

SELECT TOP 3 OfertaSevicii.CodServiciu, OfertaSevicii.DenumireServiciu, Contracte.Tarif FROM OfertaSevicii INNER JOIN Contracte ON OfertaSevicii.CodServiciu=Contracte.CodServiciu WHERE Contracte.Tarif >(Select AVG(Tarif) FROM Contracte) ORDER BY Tarif DESC;

Observaţie: afişarea primelor 3 servicii cu tarifele mai mari decât media presupune utilizarea atributului TOP în cadrul frazei SELECT pentru specificaea numărului de elemente şi sortarea descrescătoare în funcţie de Tarif prin ORDER BY.

IV.f ) Să se afişeze lunile din anul 2008 în care agenţia a încheiat mai mult de 3 contracte; rezultatele vor fi ordonate în funcţie de luna în care s-a încheiat contractul.

SELECT MONTH([DataIncheiereContract]) AS Luna, COUNT(NrContract) AS NrTotalContracte FROM Contracte WHERE YEAR([DataIncheiereContract])=2008

Page 39: Studii de Caz Access 2007

GROUP BY MONTH([DataIncheiereContract]) HAVING COUNT(Contracte.NrContract)>3 ORDER BY MONTH([DataIncheiereContract]);

IV.g) Să se determine numărul de prestatori care au efectuat servicii pe fiecare categorie de servicii pentru contractele încheiate în trimestrele 1 şi 2 ale anului precedent.

TRANSFORM COUNT(PrestatorServicii.CodPrestatorServicii) AS NrPrestatori SELECT OfertaSevicii.DenumireServiciu FROM ((CategorieServicii INNER JOIN OfertaSevicii ON CategorieServicii.CodCategorieSevicii = OfertaSevicii.CodCategorieServicii) INNER JOIN Contracte ON OfertaSevicii.CodServiciu = Contracte.CodServiciu) INNER JOIN PrestatorServicii ON OfertaSevicii.CodServiciu = PrestatorServicii.CodServiciu WHERE DATEPART("q",[DataIncheiereContract]) IN (1,2) AND YEAR([DataIncheiereContract]) =YEAR(Date())-1 GROUP BY OfertaSevicii.DenumireServiciu PIVOT CategorieServicii.DenumireCategorie;

Observaţie: funcţia DATEPART(interval, Data_referinţă) permite extragerea unor intervale de timp dintr-o dată calendaristică prin intermediul unor constante de tip text cu valoare predefinită (“d” – zile, “m” – luni, “q” – trimestre, “y” – ani”).

IV.h) Să se afişeze tipurile de servicii care au fost contractate de cele mai multe ori. SELECT OfertaServicii.CodServiciu, OfertaServicii.DenumireServiciu FROM OfertaServicii INNER JOIN Contracte ON OfertaServicii.CodServiciu = Contracte.CodServiciu GROUP BY OfertaServicii.CodServiciu, OfertaServicii.DenumireServiciu HAVING COUNT(*) = (SELECT TOP 1 COUNT(*) FROM Contracte GROUP BY CodServiciu ORDER BY 1 DESC);

Observaţie: Prin intermediul subinterogării se determină numărul maxim de contracte încheiate pe diferite tipuri de servicii (câmpul în funcţie de care se realizează ordonarea înregistrărilor se precizează prin poziţia pe care o ocupă în cadrul frazei SELECT (1) sau prin expresia COUNT(*)), iar la nivelul interogării principale se identifică serviciile care îndeplinesc condiţia specificată.

IV.i) Să se micşoreze cu 10% tariful standard aferent contractelor anulate anul trecut. UPDATE Contracte SET Tarif = Tarif*90/100 WHERE NrContract IN (SELECT NrContract FROM Contracte INNER JOIN ContracteTuristi ON Contracte.NrContract=ContracteTuristi.NrContract WHERE YEAR([ContracteTuristi.DataAnulareContract]) = YEAR(Date())-1);

Page 40: Studii de Caz Access 2007

Studii de caz

40

IV.j) Să se şteargă din baza de date serviciile care anul trecut au fost contractate de un număr de ori mai mic decât o valoare care va fi precizată de utilizator.

DELETE * FROM OfertaServicii WHERE CodServiciu IN (SELECT CodServiciu FROM OfertaServicii INNER JOIN Contrate ON OfertaServicii.CodServiciu= Contrate.CodServiciu WHERE YEAR([Contract.DataIncheiereContract]) = YEAR(Date())-1 GROUP BY OfertaServicii.CodServiciu HAVING COUNT(Contract.NrContract)<[Introduceti numărul minim]);

Studiu individual:

a) Să se afişeze numele turiştilor care au contractat servicii de tip „circuit” în ultimii 2 ani; datele vor fi ordonate alfabetic în funcţie de numele turiştilor. b) Să se calculeze vârsta fiecărui turist şi reducerea acordată de agenţie pentru serviciile oferite, ştiind că aceasta se determină în mod diferenţiat, pe categorii de vârstă (vezi restricţiile specificate în textul problemei). c) Să se afişeze tariful mediu pe fiecare categorie de servicii contractate în Italia sau Grecia pe fiecare lună a anului precedent. d) Să se şteargă din baza de date numele unui prestator de servicii pe care agenţia l-a avut ca partener în semestrul al II-lea al anului 2008 şi al cărui cod va fi specificat de utilizator. e) Să se mărească cu 15% tariful aferent serviciului care a fost contractat de cele mai multe ori.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Să se realizeze un formular obţinut pe baza tabelei Turisti:

Page 41: Studii de Caz Access 2007

Observaţie:

Formularul Turisti a fost generat cu ajutorul comenzii Form Wizard, din meniul Create-Forms-More forms, şi completat apoi în modul design cu butoane de închidere

a formularului , butoane de parcurgere secvenţială a

înregistrărilor , butoane de salvare şi adăugare înregistrări

şi combo box-ul de căutare a turiştilor .

V.b) Realizaţi un formular cu subformular pentru gestionarea contractelor încheiate de agenţie:

Observaţii:

a). Formularul Contracte este un formular complex alcătuit dintr-un formular principal şi un subformular, sincronizate prin intermediul câmpului NrContract (verificarea se va realiza în proprietăţile subformularului Link Child Fields şi Link Master Fields – NrContract). Formularul principal a fost generat pe tabela Contracte, iar subformularul pe baza unei interogări prin intermediul controlului subform în modul design al formularului principal.

Page 42: Studii de Caz Access 2007

Studii de caz

42

Interogarea sursă a subformularului s-a realizat pe baza tabelelor Contracte, ContracteTuristi şi Turisti cu scopul de a asocia pentru fiecare turist, tariful serviciului în raport cu vârsta acestuia. În acest sens, la nivelul interogării s-a calculat vârsta fiecărui turist pe baza câmpului Data Nasterii şi apoi s-a asociat un tarif recalculat pe baza algoritmului de mai jos (specificat în enunţul problemei):

Varsta: Year([DataIncheiereContract])-Year([DataNasterii]) Tarif serviciu recalculat: [Tarif]-IIf([Varsta]<=2; [Tarif]*100/100; IIf([Varsta]<=12;

[Tarif]*40/100;0)) b). Formularul Contracte a fost completat cu o linie de Total pentru calculul valorii totale a serviciilor incluse pentru fiecare contract. În acest scop, în subformularul “Subformular” s-a creat o casetă text, căreia i s-a atribuit numele “TotalTarif”, iar pentru proprietatea Control Source s-a specificat formula =Sum([TarifRecalculat]).

Ulterior, se revine în formularul principal Contract, unde s-a creat o altă casetă text şi în caseta de proprietăţi, la rubrica Control Source se introduce formula:

=[subformular subform].[Form]![TotalTarif].

c). Pentru a preciza semnatarul contractului, pe formularul principal s-a prevăzut un combo-box care are ca sursă interogarea următoare:

Această interogare permite alegerea ca semnatar doar a unui turist, dintre toţi beneficiarii înscrişi pe acel contract. Pentru ca această listă să fie reactualizată cu turiştii afişaţi pe contractul respectiv s-a prevăzut:

Page 43: Studii de Caz Access 2007

Private Sub Form_Current() Me.semnatar.Requery End Sub

Studiu individual:

a) Să se realizeze un formular pe baza tabelei DocumentPlată. b) Să se realizeze un formular cu subformular pentru obţinerea unei Facturi.

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: Să se realizeze un obiect de tip raport pentru a obţine una dintre situaţiile de ieşire frecvent solicitate la nivelul agenţiei: Situaţia contractelor încheiate pe fiecare categorie de servicii în perioada...

Sursa raportului este interogarea următoare proiectată pentru a cumula toate caracteristicile situaţiei de obţinut.

Selecţia perioadei se face prin intermediul formularului “Listare”:

Page 44: Studii de Caz Access 2007

Studii de caz

44

Raportul a fost proiectat pentru a furniza informaţii detaliate pentru fiecare categorie de servicii oferite de agenţie, cu specificarea contractelor încheiate, a datei de încheiere pentru fiecare contract şi a serviciului prevăzut. În acest sens, se impune gruparea informaţiilor pe fiecare categorie de servicii, calculându-se numărul total de contracte încheiate.

Pentru a se realiza filtrarea informaţiilor la nivelul perioadei specificate în formularul Listare, în cadrul raportului s-au setat proprietăţile:

Filter: DataIncheiereContract between forms!Listare!DataInceput and forms!Listare!DataSfarsit Filter on: yes.

Studiu individual:

a) Să se realizeze un obiect de tip raport pentru a obţine Situaţia facturilor încasate pe luna...

b) Să se realizeze un obiect de tip raport pentru a obţine Situaţia contractelor anulate în perioada...

Page 45: Studii de Caz Access 2007

Bază de date pentru evidenţa testărilor la un centru de certificare a aptitudinilor de operare pe calculator

Un centru de certificare a aptitudinilor de operare pe calculator, doreşte să îşi îmbunătăţească activitatea de gestiune a testării candidaţilor. În acest sens, se doreşte implementarea unui sistem informatic prin care să se ţină evidenţa testărilor programate pentru diferite module, a examinatorilor responsabili pentru fiecare testare, a sălilor în care se desfăşoară testările, a candidaţilor înscrişi, precum şi a rezultatelor obţinute de către aceştia. Modulele vor avea în cadrul sistemului un identificator unic, o denumire şi vor fi încadrate într-un anumit nivel de certificare. Programarea testărilor presupune alocarea unui identificator unic al testării, stabilirea modulului pentru care se face testarea, a datei testării, a orei de începere a testării, a duratei testării, a orei de terminare a testării, a sălii în care se va desfăşura, a tarifului perceput, precum şi a examinatorului responsabil pentru testarea respectivă. Centrul dispune de mai multe săli, fiecare având un număr unic şi un anumit număr de locuri disponibile. Examinatorii au un identificator unic alocat de către centru, ce va fi memorat în sistem alături de numele şi prenumele acestora. Pentru fiecare candidat vor fi stocate în sistem date privind: codul numeric personal (CNP), numele şi prenumele, seria şi numărul cărţii de identitate, adresa şi localitatea. Înscrierea la o testare presupune stocarea în baza de date a informaţiilor referitoare la testarea pentru care se face înscrierea, data la care se face înscrierea şi candidatul înscris. De asemenea, sistemul trebuie să aloce un identificator unic pentru fiecare înscriere. După susţinerea fiecărei testări şi corectarea testelor, se vor stoca în cadrul sistemului rezultatele aferente testării respective, precizându-se punctajul obţinut de către fiecare candidat.

Reguli de gestiune:

• O testare se referă la un singur modul, are repartizat un singur examinator responsabil cu aceasta şi este programată într-o sală disponibilă la data testării şi în intervalul de timp în care se desfăşoară testarea;

• Un examinator poate fi responsabil la mai multe testări;

• O înscriere a unui candidat se referă la o singură testare programată la o dată ulterioară datei de înscriere;

• Un candidat se poate înscrie la mai multe testări;

• Pentru o testare nu poate fi înscris un număr de candidaţi mai mare decât numărul de locuri disponibile în sala în care se desfăşoară testarea.

I. Realizaţi modelul bazei de date şi implementaţi în MS Access Proiectarea unei baze de date poate fi realizată prin mai multe metode, una dintre acestea fiind obţinerea modelului relaţional prin normalizare. Pentru ca într-o bază de date să nu existe redundanţă şi anomalii (anomalii la adăugare, anomalii la modificare

III

Page 46: Studii de Caz Access 2007

Studii de caz

46

şi anomalii la ştergere) aceasta trebuie să respecte o serie de reguli, denumite forme normale (FN1, FN2, FN3, FNBC, FN4 şi FN5).

Pentru obţinerea modelului relaţional se poate utiliza matricea dependenţelor. Întocmirea acesteia presupune parcurgerea următoarelor etape:

Etapa 1: Stabilirea dicţionarului de atribute Din enunţul problemei rezultă următorul dicţionar preliminar al atributelor: identificator modul, denumire modul, nivel modul, identificator testare, modul testat, dată testare, oră începere testare, durată testare, oră terminare testare, sală testare, tarif testare, examinator responsabil, număr sală, număr locuri disponibile sală, identificator examinator, nume şi prenume examinator, CNP candidat, nume şi prenume candidat, serie carte identitate candidat, număr carte identitate candidat, adresă candidat, localitate candidat, identificator înscriere, testarea pentru care se face înscrierea, dată înscriere, candidat înscris, punctaj obţinut.

Pentru obţinerea dicţionarului atributelor în forma finală, din listă se vor elimina:

• Atributele sinonime: modul testat, sală testare, examinator responsabil, testarea pentru care se face înscrierea, candidat înscris.

• Atributele calculate: oră terminare testare.

Astfel, se obţine următorul dicţionar final al atributelor: identificator modul, denumire modul, nivel modul, identificator testare, dată testare, oră începere testare, durată testare, tarif testare, număr sală, număr locuri disponibile sală, identificator examinator, nume şi prenume examinator, CNP candidat, nume şi prenume candidat, serie carte identitate candidat, număr carte identitate candidat, adresă candidat, localitate candidat, identificator înscriere, dată înscriere, punctaj obţinut.

Etapa 2: Stabilirea cheilor candidate Cheile candidate sunt acele atribute din dicţionarul atributelor care au valori unice şi nenule. Pentru problema dată, cheile candidate sunt: identificator modul, identificator testare, număr sală, identificator examinator, CNP candidat, identificator înscriere.

Etapa 3: Stabilirea cheilor primare Dintre cheile candidate se vor alege cheile primare. În cazul acestui exemplu, toate cheile candidate vor deveni chei primare.

Etapa 4: Stabilirea dependenţelor La completarea matricei se vor avea în vedere următoarele tipuri de dependenţe între cheile primare şi celelalte atribute:

• dependenţe funcţionale (simple) (1)

• dependenţe funcţionale (simple) tranzitive (1T)

• dependenţe multiple (M)

Notă: Pentru simplificarea modelului nu se vor lua în considerare dependenţele parţiale şi dependenţe multiple tranzitive.

Page 47: Studii de Caz Access 2007

Etapa 5: Identificarea atributelor izolate şi găsirea determinanţilor acestora Se identifică atributul izolat punctaj obţinut. Pentru determinarea acestuia se va forma cheia primara compusa din atributele CNP candidat şi identificator testare, deoarece se referă la punctajul obţinut de un anumit candidat la o anumită testare.

În urma parcurgerii celor 5 etape se obţine următoarea matrice a dependenţelor:

Pe baza matricei dependenţelor se vor forma relaţiile (tabelele), având în vedere următoarele reguli:

• Fiecare cheie primara împreună cu atributele determinate simplu de către aceasta vor forma o relaţie. În cazul în care printre aceste atribute se regăseşte o altă cheie primară, aceasta va fi considerată cheie externă pentru relaţia creată.

• Dependenţele multiple reciproce stabilite între două atribute ce reprezintă chei primare vor determina formarea unei noi relaţii, care va fi identificată printr-o cheie primară compusă din cele două atribute, ce vor fi în acelaşi timp şi chei externe.

Modelul relaţional al bazei de date este următorul:

Candidati (CNP, NumePrenume, SerieCI, NumarCI, Adresa, Localitate) Inscrieri (IDInscriere, DataInscriere, CNP, IDTestare)

Rezultate (CNP, IDTestare, PunctajObtinut)

Testari (IDTestare, DataTestare, OraIncepereTestare, DurataTestare, TarifTestare, IDModul, IDExaminator, NumarSala)

Module (IDModul, DenumireModul, NivelModul)

Examinatori (IDExaminator, NumePrenumeExaminator)

Sali (NumarSala, NumarLocuri)

Page 48: Studii de Caz Access 2007

Studii de caz

48

Relaţiile stabilite ]ntre tabelele din baza de date Access sunt prezentate în figura următoare:

Studiu individual:

Pentru ca un candidat sa poată fi înscris la o testare, acesta trebuie să achite în prealabil tariful corespunzător testării respective. Achitarea tarifului se face pe baza unei chitanţe ce are un număr unic, o dată şi o sumă. Printr-o chitanţă se achită tariful corespunzător unei singure înscrieri, pentru un singur candidat.

Completaţi modelul relaţional prin adăugarea tabelului necesar achitării taxei de înscriere şi stabiliţi legăturile dintre acesta şi celelalte tabele ale modelului.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) Durata testării se va selecta dintr-o listă cu elementele: 2 ore şi 3 ore.

Rezolvare:

Pentru câmpul DurataTestare se va alege tipul de date Number. Pentru stabilirea formatului de afişare în ore şi crearea listei se vor modifica următoarele proprietăţi ale câmpului:

Categoria General:

• Format: # ”ore”

Categoria Lookup:

• Display control: Combo Box

• Row source type: Value List

• Row source: 2;3

• Limit to list: Yes

Page 49: Studii de Caz Access 2007

II.b) Definiţi un şablon de introducere a seriei cărţii de identitate a candidatului astfel încât să fie acceptată doar introducerea a două litere obligatorii, ce vor fi formatate în vederea afişării sub formă de majuscule. Completarea acestui câmp este obligatorie la introducerea datelor în tabelul Candidati.

Rezolvare:

Câmpului SerieCI îi va corespunde tipul de date Text şi se vor stabili următoarele proprietăţile:

Categoria General:

• Format: >

• Input Mask: LL • Required: Yes

Semnul > utilizat la proprietatea Format converteşte caracterele introduse în majuscule, iar caracterul L înlocuieşte o literă obligatorie.

II.c) Pentru data de înscriere a candidaţilor se va utiliza data curentă drept valoare implicită.

Rezolvare:

Datei de înscriere îi corespunde tipul de date Date/Time. Pentru atribuirea datei curente ca valoare implicită se modifică următoarea proprietate a câmpului:

Categoria General:

• Default value: Date()

II.d) Cheia externă IDModul din cadrul tabelului Testări trebuie să aibă ca sursă înregistrările corespunzătoare din tabelul Module (în care acest câmp este cheie primară).

Rezolvare:

Pentru câmpul IDModul, din tabelul Testări, se alege tipul de date Number şi se stabilesc următoarele proprietăţi:

Categoria Lookup:

• Display control: Combo Box • Row source type: Table/Query • Row source: SELECT IDModul, DenumireModul, NivelModul FROM

Module ORDER BY IDModul; • Column count: 3 • Column widths: 0cm;2,54cm;2,54cm • Limit to list: Yes

Dimensiunea primei coloane este de 0 cm, deoarece se doreşte afişarea în listă doar a celorlalte două coloane (DenumireModul şi NivelModul).

Page 50: Studii de Caz Access 2007

Studii de caz

50

Studiu individual:

a) Să se definească un şablon de introducere a CNP-ului candidaţilor, care să permită doar introducerea a 13 cifre obligatorii.

b) Punctajul obţinut de candidaţi este cuprins între 0 şi 100 puncte.

c) Nivelul modului se selectează dintr-o listă cu elementele: începători, avansaţi.

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afişeze, în ordinea punctajelor obţinute, o listă a candidaţilor promovaţi şi nepromovaţi la o anumită testare. Un candidat este considerat promovat dacă a obţinut un punctaj de minim 80 puncte.

III.b) Să se creeze o interogare care să afişeze o listă a cursanţilor care au promovat testele susţinute la un anumit modul, într-un anumit trimestru al anului curent. Denumirea modulului şi numărul trimestrului se vor introduce la rularea interogării. Un test se consideră promovat dacă s-a obţinut un punctaj de minim 80 puncte.

Page 51: Studii de Caz Access 2007

III.c) Să se mărească cu 20% tariful de testare perceput pentru toate testările programate după data curentă, la modulele Excel 2 şi Access 2, în zile de week-end.

Această cerere este o interogare de actualizare. La crearea sa, se apasă butonul Update

, care afişează rândul Update to, in cadrul grilei QBE.

Pentru aflarea zilei din săptămână corespunzătoare datei testării se foloseşte funcţia Weekday. S-a utilizat, drept al doilea argument al funcţiei, tipul 2- conform căruia ziua 1 este considerată ziua de luni şi ziua 7 cea de duminică.

III.d) Să se afişeze modulele pentru care sunt programate testări pentru următoarea lună, pe săli, pe date şi pe ore.

IIf(Month(Date())=12;1;Month(Date())+1)

IIf(Month(Date())=12;Year(Date())+1;Year(Date()))

Page 52: Studii de Caz Access 2007

Studii de caz

52

Pentru rezolvarea acestei cerinţe se poate crea o interogare de tip tabel încrucişat, cu următoarea structură:

• Antet de rând – data şi ora de începere a testării

• Antet de coloană – numărul sălii

• Conţinut tabel – denumirea modului.

Crearea unei astfel de interogări presupune apăsarea butonului , care afişează două noi rânduri în grila QBE: Total şi Crosstab.

Pentru afişarea rezultatelor doar pentru luna următoare se adaugă următoarele condiţii:

• Luna testării trebuie să fie egală cu luna curentă + 1. În cazul în care luna curentă este decembrie (12), luna următoare este considerată luna ianuarie (1).

• Anul testării trebuie să fie egal cu anul curent, cu excepţia cazului în care luna curentă este decembrie (12), când anul testării va fi egal cu anul curent + 1.

Studiu individual:

a) Să se afişeze testările programate pentru module de nivel avansaţi, în zile de week-end, în lunile martie, iunie şi septembrie ale anului curent. b) Să se afişeze pentru un examinator (al cărui identificator este introdus la rularea interogării) numărul fiecărei săli la care are programate testări în următoarea lună. Rezultatul va fi afişat sub formă de tabel încrucişat (crosstab), luând în considerare data testării, ora de început a testării şi denumirea modulului pentru care este organizată testarea. c) Să se afişeze punctajul minim, punctajul maxim şi media punctajelor obţinute de către cursanţi pentru fiecare testare organizată în ultima jumătate a anului precedent.

IV. Realizaţi interogări SQL pentru următoarele cerinţe: IV.a) Să se afişeze pentru un candidat (al cărui CNP se introduce la rularea interogării) o listă a modulelor pentru care a obţinut punctaj de promovare la testările susţinute. Promovarea unui test presupune obţinerea a minim 80 puncte.

SELECT Module.DenumireModul, Rezultate.PunctajObtinut FROM ([Module] INNER JOIN Testari ON Module.IDModul = Testari.IDModul) INNER JOIN (Candidati INNER JOIN Rezultate ON Candidati.CNP = Rezultate.CNP) ON Testari.IDTestare = Rezultate.IDTestare WHERE Candidati.CNP=[Introduceti CNP-ul candidatului] AND Rezultate.PunctajObtinut>=80;

IV.b) Să se afişeze modulele pentru care nu s-a organizat nici o testare. SELECT Module.IDModul, Module.DenumireModul, Module.NivelModul FROM [Module] LEFT JOIN Testari ON Module.IDModul=Testari.IDModul WHERE Testari.IDModul IS NULL;

Page 53: Studii de Caz Access 2007

IV.c) Să se afişeze toate modulele de nivel avansaţi, pentru care au fost organizate mai mult de 30 de testări, în anii 2007 şi 2008.

SELECT Module.DenumireModul, Count([IDTestare]) AS NumarTestari FROM [Module] LEFT JOIN Testari ON Module.IDModul=Testari.IDModul WHERE Module.NivelModul="avansati" AND Year([DataTestare]) In (2007,2008) GROUP BY Module.DenumireModul HAVING Count([IDTestare])>30;

IV.d) Să se şteargă testările programate la date anterioare datei curente, dar care nu au avut loc efectiv deoarece nu s-a înscris nici un cursant.

DELETE * FROM Testari WHERE [DataTestare]<Date() AND IDTestare NOT IN (SELECT Inscrieri.IDTestare FROM Testari INNER JOIN Inscrieri ON Testari.IDTestare = Inscrieri.IDTestare);

IV.e) Să se afişeze primii 10 candidaţi înscrişi la testări în prima lună a anului curent. În cazul în care un candidat s-a înscris la mai multe module, numele acestuia va apărea o singură dată pe listă.

SELECT DISTINCT TOP 10 Candidati.CNP, Candidati.NumePrenume FROM Candidati INNER JOIN Inscrieri ON Candidati.CNP=Inscrieri.CNP WHERE (((Month([DataInscriere]))=1) AND ((Year([DataInscriere]))=Year(Date())));

IV.f ) Să se afişeze numărul de candidaţi înscrişi pe module, în fiecare an, din anul 2005 până în prezent. Modulele vor fi grupate pe nivele, afişându-se mai întâi cele corespunzătoare nivelului începători.

TRANSFORM Count(Candidati.CNP) AS NumarCandidati SELECT Module.NivelModul, Module.DenumireModul FROM ([Module] INNER JOIN Testari ON Module.IDModul = Testari.IDModul) INNER JOIN (Candidati INNER JOIN Inscrieri ON Candidati.CNP = Inscrieri.CNP) ON Testari.IDTestare = Inscrieri.IDTestare WHERE Year([DataTestare]) Between 2005 And Year(Date()) GROUP BY Module.NivelModul, Module.DenumireModul ORDER BY Module.NivelModul DESC PIVOT Year([DataTestare]);

IV.g) Să se creez un tabel numit ArhivaTestari, care să cuprindă detalii privind testările care au fost organizate până în anul precedent.

SELECT Testari.IDTestare, Testari.DataTestare, Testari.OraIncepereTestare, Testari.DurataTestare, Testari.TarifTestare, Testari.IDModul, Module.DenumireModul, Module.NivelModul, Testari.IDExaminator, Examinatori.NumePrenumeExaminator, Testari.NumarSala, Sali.NumarLocuri INTO ArhivaTestari

Page 54: Studii de Caz Access 2007

Studii de caz

54

FROM Sali INNER JOIN ([Module] INNER JOIN (Examinatori INNER JOIN Testari ON Examinatori.IDExaminator = Testari.IDExaminator) ON Module.IDModul = Testari.IDModul) ON Sali.NumarSala = Testari.NumarSala WHERE Year([DataTestare])<=Year(Date())-1;

IV.h) Să se adauge în tabelul ArhivaTestari (creat la punctul anterior) toate testările organizate în primul trimestru al anului curent.

INSERT INTO ArhivaTestari ( IDTestare, DataTestare, OraIncepereTestare, DurataTestare, TarifTestare, IDModul, DenumireModul, NivelModul, IDExaminator, NumePrenumeExaminator, NumarSala, NumarLocuri ) SELECT Testari.IDTestare, Testari.DataTestare, Testari.OraIncepereTestare, Testari.DurataTestare, Testari.TarifTestare, Testari.IDModul, Module.DenumireModul, Module.NivelModul, Testari.IDExaminator, Examinatori.NumePrenumeExaminator, Testari.NumarSala, Sali.NumarLocuri FROM Sali INNER JOIN ([Module] INNER JOIN (Examinatori INNER JOIN Testari ON Examinatori.IDExaminator = Testari.IDExaminator) ON Module.IDModul = Testari.IDModul) ON Sali.NumarSala = Testari.NumarSala WHERE Year([DataTestare])=Year(Date()) AND DatePart("q",[DataTestare])=1;

IV.i) Să se afişeze denumirea modulului la care s-au înscris cei mai mulţi candidaţi. SELECT Module.DenumireModul, Count(Candidati.CNP) AS NrCandidatiInscrisi FROM Candidati INNER JOIN (([Module] INNER JOIN Testari ON Module.IDModul=Testari.IDModul) INNER JOIN Inscrieri ON Testari.IDTestare=Inscrieri.IDTestare) ON Candidati.CNP=Inscrieri.CNP GROUP BY Module.DenumireModul HAVING Count(Candidati.CNP)>=ALL (SELECT Count(Candidati.CNP) FROM Candidati INNER JOIN (([Module] INNER JOIN Testari ON Module.IDModul = Testari.IDModul) INNER JOIN Inscrieri ON Testari.IDTestare = Inscrieri.IDTestare) ON Candidati.CNP = Inscrieri.CNP GROUP BY Module.DenumireModul);

IV.j) Să se micşoreze cu 15% tariful perceput pentru testările programate în următoarea perioadă, la care s-a înscris un număr de candidaţi mai mic decât jumătate din numărul de locuri disponibile în sălile în care acestea sunt organizate.

UPDATE Testari SET TarifTestare = [TarifTestare]*85/100 WHERE [DataTestare]>Date() AND IDTestare IN (SELECT Testari.IDTestare FROM Testari LEFT JOIN Inscrieri ON Testari.IDTestare = Inscrieri.IDTestare GROUP BY Testari.IDTestare HAVING Count(Inscrieri.IdInscriere)<=ALL (SELECT [NumarLocuri]/2 As JumatateLocuriSala FROM Sali INNER JOIN (Testari LEFT JOIN Inscrieri ON Testari.IDTestare = Inscrieri.IDTestare) ON Sali.NumarSala = Testari.NumarSala));

Page 55: Studii de Caz Access 2007

Studiu individual:

a) Să se afişeze numărul de testări la care a fost responsabil fiecare examinator al centrului, în ultimul trimestru al anului precedent.

b) Să se afişeze o listă a sălilor în care nu a fost organizată nici o testare.

c) Să se afişeze detalii privind candidatul care s-a înscris la cele mai multe testări.

d) Să se şteargă testările programate în următoarea lună, la care s-a înscris un număr de candidaţi mai mic de 5.

e) Să se creeze un nou tabel, numit DetaliiCandidati, care să cuprindă suplimentar faţă de datele preluate din tabelul Candidati, informaţii privind data naşterii şi vârsta fiecărui candidat.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular care să permită înscrierea candidaţilor la testările programate pentru diferite module.

În cadrul formularului creat pentru rezolvarea acestei cerinţe se selectează din lista Denumirea modului pentru care se face înscrierea şi se apasă butonul Afişare testări programate, care afişează într-o listă toate testările programate pentru următoarea perioadă, pentru modulul selectat anterior, la care mai sunt locuri disponibile (numărul de candidaţi înscrişi la o testare nu trebuie să depăşească numărul de locuri din sala în care se desfăşoară). Se selectează din listă testarea

la care doreşte candidatul să se înscrie şi se apasă butonul Fişă înscriere, ceea ce va conduce la afişarea câmpurilor ce trebuie completate pentru înregistrarea propriu-zisă a înscrierii în baza de date.

Page 56: Studii de Caz Access 2007

Studii de caz

56

În cadrul fişei de înscriere este necesară doar completarea CNP-ului candidatului, celelalte câmpuri fiind completate automat astfel: data înscrierii va fi considerată data curentă, numele candidatului va fi preluat din tabelul „Candidaţi” în funcţie de CNP, iar ID testare va fi preluat de la testarea selectată în lista testărilor programate. În cazul în care candidatul nu se află în baza de date a centrului de testare, acesta poate fi înregistrat prin apăsarea butonului Adaugă candidat, ce deschide un formular (prezentat

la punctul V.b.) ce permite introducerea datelor acestuia. După completarea fişei de înscriere se apasă butonul Salvare înscriere, pentru salvarea acesteia în baza de date. Formularul de înscriere va fi închis prin apăsarea butonului Închidere formular.

Pentru realizarea acestui formular din meniul Create se alege opţiunea Form Design, după care se salvează noul formular sub denumirea frmInscriere. Din categoria Form Design Tools, se utilizează următoarele butoane pentru adăugarea controalelor pe formular:

- Casetă text (Text Box)

- Buton de comandă (Button)

- Casetă combinată (Combo Box)

- Listă derulantă (List Box)

Utilizând butonul Property Sheet se afişează lista de proprietăţi. Pentru controalele adăugate pe formularul de înscriere a candidaţilor se stabilesc proprietăţile prezentate în tabelul de mai jos.

Pentru formular se vor modifica proprietăţile:

• Caption: Formular inscriere candidati

• Record Selectors: No • Navigation Buttons: No • Close Button: No • On Load: Cod VBA 1

Notă: Codurile VBA şi interogările utilizate drept sursă pentru formular şi pentru unele controale, vor fi prezentate după tabelul de proprietăţi.

Page 57: Studii de Caz Access 2007

Control Proprietăţi

• Name: cboDenumireModul • Row source: SELECT IDModul,

DenumireModul, NivelModul FROM Module ORDER BY DenumireModul

• Row source type: Table/Query • Limit to list: Yes • Column count: 3 • Column widths: 0cm;2,544cm;2,501cm

Tip control: Combo Box Controlul are drept sursă câmpurile din tabelul Module.

Tip control: Button

• Name: cmdAfisareTestariProgramate • Caption: Afisare testari programate • On click: Event procedure -> Cod VBA 2

• Name: lstTestariProgramate • Row source: TestariProgramate • Row source type: Table/Query • Limit to list: Yes • Column count: 5 • Column Heads: yes • Column widths:

2cm;2,507cm;3,501cm;2,507cm;2cm

Tip control: List Box

Lista derulanta are drept sursă interogarea TestariProgramate.

Tip control: Button

• Name: cmdFisaInscriere • Caption: Fisa inscriere • On click: Event procedure -> Cod VBA 3

• Name: txtDataInscriere • DefaultValue: Date() • Enabled: No

Tip control: Text Box

La această rubrică va fi afişata în mod implicit data curentă, utilizatorul neputând edita acest câmp.

Tip control: Combo Box

• Name: cboCNP • Row source: SELECT [Candidati].[CNP]

FROM Candidati; • Row source type: Table/Query • Limit to list: Yes • Column count: 1

Page 58: Studii de Caz Access 2007

Studii de caz

58

• Column widths: 2,54cm • On change: Event procedure -> Cod VBA 4 • On got focus: Event procedure -> Cod VBA 5 Controlul utilizează ca sursă câmpul CNP din tabelul Candidaţi. La modificarea câmpului (evenimentul Change) este definită o procedură care să actualizeze numele candidatului în formular, în funcţie de noul CNP selectat. La accesarea câmpului (evenimentul Got focus) este definită o procedură care actualizează elementele din listă, în cazul în care a fost adăugat un nou candidat în baza de date, utilizând butonul Adaugare candidat.

Tip control: Button

• Name: cmdAdaugareCandidat • Caption: Adaugare candidat • On click: Event procedure -> Cod VBA 6

• Name: txtDataInscriere • Control source: =DLookUp("[NumePrenume]";"Candidati";"[CNP]=" & "[Forms]![frmInscriere]![cboCNP]") • Enabled: No

Tip control: Text Box

Funcţia DlookUp preia numele şi prenumele candidatului din tabelul Candidati, în funcţie de CNP-ul selectat în formular la rubrica CNP candidat. Utilizatorul nu poate modifica conţinutul acestui câmp.

• Name: txtIDTestare • Enabled: No

Tip control: Text Box Valoarea acestui câmp este atribuită în mod

automat la apăsarea butonului Fisa Inscrirere, fiind preluat identificatorul testării selectate în lista testărilor programate. Utilizatorul nu poate modifica conţinutul acestui câmp.

Tip control: Button

• Name: cmdSalvareInscriere

• Caption: Salvare inscriere

• On click: Event procedure -> Cod VBA 7

Page 59: Studii de Caz Access 2007

• Name: cmdInchidereFormular • Caption: Inchidere formular • On click: Macro pentru închidere formular

Tip control: Button Pentru ataşarea macrocomenzii pentru închiderea

formularului se executa click mouse dreapta pe buton, se alege Build Event -> Macro Builder:

Action: Close

Arguments: Form; frmInscriere; Yes

Cod VBA 1: La încărcarea formularului frmInscrieri (evenimentul On Load), controalele aferente fişei de înscriere nu trebuie să fie vizibile, deoarece înainte de completarea acestora este necesară selectarea testării pentru care se face înscrierea. Astfel, este necesară definirea următoarei proceduri VBA:

Private Sub Form_Load() txtDataInscirere.Visible = False

cbocnp.Visible = False

txtNumePrenume.Visible = False txtIDTestare.Visible = False

cmdSalvareInscriere.Visible = False cmdAdaugareCandidat.Visible = False

End Sub

Cod VBA 2: La apăsarea butonului Afişare testări programate (evenimentul On Click) se vor afişa testările programate pentru modulul selectat la rubrica Denumire modul. În cazul în care nu a fost selectat nici un modul, se va afişa mesajul "Selectaţi denumirea modulului!". Procedura aferentă acestui eveniment este următoarea:

Private Sub cmdAfisareTestariProgramate_Click() If cboDenumireModul.listindex = -1 Then

MsgBox "Selectati denumirea modulului!" Else

lstTestariProgramate.Requery

End If

End Sub

Pentru afişarea testărilor programate în cadrul listei lstTestariProgramate, se utilizează drept sursă a acesteia interogarea TestariProgramate. Această interogare returnează detalii privind testările programate la o dată ulterioară datei curente, pentru modulul selectat la rubrica Denumire modul, la care mai există locuri disponibile (numărul cursanţilor înscrişi până la momentul respectiv este mai mic decât numărul locurilor din sala în care se desfăşoară testarea).

Page 60: Studii de Caz Access 2007

Studii de caz

60

Interogarea TestariProgramate are următorul conţinut:

SELECT Testari.IDTestare, Testari.DataTestare, Testari.OraIncepereTestare, Testari.DurataTestare, Testari.TarifTestare, Testari.IDModul, [Numar locuri disponibile la fiecare testare].NumarLocuriDisponibile FROM Testari INNER JOIN [Numar locuri disponibile la fiecare testare] ON Testari.IDTestare = [Numar locuri disponibile la fiecare testare].IDTestare WHERE (((Testari.DataTestare)>Date()) AND ((Testari.IDModul)=[Forms]![frmInscriere]![cboDenumireModul].[value]) AND (([Numar locuri disponibile la fiecare testare].NumarLocuriDisponibile)>0));

În cadrul acestei interogări au fost utilizate rezultatele unei alte interogări - Numar locuri disponibile la fiecare testare, care calculează numărul de locuri care au rămas disponibile pentru fiecare testare programată:

SELECT Testari.IDTestare, Count(Inscrieri.IDInscriere) AS NumarCandidatiInscrisi, Sali.NumarLocuri, [NumarLocuri]-[NumarCandidatiInscrisi] AS NumarLocuriDisponibile

FROM (Sali INNER JOIN Testari ON Sali.NumarSala = Testari.IDSala) LEFT JOIN Inscrieri ON Testari.IDTestare = Inscrieri.IDTestare

GROUP BY Testari.IDTestare, Sali.NumarLocuri;

Cod VBA 3: Butonul Fisa Inscriere va afişa la executarea evenimentului Click controalele aferente fişei de înscriere, preluând la rubrica ID Testare identificatorul testării selectate anterior din lista testărilor programate. În cazul în care nu a fost selectată nici o testare din listă se afişează mesajul "Selectaţi o testare din lista!".

Private Sub cmdFisaInscriere_Click() ‘ se verifică dacă a fost selectată o testare din lista lstTestariProgramate

If lstTestariProgramate.ItemsSelected.Count = 0 Then

MsgBox "Selectati o testare din lista!"

Else ‘ se atribuie casetei text txtIDTestare, id-ul testarii selectate in lista lstTestariProgramate

Dim Item As Variant

Set Item = lstTestariProgramate.ItemsSelected txtIDTestare = lstTestariProgramate.Column(0, Item) ‘ se afişează controalele aferente fişei de înscriere

txtDataInscirere.Visible = True cbocnp.Visible = True

txtNumePrenume.Visible = True txtIDTestare.Visible = True

cmdSalvareInscriere.Visible = True cmdAdaugareCandidat.Visible = True

End If

End Sub

Page 61: Studii de Caz Access 2007

Cod VBA 4: La completarea fişei de înscriere, în situaţia în care candidatul există în baza de date, CNP-ul acestuia se va selecta din listă la rubrica CNP candidat. În caz contrar, se va utiliza butonul Adaugare candidat, pentru adaugarea acestuia în baza de date şi apoi se va selecta CNP-ul din listă. În funcţie de CNP-ul selectat se vor afişa numele şi prenumele candidatului la rubrica Nume candidat. La modificarea CNP-ului, trebuie să se realizeze şi modificarea numelui şi prenumelui aferente candidatului respectiv. Din acest motiv este necesară definirea următoarei proceduri la evenimentul On Change aferent controlului cboCNP:

Private Sub cboCNP_Change() txtNumePrenume.Requery

End Sub

Cod VBA 5: În cazul în care s-a utilizat butonul Adaugare candidat pentru adăugarea unui nou candidat în baza de date, la revenirea în formularul de înscriere este necesară actualizarea listei CNP-urilor când aceasta este accesată. Astfel, va fi definită următoarea procedură pentru evenimentul On Got focus aferent controlului cboCNP:

Private Sub cboCNP_GotFocus() cbocnp.Requery

End Sub

Cod VBA 6: Butonul Adaugare candidat are ataşat codul VBA pentru deschiderea formularului frmCandidati, utilizat pentru introducerea unui candidat în baza de date. Formularul va fi deschis în modul acFormAdd, care permite doar introducerea unui nou candidat în baza de date, nu şi modificarea celor existenţi.

Private Sub cmdAdaugareCandidat_Click() DoCmd.OpenForm "frmAdaugareCandidat", acNormal, , , acFormAdd

End Sub

Cod VBA 7: Salvarea înscrierii în baza de date se face prin apăsarea butonului Salvare înscriere. În cazul în care nu a fost completat CNP-ul candidatului, sistemul afişează un mesaj de atenţionare.

Private Sub cmdSalvareInscriere_Click() ‘ se verifică dacă a fost completat CNP-ul

If cbocnp.listindex = -1 Then

MsgBox "Completati CNP-ul candidatului!"

Else Dim setul As Recordset ‘ declarare recordset

Set setul = CurrentDb().OpenRecordset("Inscrieri", dbOpenTable) ‘ se adaugă conţinutul controalelor de pe formular în câmpurile tabelei Inscrieri setul.AddNew

setul!CNP = cbocnp.Value

setul!idtestare = txtIDTestare.Value

setul.Update

Page 62: Studii de Caz Access 2007

Studii de caz

62

MsgBox "Inscriere efectuata"

End If End Sub

V.b) Realizaţi un formular care să permită adăugarea unui nou candidat în baza de date. Acest formular se va deschide la apăsarea butonului Adăugare client din cadrul formularului de înscriere a candidaţilor pentru susţinerea unei testări (prezentat la punctul anterior). Afişaţi în acest formular, suplimentar faţă de datele candidatului, data naşterii şi vârsta acestuia, în funcţie de codul numeric personal.

Pentru rezolvarea acestei cerinţe poate fi creat un formular ale cărui câmpuri să fie legate la câmpurile din tabelul Candidati. Crearea formularului poate fi realizată fie în modul Form Design, fie utilizând instrumentul Wizard. Astfel, formularul va cuprinde casete text pentru introducerea următoarelor date ale candidatului: CNP, nume şi prenume, serie carte identitate, număr carte identitate, adresă şi localitate. Suplimentar se vor adaugă două casete text în care vor fi afişate data naşterii şi vârsta candidatului, precum si un buton Revenire, ce închide acest formular, permiţând revenirea la formularul de înscriere a candidatului pentru susţinerea unei testări.

Control Proprietăţi

Tip control: Text Box

• Name: txtDataNasterii • Control Source:

=IIf(IsNull([cnp]);"";DateValue(Mid([cnp];4;2) & "." & Mid([cnp];6;2) & "." & (Switch(Mid([cnp];1;1)=1;19;Mid([cnp];1;1)=2;19;Mid([cnp];1;1)=5;20;Mid([cnp];1;1)=6;20) & Mid([cnp];2;2))))

• Enable: No

Data naşterii se obţine extrăgând din CNP: Ziua naşterii Luna naşterii Anul naşterii

Vârsta se calculează ca diferenţă între data curentă şi data naşterii.

Închide formularul

Page 63: Studii de Caz Access 2007

Tip control: Text Box

• Name: txtVarsta • Control Source:

=IIf(IsNull([cnp]);"";Int((Now()-[txtDataNasterii])/365,25) & " ani")

• Enable: No

• Name: cmdRevenire • Caption: Revenire • On click: Macro pentru închidere formular

Tip control: Button Pentru ataşarea macrocomenzii pentru închiderea

formularului se executa click mouse dreapta pe buton, se alege Build Event -> Macro Builder: Action: Close Arguments: Form; frmAdaugareCandidat; Yes

La obţinerea datei de naştere din CNP s-au folosit următoarele funcţii:

DateValue – converteşte un şir de caractere reprezentând luna, ziua şi anul, pentru obţinerea unei date calendaristice. Aceste şiruri de caractere trebuie să fie separate de un simbol valid pentru formatul de dată.

Mid – extrage o anumită parte dintr-un şir de caractere. Argumentele funcţiei sunt:

• şirul de caractere din care se face extragerea • valoarea poziţională a caracterului de la care se începe extragerea • numărul de caractere de extras

Switch – evaluează o lisă de expresii şi returnează o valoare sau o expresie asociată cu prima expresie din listă care este adevărată. Argumentele funcţiei sunt perechi formate din expresii şi valori. Expresiile sunt evaluate de la stânga la dreapta. Funcţia va returna valoarea asociată cu prima expresie care este evaluată ca fiind adevărată.

La obţinerea anului naşterii se ia în considerare prima cifră a CNP-ului, după cum urmează:

• 1 / 2 – data naşterii cuprinsă între 1 ianuarie 1900 şi 31 decembrie 1999 • 3 / 4 - data naşterii cuprinsă între 1 ianuarie 1800 şi 31 decembrie 1899 • 5 / 6 - data naşterii cuprinsă între 1 ianuarie 2000 şi 31 decembrie 2099

Pentru a evita afişarea unei erori în casetele text aferente datei naşterii şi vârstei, în cazul în care CNP-ul nu este încă completat, se utilizează funcţiile IIf şi IsNull.

Studiu individual:

a) Realizaţi un formular care să permită adăugarea unei noi testări în baza de date. La planificarea sălii se va avea în vedere faptul că aceasta trebuie să fie disponibilă la data şi în intervalul de timp pentru care este programată testarea.

b) Realizaţi un formular destinat introducerii punctajelor obţinute de către fiecare candidat la o anumită testare.

Page 64: Studii de Caz Access 2007

Studii de caz

64

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Să se creeze un raport care să afişeze detalii privind testările programate, pe fiecare modul, într-o anumită perioadă (ce se va introduce intr-un formular înainte de deschiderea raportului).

Rezolvare:

Pentru crearea raportului din meniul Create se alege opţiunea Report Wizard. Sursa raportului este constituită din câmpuri aparţinând mai multor tabele, după cum urmează:

• Tabelul Module: DenumireModul, NivelModul • Tabelul Testari: DataTestare, OraIncepereTestare, DurataTestare,

TarifTestare, NumarSala Se va alege opţiunea de vizualizare a datelor în funcţie de Module (by Module) şi se va face o sortare a acestora după câmpul DataTestare, ascendent.

Page 65: Studii de Caz Access 2007

După creare, raportul se deschide în modul Design View şi se efectuează următoarele modificări ale acestuia:

• În antetul raportului (Report Header) se adaugă două controale de tip Text Box pentru afişarea perioadei pentru care se întocmeşte:

Element afişat Proprietăţi

Data început perioada • Name: txtInceputPerioada

• Control Source: =[Forms]![frmPerioada]![txtDataInceput]

• Enable: No

Data sfârşit perioada • Name: txtSfarsitPerioada

• Control Source:

=[Forms]![frmPerioada]![txtDataSfarsit]

Sursa controalelor o reprezintă datele calendaristice introduse în formularul frmPerioada, în casetele text txtDataInceput şi txtDataSfarsit, înainte de deschiderea raportului.

• Pentru ca raportul creat să afişeze doar informaţii privind testările programate în perioada introdusă în formularul frmPerioada, înainte de deschiderea raportului, este necesară adăugarea următorului filtru:

Page 66: Studii de Caz Access 2007

Studii de caz

66

• Pentru calcularea orei de terminare a testării, în secţiunea Detail a raportului, se adaugă un control de tip Text Box, cu următoarea sursă (proprietatea Control Source):

=Format([OraIncepereTestare]-[DurataTestare];"Short Time") • Afişarea numărului de testări programate pentru fiecare modul, se face

adăugând în subsolul grupării IDModul (secţiunea IDModul Footer) a unui control de tip Text Box. Sursa pentru acest control este următoarea:

="Numar testari programate pentru modulul " & [DenumireModul] & ", " & "nivel " & [NivelModul] & ": " & Count([DenumireModul])

Afişarea subsolului grupării IDModul se face apăsând butonul şi selectând oţiunea with a footer section, din cadrul fereastrei Group, Sort, and Total.

• La sfârşitul raportului va fi afişat numărul total de testări programate. Pentru realizarea acestei cerinţe, se creează un control de tip Text Box în subsolul raportului (secţiunea Report Footer), cu următoarea sursă:

="Numar total testari programate in perioada " & [txtInceputPerioada] & " - " & [txtSfarsitPerioada] & ": " & Count([DenumireModul])

VI.b) Să se creeze un raport pentru afişarea rezultatelor obţinute de către candidaţi la o anumită testare, ce se va selecta dintr-o listă înainte de deschiderea raportului. În funcţie de punctajul obţinut se va afişa calificativul corespunzător astfel:

• punctaj < 80 puncte: calificativul ”nepromovat”

• punctaj >= 80 puncte: calificativul ”promovat”

Rezultatele vor fi afişate în ordine descrescătoare a punctajelor, iar calificativele vor fi formatate cu culori diferite: roşu pentru nepromovat şi albastru pentru promovat.

La finalul raportului se vor calcula: numărul total de candidaţi, numărul de candidaţi promovaţi şi numărul de candidaţi respinşi.

Page 67: Studii de Caz Access 2007

Rezolvare:

Pentru crearea raportului din meniul Create se alege opţiunea Report Wizard. Sursa raportului este constituită din câmpuri aparţinând mai multor tabele, după cum urmează:

• Tabelul Rezultate: CNP, PunctajObtinut

• Tabelul Candidati: NumePrenume • Tabelul Testari: IDTestare, DataTestare • Tabelul Module: DenumireModul, NivelModul

Se va alege opţiunea de vizualizare a datelor în funcţie de Testari (by Testari) şi se va face o sortare a acestora după câmpul PunctajObtinut, descendent.

După creare, raportul se deschide în modul Design View şi se efectuează următoarele modificări ale acestuia:

Page 68: Studii de Caz Access 2007

Studii de caz

68

• Se muta în antetul raportului controalele ce cuprind informaţii privind: IDTestare, DataTestare, DenumireModul şi NivelModul.

• Se adaugă un control de tip Text Box, pentru afişarea calificativului corespunzător fiecărui candidat. Pentru acest control se modifică următoarele proprietăţi:

o Name: txtCalificativ

o Control Source: =IIf([PunctajObtinut]<80;"nepromovat";"promovat")

• În subsolul raportului (Report Footer) se adaugă trei controale de tip Text Box, pentru calcularea numărului total de candidaţi, a numărului de candidaţi promovaţi şi a numărului de candidaţi respinşi.

Element calculat Proprietatea Control Source

Număr total candidaţi =Count([CNP])

Număr candidaţi promovaţi =Sum(IIf([PunctajObtinut]>=80;1;0))

Număr candidaţi nepromovaţi =Sum(IIf([PunctajObtinut]<80;1;0))

• Pentru ca raportul creat să afişeze doar informaţii privind testarea care a fost selectată din listă (cboTestare), în formularul frmSelectareTestare, înainte de deschiderea raportului, este necesară adăugarea următorului filtru:

Page 69: Studii de Caz Access 2007

• Formatarea condiţională a calificativelor, în vederea aplicării unui font roşu

pentru calificativul ”nepromovat” şi a unui font albastru pentru cel ”promovat”, se face selectând controlul txtCalificativ şi apăsând butonul

. În cadrul ferestrei deschise pe ecran ca urmare a acestei acţiuni se adaugă următoarele condiţii, cu formatările aferente:

Studiu individual:

a) Să se creeze un raport care să afişeze lista candidaţilor înscrişi pentru fiecare testare programată într-o anumită perioadă (perioada se va introduce într-un formular înainte de deschiderea raportului). În cadrul raportului se va calcula numărul de candidaţi înscrişi pentru fiecare testare şi pe total. b) Să se creeze un raport cu toate testările programate la o dată ulterioară datei curente, cu precizarea pentru fiecare testare a: numărului de candidaţi înscrişi, a numărului total de locuri disponibile, precum şi a numărului de locuri neocupate. Se vor evidenţia, prin aplicarea unui font roşu, testările la care nu s-a înscris nici un candidat.

Page 70: Studii de Caz Access 2007

Studii de caz

70

Bază de date pentru gestiunea aprovizionărilor cu materiale la o firmă

Se doreşte realizarea unei baze de date pentru gestiunea aprovizionărilor cu materiala la o firmă ce dispune de mai multe depozite situate în locaţii diferite din ţară.

Depozitele firmei sunt numerotate şi, pentru fiecare dintre acestea sunt cunoscute localitatea şi adresa exactă.

Firma se aprovizionează cu materiale de la mai mulţi furnizori, identificaţi prin CUI furnizor, denumire firmă şi pentru care se cunosc ţara, localitatea şi adresa.

Toate materialele achiziţionate de firmă sunt cuprinse într-un nomenclator de materiale în care sunt specificate: codul material, denumire material, unitate de măsură (UM) şi clasa de calitate.

În momentul realizării unei aprovizionări la un depozit se întocmeşte o notă de recepţie pe care sunt consemnate: numărul recepţiei, data recepţie şi denumirile materialele aprovizionate cu cantităţile şi preţurile aferente pentru fiecare material. În final se calculează valoarea totală a materialelor recepţionate.

Notele de recepţie sunt semnate de o comisie de recepţie alcatuită din gestionarii depozitului. La un depozit sunt angajaţi unul sau mai mulţi gestionari pentru care se cunosc: cod numeric personal (CNP), Serie şi număr carte de identitate, nume gestionar, data angajare, data nastere şi număr telefon.

Reguli de gestiune:

• O notă de recepţie se întocmeşte la un singur depozit pentru materiale care provin de la un singur furnizor.

• Pe o notă de recepţie pot fi consemnate unul sau mai multe materiale.

• Numerele bonurilor de recepţie sunt atribuite în mod unic la nivelul firmei.

• Preţurile de aprovizionare ale materialelor sunt variabile în timp şi pot diferi de la un furnizor la altul.

• Un gestionar al firmei este angajat la un singur depozit (dar, aşa cum s-a precizat în enunţ, la un depozit sunt angajaţi mai mulţi gestionari).

• O comisie de recepţie e formată din unul sau mai mulţi gestionari ai depozitului.

I. Realizaţi modelul relaţional al bazei de date şi implementaţi în MS Access

Pe baza informaţiilor din enunţul problemei şi a regulilor de gestiune, se poate constitui dicţionarul atributelor şi se pot contura dependenţele funcţionale dintre acestea. Aceste aspecte sunt redate sintetic prin intermediul matricei dependenţelor funcţionale. Observaţie: Numele atributelor au fost prescurtate (de exemplu nume furnizor � NumeFz, cod material � CodM).

IV

Page 71: Studii de Caz Access 2007

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24

1 NrDepozit 1 1

2 LocalitateD

3 AdresaD

4 CUIFz 1 1 1 1

5 NumeFz

6 TaraFz

7 LocalitateFz

8 AdresaFz

9 CodM 1 1 1

10 NumeM

11 UM

12 Clasa

13 NrReceptie 1 1t 1t 1 1t 1t 1t 1t 1

14 DataReceptie

15 PretUnitar

16 Cantitate

17 CNP 1 1t 1t 1 1 1 1 1

18 NrCI

19 SerieCI

20 NumeGest

21 DataAngajare

22 TelefonGest

23 CodM+NrReceptie 1 1

Page 72: Studii de Caz Access 2007

Studii de caz

72

Observaţii:

• Nu au fost luate în considerare atributele calculate. În cazul de faţă, atribut calculat este valoarea totală a materialelor recepţionate.

• Nu au fost luate în considerare decât o singură dată atributele sinonime (de exemplu numele materialului din nomenclatorul de materiale şi denumire material de pe fiecare notă de recepţie)

• Potenţialele chei primare (atributele determinante) au fost subliniate în prima coloană.

• Dependenţele funcţionale au fost marcate cu simbolul 1, iar cele tranzitive cu 1t.

• S-a constata că atributul CNP şi atributul compus din Serie şi Număr CI (carte de identitate) reprezintă potenţiale chei candidate pentru că determină aceleaşi atribute (cele care descriu gestionarul). În plus, între cele două există dependenţe funcţionale reciproce (la o realizare a CNP corespunde o singură combinaţie Serie şi Număr CI şi invers). A fost preferat ca determinant atributul CNP, alegerea având la bază criteriul stabilităţii în timp (CNP nu se modifică pe parcursul existenţei unei persoane)

• După marcarea dependenţelor funcţionale s-a constat că atributele PretUnitar şi Cantitate nu sunt determinate funcţional de către nici una din potenţialele chei primare. În acest scop s-a căutat un determinant compus şi a fost identificată combinaţia formată din CodM şi NrReceptie pe baza căreia se poate specifica un singur preţ şi o singură cantitate aprovizionată (dintr-un anumit material, la o anumită recepţie) .

Încercând să conturăm modelul relaţional al bazei de date plecând de la matricea dependenţelor funcţionale şi de la observaţiile anterioare se pot defini următoarele tabele:

Depozit (NrDepozit, LocalitateD, AdresaD)

Furnizor (CUIFz, NumeFz, TaraFz, LocalitateFz, AdresaFz)

Material (CodM, NumeM, UM, Clasa )

Receptie (NrReceptie, DataReceptie, NrDepozit, CUIFz)

Gestionar (CNP, NrDepozit, SerieCI, NrCI, NumeGest, DataAngajare, TelefonGest)

ContinutReceptie (CodM, NrReceptie, Cantitate, PretUnitar)

Studiind legăturile existente între tabele şi revenind la enunţul problemei se constată că nu există suficiente legături cheie primară – cheie externă pentru a determina care sunt gestionarii care au semnat notele de recepţie. Întrucât între cheile primare ale tabelelor Gestionar şi Recepţie există dependenţe multivaloare reciproce (un gestionar poate asista la mai multe recepţii şi o recepţie e realizată de o comisie formată din mai mulţi gestionari, se impune adăugarea unui tabel intemediar care să asigure legătura. Acest tabel va descrie, de fapt, componenţa comisiilor de recepţie.

ComisieRecepţie (CNP, NrRecepţie)

Page 73: Studii de Caz Access 2007

Baze de date Access 2007

73

Rezultatul implementării modelului relaţional în Microsoft Access 2007 este următorul:

Studiu individual:

1. Pentru a utiliza cât mai eficient spaţiul de depozitare, după recepţionarea materialelor există posibilitatea ca acestea să fie mutate dintr-un depozit în altul. Pentru mutarea materialelor între depozite se întocmesc bonuri de transfer pe care se precizează: număr bon, data transfer, materialul transferat şi cantitatea aferentă. Un bon de transfer este întocmit pentru un singur material, la un singur depozit expeditor, către un singur depozit destinaţie. Fiecare bon de transfer este semnat de un gestionar la depozitul de unde pleacă materialul şi de către un gestionar la depozitul unde materialul ajunge. Adăugaţi modelului relaţional tabelul, sau tabelele, ce permit memorarea datelor privind transferurile de materiale.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) Pentru fiecare gestionar se va verifica DataAngajare să nu fie anterioară datei de 2 februarie 2000 (când s-a înfiinţat firma). Regula de validare este următoarea:

Page 74: Studii de Caz Access 2007

Studii de caz

74

II.b) Pentru a facilita introducerea datelor în tabelul ComisieReceptie, CNP gestionar se va selecta prin intermediul unei liste ce va afişa valorile pentru câmpurile CNP şi NumeGest din tabelul gestionari (gestionari vor fi afişaţi alfabetic).

În acest sens se va deschide tabelul ComisieReceptie in modul Design şi se va selecta câmpul CNP, după care se va alege secţiunea Lookup aferentă casetei de proprietăţi.

Se vor stabili următoarele proprietăţi:

• Display Control � ComboBox

• RowSource � SELECT CNP, NumeGest FROM GESTIONAR ORDER BY NumeGest;

• Column Count � 2 (pentru a afişa ambele câmpuri din instrucţiunea SELECT precizată ca sursă a listei)

Rezultatul este prezentat în figura următoare:

II.c) In tabelul Furnizori se va impune o regulă de validare, astfel încât, dacă se adaugă un furnizor din Spania, localitatea furnizorului nu se va putea completa decât cu valorile “Madrid” Sau “Toledo”.

Întrucât acestă validare se realizează prin compararea unor valori din câmpuri diferite,

Page 75: Studii de Caz Access 2007

Baze de date Access 2007

75

regula va fi implementată la nivelul validărilor tabelului. În acest scop se va deschide tabelul în modul Design şi se va apăsa butonul Properties din bara de instrumente.

Expresia pentru regula de validare este prezentată în figura următoare: IIf([TaraFZ]="Spania";[LocalitateFZ] In ("Madrid";"Toledo"))

Studiu individual:

Modificaţi proprietăţile la nivel de câmp sau tabel care să permită: a) Completarea automată a datelor de recepţie cu data curentă. b) Preturile şi cantităţile materialelor recepţionate să fie obligatoriu pozitive. c) Codurile unice (CUI) ale furnizorilor din tabelul Recepţie să poată fi selectate prin intermediul unei liste în care să figureze codurile şi numele furnizorilor din tabelul furnizori.

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se calculeze vechimea în ani pentru gestionarii care lucrează în depozitele firmei din Ploieşti şi, în funcţie de vechime, o primă de 1000 lei pentru cei cu vechime peste 5 ani şi 750 lei pentru ceilalţi.

Validare la nivel de tabel

Page 76: Studii de Caz Access 2007

Studii de caz

76

III.b) Să se calculeze Total cantitate recepţionată pe fiecare material în intervalul 1 ianuarie 2007 – 16 martie 2007.

Observaţie: Pentru câmpul DataRecepţie, în rândul Total al interogării s-a specificat opţiunea Where, întrucât acest câmp este necesar doar pentru impunerea condiţiilor, nu şi pentru gruparea.

III.c) Calculaţi valoarea totala a recepţiilor pe fiecare furnizor extern (din afara României) şi convertiţi această valoare în euro la un curs tastat ca parametru al interogării.

Observaţie: Pentru valoarea calculată în euro, în rândul total al interogării s-a selectat opţiunea Expression întrucât acest câmp este calculat pe baza câmpului Valoare, care este rezultatul unei agregări. Câmpurile PretUnitar şi Cantitate nu au fost incluse separat în grila interogării întrucât ar fi afectat gruparea datelor (unui furnizor îi corespund mai multe preţuri, etc.)

Page 77: Studii de Caz Access 2007

Baze de date Access 2007

77

III.d) Să se realizeze o interogare de tip CrossTab pentru a evidenţia preţul maxim al fiecărui material în fiecare lună a anului 2008 .

Observaţie: După apăsarea butonul CrossTab din bara de instrumente, în grila interogării devine vizibil rândul Crosstab în care se va preciza ce câmp de grupare va fi afişat pe coloanele tabelului (Column heading), care sunt câmpurile ce vor fi afişate pe rânduri (Row Heading) şi care sunt valorile de afişat la intersecţie (Value) Rezultatul interogării e prezentat în figura următoare:

Notă: În lunile anului care nu sunt afişate pe coloane nu există recepţii. Studiu individual:

Realizaţi următoarele interogări : a) Calculaţi câţi salariaţi a angajat firma în anul 2009 în fiecare oraş. b) Calculaţi diferenţa între preţul maxim şi preţul minim de recepţie pe fiecare material.

Interogare de tip CrossTab

Page 78: Studii de Caz Access 2007

Studii de caz

78

IV. Realizaţi interogări SQL pentru următoarele cerinţe:

IV.a) Care sunt cei mai noi 10 angajati din firmă ? SELECT TOP 10 NumeGest FROM Gestionar ORDER BY DataAngajare DESC

IV.b) Să se extragă într-un tabel numit Concedieri toţi angajaţii de la depozitele 1,2 şi 5. În tabelul Concedieri vor figura doar codurile numerice personale, numele gestionarilor şi, într-un câmp numit Motiv, se va afişa textul “inchidere depozit” pentru cei din depozitul 1 şi “absenţe nemotivate” pentru ceilalţi.

SELECT CNP, NumeGest, IiF(NrDepozit=1, "inchidere depozit", "absente") AS Motiv INTO Concedieri FROM Gestionar WHERE NrDepozit IN (1,2,5)

Observaţie: Interogarea de selecţie a fost transformată într-o interogare ce permite crearea unui nou tabel prin precizarea clauzei INTO, după instrucţiunea SELECT.

IV.c) Să se afişeze lista ordonată alfabetic cu numele furnizorilor de la care firma a realizat recepţii în ultimele 7 zile.

SELECT DISTINCT NumeFz FROM Furnizor, Receptie WHERE Furnizor.CUIFz=Receptie.CUIFz AND DataReceptie>Date()-7 ORDER BY NumeFz

Această interogare poate fi rezolvată prin exprimarea legăturii între tabelele sursă direct în clauza FROM astfel:

SELECT DISTINCT NumeFz FROM Furnizor INNER JOIN Receptie ON Furnizor.CUIFz=Receptie.CUIFz WHERE DataReceptie>Date()-7 ORDER BY NumeFz

Observaţie: Clauza DISTINCT a fost utilizată, imediat după instrucţiunea SELECT pentru a preîntâmpina apariţia în lista de rezultate a unui furnizor de mai multe ori (pentru fiecare recepţie de la acel furnizor).

IV.d) Să se afişeze numele şi adresele furnizorilor de la care firma a aprovizionat benzină.

SELECT DISTINCT NumeFz, TaraFz, LocalitateFz, AdresaFz FROM Furnizor AS F, Receptie AS R, ContinutReceptie AS CR, Material AS M WHERE F.CUIFz=R.CUIFz AND R.NrReceptie=CR.NrReceptie AND CR.CodM=M.CodM AND NumeM="benzina"

Observaţie: Întrucât, pentru a exprima legătura dintre furnizor şi material, este necesară preluarea în clauza FROM a tabelelor Receptie şi ConţinutRecepţie, pentru a

Page 79: Studii de Caz Access 2007

Baze de date Access 2007

79

scrie mai uşor interogarea s-au atribuit alias-uri numelor de tabele (de ex. Receptie AS R) .

IV.e) Să se afiseze numele gestionarilor de la depozitul 1 care nu au participat la nicio recepţie (CNP-ul acestor gestionari nu se regăseşte în tabelul ComisieRecepţie)

SELECT NumeGest FROM Gestionar LEFT JOIN ComisieReceptie ON Gestionar.CNP=ComisieReceptie.CNP WHERE ComisieReceptie.CNP IS NULL AND NrDepozit=1

Observaţie: Utilizarea LEFT JOIN în loc de INNER JOIN permite preluarea tuturor gestionarilor din depozitul 1, indiferent dacă aceştia apar în tabelul ComisieRecepţie sau nu. Filtrarea celor ca nu figurează în tabelul de comisii se realizează prin condiţia ComisieReceptie.CNP Is Null.

O altă variantă de rezolvare este următoarea: SELECT NumeGest FROM Gestionar WHERE NrDepozit=1 AND CNP NOT IN (SELECT CNP from ComisieReceptie)

IV.f ) Calculaţi cantitatea medie aprovizionată la o recepţie din fiecare material. Se va ordona lista descrescător, după cantiatatea medie determinată.

SELECT Material.CodM, NumeM, AVG(Cantitate) AS [Cantitate medie receptionata] FROM Material INNER JOIN ContinutReceptie ON Material.CodM=ContinutReceptie.CodM GROUP BY Material.CodM, NumeM ORDER BY AVG(Cantitate) DESC

IV.g) Să se afişeze lista furnizorilor de la care s-au realizat cel puţin de 10 recepţii după data de 10 martie 2009.

SELECT Furnizor.CUIFz, NumeFz, COUNT(NrReceptie) AS [Total receptii] FROM Furnizor INNER JOIN Receptie ON Furnizor.CUIFz=Receptie.CUIFz WHERE DataReceptie>#10/3/2009# GROUP BY Furnizor.CUIFz, NumeFz HAVING COUNT(NrReceptie)>=10

Observaţii:

• Condiţia ce implică utilizarea funcţiei agregat COUNT a condus la necesitatea utilizării clauzei HAVING.

• Câmpul DataRecepţie nu apare în instrucţiunea SELECT, ci doar în clauza WHERE întrucât nu este un câmp de grupare.

Page 80: Studii de Caz Access 2007

Studii de caz

80

IV.h) Să se diminueze cu 2% preţurile de recepţie aferente recepţiilor din ziua curentă pentru materialele din clasa de calitate 2.

UPDATE ContinutReceptie SET PretUnitar=PretUnitar*0.98 WHERE NrReceptie IN (SELECT NrReceptie FROM Receptie WHERE DataReceptie=Date() ) AND CodM IN (SELECT CodM FROM Material WHERE Clasa=2)

IV.i) Să se şteargă din baza de date toţi gestionarii din depozitul 1 şi ceilalţi de la alte depozite dacă nu figurează în nicio comisie de recepţie.

DELETE * FROM Gestionar WHERE NrDepoziit=1 OR CNP NOT IN (SELECT CNP FROM ComisieReceptie)

IV.j) Care este cel mai ieftin material recepţionat în anul 2009 ? (materialul recepţionat la cel mai mic preţ).

SELECT NumeM FROM Material INNER JOIN ContinutReceptie ON Material.CodM=ContinutReceptie.CodM WHERE PretUnitar <= ALL(SELECT PretUnitar FROM ContinutReceptie INNER JOIN Receptie ON ContinutReceptie.NrReceptie=Receptie.NrReceptie WHERE YEAR(DataReceptie)=2009)

Studiu individual:

a) Să se calculeze valoarea fiecărei recepţii şi valoarea TVA aferentă (aplicând o cotă de 19%) b) Să se calculeze câţi gestionari au participat la fiecare recepţie. c) Să se şteargă recepţiile ce provin de la furnizorul “ABC SRL”. d) Să se identifice care sunt gestionarii din depozitul 2 care au participat la mai mult de 100 recepţii în ultimul an. e) Să se calculeze cantitatea totală recepţionată din fiecare material, în fiecare an.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular cu subformular pentru a vizualiza la fiecare recepţie care sunt gestionarii ce fac parte din comisie. Pe formularul bazat pe tabelul Recepţie, codul furnizorului se va alege prin intermediul unui control de tip ComboBox, iar pe subformularul ce va avea ca sursă tabelul ComisieReceptie, gestionarii se vor alege de asemenea dintr-o listă. Această listă va fi conţine doar gestionarii din depozitul în care a avut loc recepţia.

Practic, subformularul nu va conţine decât un control de tip ComboBox în care se vor afişa CNP şi nume gestionar pentru a fi alcătuită comisia de recepţie.

Page 81: Studii de Caz Access 2007

Baze de date Access 2007

81

Formularul şi subformularul în mod Design sunt prezentate în figura următoare.

Cea mai simplă metodă pentru transformarea casetei CUIFz de pe formular în listă de tip ComboBox este să se efectueze click cu butonul drept al mouseului pe suprafaţa casetei şi, din meniul contextual, să se selecteze opţiunea Change To (figura următoare).

Apoi, prin intermediul casetei Properties se vor modifica următoarele proprietăţi ale listei de tip Combo:

• Row Source: SELECT CUIFz, NumeFz FROM Furnizor ORDER BY NumeFz

• Column Count: 2 (pentru a afişa ambele câmpuri din comanda SELECT)

• Colum Widths: 0cm;5cm (dacă se doreşte ascunderea primei coloane şi doar afişarea numelui furnizorului)

Pentru crearea listei de gestionari din subformular nu este însă suficient să se modifice tipul de control şi proprietăţile enumerate mai sus întrucât lista trebuie restrânsă la gestionarii de la depozitul unde are loc recepţia. Acest depozit este precizat în caseta NrDepozit pe formularul principal care îşi poate modifica valoarea de câte ori se trece la o altă recepţie.

În acest sens, vom stabili în mod dinamic sursa de date (row source) pentru lista ce permite selecţia gestionarilor în subformular. Acest lucru este necesar atunci când pe formular se trece la o altă notă de recepţie sau când utilizatorul modifică manual numărul depozitului unde are loc recepţia.

Formular

Subformular

Page 82: Studii de Caz Access 2007

Studii de caz

82

Evenimentul ce survine la nivelul formularului în momentul în care se trece de la o notă de recepţie la alta şi este necesară reconfigurarea listei de gestionari este On Current, iar evenimentul care survine la nivelul casetei NrDepozit, atunci când utilizatorul modifică numărul depozitului pentru nota de recepţie curentă este Before Update .

Pentru a nu scrie de mai multe ori aceeaşi instrucţiune care modifică sursa de date a listei CNP din subformular, vom crea o procedură ce va prelua ca argument numărul depozitului de pe formular:

Sub ActualizezListaGestionari(depozit)

ComisieReceptie.Controls("cnp").RowSource = _ "SELECT CNP, NumeGest FROM Gestionar WHERE NrDepozit=" & depozit

End Sub

Această procedură este apelată ori de câte ori survin evenimentele amintite anterior:

‘ deplasarea de la o înregistrare la alta în formularul principal

Private Sub Form_Current()

Call ActualizezListaGestionari(NrDepozit.Value)

End Sub

‘ modificarea de către utilizator a numărului depozitului Private Sub NrDepozit_BeforeUpdate(Cancel As Integer)

Call ActualizezListaGestionari(NrDepozit.Value)

End Sub

Formularul, în mod de vizualizare este prezentat în figura următoare:

V.b) Realizaţi un formular numit Catalog Materiale care să permită vizualizarea materialelor în format tabelar. Se va adăuga pentru fiecare material un buton numit “VizualizareFurnizori” care va permite afişarea listei furnizorilor de la care s-a aprovizionat materialul respectiv.

Page 83: Studii de Caz Access 2007

Baze de date Access 2007

83

Pentru a afişa lista furnizorilor aferenţi unuia dintre materialele de pe formular, se va proiecta mai întâi o interogare în care se va specifica, în rândul de criterii, codul materialului prin referirea casetei CodM de pe formularul Catalog Materiale.

Sintaxa utilizată este Forms!NumeFormular!NumeControl iar interogarea numită FurnizoriMateriale este prezentată în figura următoare:

Codul VBA ataşat butonul de comandă de pe formular are rolul să deschidă această interogare:

Private Sub AfisezFurnizori_Click()

DoCmd.OpenQuery ("FurnizoriMaterial")

End Sub

Observaţie: Dacă pe baza interogării FurnizoriMateriale s-ar fi realizat un raport sau un formular, se puteau utiliza pentru butonul de comandă una dintre metodele OpenForm sau OpenReport ale obiectului DoCmd.

Page 84: Studii de Caz Access 2007

Studii de caz

84

Studiu individual:

a) Să se realizeze un formualar cu subformular pentru actualizarea recepţiilor (formularul va avea ca sursă tabelul Receptie, iar subformularul, tabelul ContinutReceptie. b) Să se realizeze un formular cu subformular pentru a vizualiza pentru fiecare depozit lista recepţiilor în ordine cronologică.

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Să se afişeze o listă a recepţiilor dintr-un anumit an, grupate pe trimestre şi pe luni. Se vor afişa doar număr recepţie, data recepţie, număr depozit şi nume furnizor, calculându-se total recepţii la nivel de an. Pe fiecare trimestru se vor ordona recepţiile pe depozite şi, în cadrul fiecărui depozit se vor ordona invers cronologic.

Pentru realizarea raportului se va selecta meniul Create şi apoi se va apăsa butonul Report Wizzard. Etapele ce urmează a fi parcurse sunt prezentate în continuare:

1. În prima etapă se va configura sursa de date specificând câmpurile necesare din tabelele Recepţie şi respectiv Furnizor.

2. În a doua etapă, programul wizzard solicită gruparea după una dintre cele două surse de date specificate. Întrucât niciuna dintre alternativele propuse nu realizează gruparea pe trimestre se optează pentru alternativa by Receptie şi se apasă butonul Next.

Page 85: Studii de Caz Access 2007

Baze de date Access 2007

85

3. Se va adăuga DataReceptie de două ori în lista câmpurilor de grupare (o dată pentru gruparea la nivel de trimestru şi o dată pentru gruparea la nivel de lună).

Întrucât datele calendaristice sunt grupate în mod implicit pe luni, va fi necesar să se apese ulterior butonul Grouping Options… şi se va stabili gruparea pe trimestre în caseta Grouping Intervals… (figura alăturată).

4. Se stabileşte ordinea de sortare a datelor pe raport (după număr depozit şi descrescător după dată în cadrul fiecărui depozit)

5. Se precizează modul de dispunere a datelor în pagină.

Page 86: Studii de Caz Access 2007

Studii de caz

86

6. Se alege un stil pentru raport (acesta se referă la tipurile de fonturi, culoarea acestora, etc.) Proprietăţile pot fi modificate ulterior în modul Design.

7. Se stabileşte un nume pentru raport. Acesta va figura şi ca titlu al raportului, afişat pe prima pagină (în secţiunea Report Header)

Structura raportului, în modul Design, este următoarea:

Aşa cum s-a specificat în enunţ, se doreşte ca această situaţie trimestrială să fie tipărită doar pentru un anumit an.

Acest lucru se poate realiza parametrizând comanda SQL ce constituie sursa raportului (sursa raportului poate fi modificată în proprietatea Report Source – figura următoare)

Page 87: Studii de Caz Access 2007

Baze de date Access 2007

87

O altă soluţie pentru a restrânge recepţiile afişate pe raport la un anumit an calendaristic este utilizarea proprietăţilor Filter şi Filter On Load ale raportului:

Raportul în modul de vizualizare Print Preview este prezentat în figura următoare:

Page 88: Studii de Caz Access 2007

Studii de caz

88

Presupunând că se doreşte calcularea unui total general al numărului de recepţii pe anul specificat în momentul deschiderii raportului, se va adăuga o nouă casetă de tip TextBox în subsolul raportului (secţiunea Report Footer) şi se va completa proprietatea Control Source a casetei cu formula =Count(*)

Observaţie: În cazul în care se doresc subtotaluri pe luni sau pe trimestre, această casetă poate fi copiată în secţiunile de subsol ale grupărilor pe lună, respectiv trimestru.

Studiu individual:

Să se realizeze următoarele rapoarte: a) Lista recepţiilor pentru fiecare material pentru un interval de timp precizat prin specificarea a două date calendaristice de către utilizator. Se vor afişa pentru fiecare material şi cantitatea recepţionată la fiecare recepţie, calculându-se total recepţionat pe fiecare material. b) Situaţia angajărilor în firmă pe fiecare an, la fiecare depozit. Se va calcula vechimea fiecărui gestionar, exprimată în ani.

c) Lista recepţiilor din luna curentă pe furnizori. Se va calcula total recepţii de la fiecare furnizor.

Page 89: Studii de Caz Access 2007

Baze de date Access 2007

89

Bază de date pentru evidenţa poliţelor de asigurare, la o societate de profil

O societate de asigurări intenţionează să implementeze o bază de date pentru evidenţa poliţelor de asigurare. Clienţii societăţii pot fi persoane fizice sau juridice caracterizate de nume, prenume, dată naştere şi CNP, în cazul persoanelor fizice, respectiv denumire şi CUI, în cazul persoanelor juridice. Pentru fiecare client, indiferent de statutul său juridic, se atribuie un cod unic şi se reţin adresa, localitatea şi telefonul. Oferta firmei constă în mai multe tipuri de asigurări, pentru care se înregistrează codul, denumirea, riscurile acoperite, durata minimă şi cea maximă, valoarea minimă şi cea maximă, precum şi alte caracteristici. Pentru a evidenţia fiecare risc ce poate fi acoperit prin diverse tipuri de asigurari, se memorează codul riscului, denumirea şi o descriere asociată. Poliţele de asiguare încheiate de clienţii societăţii sunt înregistrate pe baza următoarelor elemente: număr poliţă, dată încheiere, dată început valabilitate, durată valabilitate (ca număr de luni), dată expirare, obiectul asigurării, tipul asigurării, valoarea asigurată şi titularul poliţei. La încheierea poliţei se întocmeşte un grafic al primelor de asigurare ce trebuie plătite în contul poliţei, consemnându-se: valoarea şi scadenţa fiecărei prime, poliţa aferentă, precum şi numărul primei, la nivelul poliţei asociate (cu alte cuvinte, pentru fiecare poliţă, vor exista primele 1, 2, 3 etc). Pentru evidenţa documentelor pe baza cărora societatea de asigurări realizează încasarea primelor, se reţin următoarele informaţii: numărul documentului (unic), tipul acestuia, data emiterii, primele încasate şi valoarea documentului.

Reguli de gestiune:

• Un tip de asigurare poate permite acoperirea mai multor tipuri de riscuri. De asemenea, acelaşi tip de risc poate face obiectul mai multor tipuri de asigurări.

• O poliţă are un singur titular şi vizează un singur tip de asigurare.

• O primă de asigurare corespunde unei singure poliţe, dar unei poliţe îi pot fi asociate mai multe prime.

• Pe baza aceluiaşi document pot fi încasate mai multe prime, însă nu se admit plăţi parţiale, fiecare primă fiind încasată integral, prin intermediul unui document unic. Fiecare document de încasare are un singur titular, clientul care efectueză plata primelor.

I. Realizaţi modelul relaţional al bazei de date şi implementaţi în MS Access Pe baza informaţiilor referitoare la activitatea societăţii de asigurări se poate constitui dicţionarul atributelor şi se pot deduce relaţiile dintre acestea. Ambele aspecte sunt redate sintetic prin intermediul matricei dependenţelor funcţionale, prezentată în continuare:

V

Page 90: Studii de Caz Access 2007

Studii de caz

90

Observaţii:

• Anterior realizării matricei au fost eliminate atributele derivate: DataExpirarePolita (se determină în funcţie de DataInceputValabilitate şi DurataValabilitate), ValoareDocumentIncasare (se calculează ca sumă a valorii primelor - ValoarePrima - încasate pe baza documentului).

• Pentru simplificare, pe primul rând al matricei au fost dispuse doar atributele sau perechile de atribute cu rol de determinant, în raport cu alte atribute.

• Dependenţele funcţionale au fost marcate cu simbolul 1, iar cele tranzitive cu 1t.

Page 91: Studii de Caz Access 2007

Baze de date Access 2007

91

Analiza matricei dependenţelor funcţionale conduce la următorul model relaţional al bazei de date:

TipAsigurare (CodAsigurare, DenumireAsigurare, DurataMinima, DurataMaxima, ValoareMinima, ValoareMaxima, AlteCaracteristici)

Risc (CodRisc, DenumireRisc, Descriere)

Client (CodClient, TipClient, Nume, Prenume, DataNastere, Cnp, Denumire, Cui, Adresa, Telefon)

PolitaAsigurare (NrPolita, DataPolita, CodAsigurare, CodClient, DataInceputValabilitate, ValoareAsigurata, ObiectAsigurare)

DocumentIncasare (NrDocumentIncasare, TipDocument, DataDocument, CodClient)

PrimaAsigurare (NrPolita, CodPrima, ValoarePrima, Scadenta, NrDocumentIncasare)

AsigurareRisc (CodAsigurare, CodRisc)

Observaţii:

• Întrucât codificarea primelor se realizează similar (1, 2, 3 etc.) în contextul fiecărei poliţe, rezultă că un astfel de cod nu poate juca rol de determinant în raport cu celelalte atributele asociate poliţelor. Deoarece fiecare cod este unic la nivelul unei poliţe date, se va apela la un determinant compus, constituit din atributele CodPrima şi NrPolita, care va deveni cheia primară a tabelei PolitaAsigurare. Totodată, în aceeaşi tabelă, NrPolita îndeplineşte şi rolul de cheie externă în raport cu cheia primară a tabelei PolitaAsigurare.

• Tabela AsigurareRisc este consecinţa dependenţelor multiple reciproce dintre atributele CodAsigurare şi CodRisc. În aceste condiţii, se impune constituirea unei tabele distincte, cu cheia primară compusă din ambele atribute, care, în mod individual, sunt chei externe în raport cu cheile primare din tabelele TipAsigurare şi Risc.

• În vederea realizării modelului relaţional au fost eliminate dependenţele tranzitive, astfel încât tabelele rezultate se află deja în forma normală 3 (FN3) şi pot face obiectul implementării.

Rezultatul implementării modelului relaţional în Microsoft Access 2007 este prezentat în figura următoare:

Page 92: Studii de Caz Access 2007

Studii de caz

92

Studiu individual:

La producerea unui risc acoperit de o poliţă valabilă, titularul poliţei sesizează societatea de asigurări, care urmează să evalueaze pagubele şi să decidă despăgubirile ce se impun. În acest scop, se întocmeşte un proces verbal care conţine următoarele elemente: numărul procesului verbal, data completării, numele expertului care l-a întocmit, poliţa (neexpirată) care stă la baza sa, concluziile şi procentul de despăgubire decis. Achitarea despăgubirilor se realizează prin intermediul unor documente de plată în care se consemnează: numărul (unic) şi tipul documentului, valoarea şi eventualele explicaţii. Nu se admit plăţi fracţionate, iar un document de plată vizează despăgubirile decise printr-un singur proces verbal. Adăugaţi modelului relaţional tabelul sau tabelele necesare pentru memorarea datelor privind despăgubirile acordate asiguraţilor.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) Valorile atributului TipClient trebuie limitate la “PF” (implicit) şi “PJ”; de asemenea nu se acceptă valoarea NULL.

Sunt vizate următoarele proprietăţi ale câmpului TipClient, din tabela Client:

- Default Value: “PF” - Required: Yes - Validation Rule: “PF” OR “PJ” - Validation Text: Valorile admise sunt PF (pentru persoanele fizice) şi PJ

pentru persoanele juridice)! O alternativă la regula de validare impusă prin proprietatea Validation Rule o constituie limitarea valorilor atributului TipClient prin intermediul unei liste derulante, care va oferi spre selecţie doar valorile admise. În acest caz, la introducerea

Page 93: Studii de Caz Access 2007

Baze de date Access 2007

93

datelor (în Datasheet View), zona aferentă câmpului TipClient, nu va mai fi afişată sub forma uzuală, a unei casete-text (TextBox), ci sub formă de casetă combinată (ComboBox). Pentru aceasta, este necesar ca la nivelul atributului TipClient să se seteze următoarele proprietăţi:

- Display Control: Combo Box - Row Source Type: Value List - Row Source: “PF”; “PJ” - Limit To List: Yes

II.b) Data de debut a valabilităţii unei poliţe nu poate fi anterioară datei de încheiere a poliţei. De asemenea, data încheierii unei poliţe nu poate fi ulterioară datei curente. Data curentă va fi utilizată ca valoare implicită pentru data de debut a perioadei de valabilitate a unei poliţe. În tabela PolitaAsigurare, la nivelul atributului DataPolita, vor fi specificate următoarele proprietăţi :

- Default Value: DATE() - Validation Rule: <= DATE() - Validation Text: Data încheierii a unei poliţe nu poate fi ulterioară datei

curente. Restricţia privind anterioritatea datei de început a valabilităţii unei poliţe faţă de data la care poliţa a fost încheiată, implică relaţia dintre valorile a două atribute ale tabelului PolitaAsigurare, prin urmare trebuie implementată prin intermediul unei reguli de validare definită la nivel de tabel:

- Table Properties / Validation Rule:

[DataPolita] <= [DataInceputValabilitate]

- Table Properties / Validation Text: Perioada de valabilitate a unei poliţe debutează după data înregistrării poliţei!

II.c) În funcţie de tipul clienţilor (persoane fizice sau juridice), se vor completa alternativ fie atributele Nume, Prenume, DataNastere şi Cnp (13 caractere numerice), fie Denumire şi Cui.

Şi în cazul acestei restricţii sunt implicate mai multe câmpuri ale aceleiaşi tabele (Client), impunându-se o soluţie similară celei prezentate anterior:

- Table Properties / Validation Rule: ([TipClient]="PJ" IMP (([Nume] IS NULL) AND ([Prenume] IS NULL) AND ([DataNastere] IS NULL) AND ([Cnp] IS NULL) AND ([Denumire] IS NOT NULL) AND ([Cui] IS NOT NULL))) AND ([TipClient]="PF" IMP (([Nume] IS NOT NULL) AND ([Prenume] IS NOT NULL) AND ([DataNastere] Is NOT NULL) AND ([Cnp] IS NOT NULL) AND ([Denumire] IS NULL) AND ([Cui] IS NULL)))

Page 94: Studii de Caz Access 2007

Studii de caz

94

- Table Properties / Validation Text: La introducerea datelor, se va tine cont de tipul clientilor!

Observaţie: Pentru a se putea face distincţia între valori (constante) text şi atribute, numele atributelor trebuie încadrate de paranteze drepte ([Nume], [Prenume] etc.), iar constantele de ghilimele (“PF”, “PJ”).

În plus, în cazul atributului Cnp (care trebuie să admită doar texte, compuse din 13 caractere numerice) se stabilesc următoarele proprietăţi:

- Data Type: Text

- Input Mask: 0000000000000 (0 indică un caracter numeric, obligatoriu)

Studiu individual:

a) Tipurile de documente care atestă încasarea contravalorii primelor de asiguare trebuie restricţionate la următoarele: chitanţă, ordin de plată, cec. Data emiterii unui document de plată nu poate fi ulterioară datei curente. b) Pentru fiecare tip de asigurare, durata minimă trebuie să fie inferioară duratei maxime, iar valoarea minimă nu o poate depăşi pe cea maximă. c) Durata maximă acoperită de fiecare tip de asigurare este de cel mult 4 ani.

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se identifice categoriile de riscuri acoperite prin tipuri de asigurări pentru care durata şi valoarea sunt fixe (predeterminate).

Observaţie: Având în vedere natura relaţiei dintre tabelele Risc şi AsigurareRisc – o categorie de riscuri poate fi asociată cu mai multe tipuri de asigurări), dar şi faptul că se urmăreşte obţinerea unei liste a riscurilor, nu şi a datelor privitoare la asigurări, este posibil ca la nivelul câmpurilor afişabile, anumite combinaţii CodRisc + DenumireRisc să apară în mod repetat. Din acest motiv, se va solicita ca din setul de rezultate returnat de interogare, să fie eliminte duplicatele (Query Properties / Unique Values: Yes).

Page 95: Studii de Caz Access 2007

Baze de date Access 2007

95

III.b) Să se obţină lista clienţilor persoane juridice, din Bucureşti şi Braşov, care deţin poliţe ce urmează să expire în următoarele 10 zile; va fi afişat şi numărul poliţei.

Observaţie: Data expirării unei poliţe poate fi deteminată cumulând durata de valabilitate (exprimată ca număr de luni, conform enunţului) la data care marcheza începutul perioadei de valabilitate şi deducând apoi o zi; spre exemplu, o poliţă cu valabilitatea de 1 an şi cu data de debut 5 mai 2009 expiră la 4 mai 2010 (aceasta este ultima zi de valabilitate). În cazul de faţă, pentru a determina data expirării, s-a utilizat funcţia calendaristică DATEADD (tip_unitate_timp, nr_unităţi_timp, debut_interval), care permite aflarea datei de sfârşit a unui interval pentru care se specifică data de început şi durata, exprimată prin numărul unităţilor de timp de un anumit tip, indicat sub forma unor constante text, predefinite (“d”- zile, “m” - luni, “yyyy” - ani etc.).

III.c) Să se determine valoarea totală a primelor încasate în numerar, la nivelul anului în curs, pe tipuri de asigurări.

Page 96: Studii de Caz Access 2007

Studii de caz

96

III.d) Să se decaleze cu 5 zile (în plus), scadenţele tuturor primelor neachitate, asociate poliţelor cu numerele 100, 101 şi 107.

Observaţie : Cererea este rezolvată prin intermediul unei introgări de acţiune, de actualizare (Update Query).

IV. Realizaţi interogări SQL pentru următoarele cerinţe: IV.a) Să se afişeze tipurile de asigurări solicitate de clienţii persoane juridice, în intevalul 15 ianuarie – 15 februarie 2009.

SELECT DISTINCT TipAsigurare.CodAsigurare, DenumireAsigurare FROM TipAsigurare INNER JOIN (PolitaAsigurare INNER JOIN Client ON PolitaAsigurare.CodClient = Client.CodClient) ON TipAsigurare.CodAsigurare = PolitaAsigurare.CodAsigurare WHERE TipClient ="PJ" AND DataPolita BETWEEN #15/01/2009# AND #15/02/2009#;

Observaţie: Datorită faptului că pentru acelaşi tip de asigurare pot exista mai multe poliţe, anumite combinaţii CodAsigurare + DenumireAsigurare pot apărea în mod repetat la nivelul setului de înregistrări returnat de interogare; pentru eliminarea duplicatelor la nivelul câmpurilor afişabile, s-a recurs la specificatorul DISTINCT.

IV.b) În cazul poliţelor cu durata de valabilitate mai mare de un an, să se afişeze primele restante şi să se calculeze valoarea penalităţilor aferente, prin aplicarea unui procent predefinit la valoarea primei: 2% pe zi, dacă întârzierea nu depăşeşte 30 zile şi 7% pe zi, în caz contrar. Înregistrările vor fi sortate descrescător, după numărul zilelor de întârziere.

SELECT PrimaAsigurare.*, ValoarePrima * IIF((DATE() - Scadenta) <= 30, 0.02, 0.07) * (DATE() - Scadenta) AS Penalitati FROM PolitaAsigurare INNER JOIN PrimaAsigurare ON PolitaAsigurare.NrPolita = PrimaAsigurare.CodPrima WHERE DurataValabilitate > 12 AND NrDocumentIncasare IS NULL AND DATE() > Scadenta ORDER BY Scadenta;

Page 97: Studii de Caz Access 2007

Baze de date Access 2007

97

Observaţie: Sortarea ascendentă, după scadenţă, produce un rezultat similar cu sortarea descendentă, după numărul zilelor de întârziere (cu cât scadenţa, depăşită deja, este mai îndepărtată în timp, cu atât numărul zilelor de întârziere este mai mare).

IV.c) Să se identifice tipurile de asigurări încheiate de clienţii persoane fizice, cu vârsta mai mică de 35 ani (la data încheierii poliţei).

SELECT DISTINCT TipAsigurare.* FROM Client INNER JOIN (PolitaAsigurare INNER JOIN TipAsigurare ON PolitaAsigurare.CodAsigurare = TipAsigurare.CodAsigurare) ON Client.CodClient = PolitaAsigurare.CodClient WHERE TipClient = "PF" AND DATEDIFF("yyyy", DataNastere, DataPolita) < 35;

Observaţie: Funcţia DATEDIFF(tip_unitate_timp, data1, data2) returnează diferenţa dintre două date, exprimată în numărul unităţilor de timp de un anumit tip (specificat prin intermediul aceloraşi constante text predefinite, ca şi în cazul funcţiei DATEADD).

IV.d) Să se determine numărul şi valoarea totală a poliţelor încheiate în semestrul 2 al anului anterior, pe tipuri de asigurări şi tipuri de clienţi. Înregistrările vor fi sortate în ordine descrescătoare, după valoarea poliţelor.

SELECT TipAsigurare.CodAsigurare, DenumireAsigurare, TipClient, SUM (ValoareAsigurata) AS [Valoare polite], COUNT(*) AS [Numar polite] FROM TipAsigurare INNER JOIN (PolitaAsigurare INNER JOIN Client ON PolitaAsigurare.CodClient = Client.CodClient) ON TipAsigurare.CodAsigurare = PolitaAsigurare.CodAsigurare WHERE YEAR(DataPolita) = YEAR(DATE()) -1 AND MONTH(DataPolita) > 6 GROUP BY TipAsigurare.CodAsigurare, DenumireAsigurare, TipClient ORDER BY SUM (ValoareAsigurata) DESC;

IV.e) Să se calculeze valoarea totală a primelor încasate în avans (înainte de scadenţă), la nivelul lunilor ianuarie, mai şi octombrie, în ultimii 3 ani; fiecare dintre lunile precizate vor fi afişate distinct, în ordine cronologică.

SELECT YEAR(DataDocument) AS An, MONTH(DataDocument) AS Luna, SUM(ValoarePrima) AS [Total incasari] FROM DocumentIncasare INNER JOIN PrimaAsigurare ON DocumentIncasare.NrDocumentIncasare = PrimaAsigurare.NrDocumentIncasare WHERE DataDocument < Scadenta AND YEAR(DataDocument) >= (YEAR(DATE())-3) AND MONTH(DataDocument) IN (1,5,10) GROUP BY YEAR(DataDocument), MONTH(DataDocument) ORDER BY 1, 2;

Page 98: Studii de Caz Access 2007

Studii de caz

98

Observaţie: Întrucât sunt reprezentate de câmpuri afişabile (an, lună), criteriile de sortare pot fi specificate atât prin intermediul expresiilor ce stau la baza lor (ORDER BY YEAR(DataDocument),MONTH(DataDocument)), cât şi prin indicarea poziţiilor pe care le ocupă în cadrul listei câmpurilor afişabile (ORDER BY 1, 2).

IV.f ) Să se realizeze un clasament al tipurilor de asigurări pentru care, în ultimile 3 săptămâni, au fost încheiate cel puţin 10 poliţe cu durata mai mare de 1 an; rezultatele vor fi sortate după numărul poliţelor, în ordine descrescătoare.

SELECT TipAsigurare.CodAsigurare, DenumireAsigurare, COUNT(*) AS [Numar polite] FROM TipAsigurare INNER JOIN PolitaAsigurare ON TipAsigurare.CodAsigurare = PolitaAsigurare.CodAsigurare WHERE DATEDIFF ("d", DataPolita, DATE()) <= 21 AND DurataValabilitate > 12 GROUP BY TipAsigurare.CodAsigurare, DenumireAsigurare HAVING COUNT(*) >= 10 ORDER BY COUNT(*) DESC;

IV.g) Să se identifice tipurile de asigurări care permit acoperirea celor mai multe riscuri.

SELECT TOP 1 TipAsigurare.CodAsigurare, DenumireAsigurare, COUNT(*) As [Nr Riscuri] FROM TipAsigurare INNER JOIN AsigurareRisc ON TipAsigurare.CodAsigurare = AsigurareRisc.CodAsigurare GROUP BY TipAsigurare.CodAsigurare, DenumireAsigurare ORDER BY 3 DESC;

Observaţie: Pentru ca specificatorul TOP 1 să returneze asigurările care acoperă numărul maxim de riscuri se impune sortarea descendentă, după valorile returnate de funcţia COUNT: ORDER BY COUNT(*) DESC, sau, ORDER BY 3 DESC.

IV.h) Să se identifice clienţii din Bucureşti, care nu mai deţin poliţe valabile, dar au acumulat debite din prime neachitate. Rezultatele obţinute în urma interogării vor fi stocate într-un nou tabel, numit Debite - Prime, cu următoarea structură: CodClient, Identitate client (numele şi prenumele, sau, după caz, denumirea), Total prime restante. Ulterior, în tabelul nou creat, vor fi adaugaţi şi debitorii din Braşov, care nu mai deţin poliţe valabile.

- Creare tabel: SELECT Client.CodClient, IIF(TipClient = "PF", Nume & " " & Prenume, Denumire) AS [Identitate client], SUM(ValoarePrima) AS [Total prime restante] INTO [Debite – Prime] FROM Client INNER JOIN (PolitaAsigurare INNER JOIN PrimaAsigurare ON PolitaAsigurare.NrPolita = PrimaAsigurare.NrPolita)

Page 99: Studii de Caz Access 2007

Baze de date Access 2007

99

ON Client.CodClient = PolitaAsigurare.CodClient WHERE DATEADD("m", DurataValabilitate, DataInceputValabilitate) >= DATE() AND NrDocumentIncasare IS NULL AND Adresa LIKE "*Bucuresti*" GROUP BY Client.CodClient, IIF(TipClient="PF", Nume & " " & Prenume, Denumire);

- Adăugare înregistrări: INSERT INTO [Debite – Prime] (CodClient, [Identitate client], [Total prime restante]) SELECT Client.CodClient, IIF(TipClient = "PF", Nume & " " & Prenume, Denumire), SUM(ValoarePrima) FROM Client INNER JOIN (PolitaAsigurare INNER JOIN PrimaAsigurare ON PolitaAsigurare.NrPolita = PrimaAsigurare.NrPolita) ON Client.CodClient = PolitaAsigurare.CodClient WHERE DATEADD("m", DurataValabilitate, DataInceputValabilitate) >= DATE() AND NrDocumentIncasare IS NULL AND Adresa LIKE "*Braşov*" GROUP BY Client.CodClient,IIF(TipClient="PF", Nume & " " & Prenume, Denumire);

IV.i) Pentru toate tipurile de asigurări care acoperă un număr minim de riscuri, precizat la execuţie, să se realizeze modificările următoare: dublarea duratei maxime a asigurării, reducerea cu 3% a valorii minime, respectiv majorarea cu 13% a valorii maxime.

Parameters [Introduceti numarul minim de riscuri] Integer; UPDATE TipAsigurare SET DurataMaxima = DurataMaxima * 2, ValoareMinima = ValoareMinima * 0.97, ValoareMaxima = ValoareMaxima * 1.13 WHERE CodAsigurare IN (SELECT CodAsigurare FROM AsigurareRisc GROUP BY CodAsigurare HAVING COUNT(CodAsigurare) > [Introduceti numarul minim de riscuri]);

IV.j) Să se renunţe la tipurile de asigurări cu valoarea, sau durata minimă, superioare mediei şi care nu au fost solicitate de nici un client.

DELETE * FROM TipAsigurare WHERE (ValoareMinima > (SELECT AVG(ValoareMinima) FROM TipAsigurare) OR DurataMinima > (SELECT AVG(DurataMinima) FROM TipAsigurare)) AND CodAsigurare <> ALL (SELECT CodAsigurare FROM PolitaAsigurare);

Page 100: Studii de Caz Access 2007

Studii de caz

100

Studiu individual:

a) Pentru un tip de asigurare indicat ca parametru, să se obţină situaţia primelor neachitate, scadente în următoarele 3 zile. b) Să se calculeze, pe tipuri de asigurări, valoarea totală a încasărilor din prime, la nivelul lunii curente. c) Să se determine durata medie de valabilitate şi valoarea medie a asigurărilor încheiate de clienţii persoane juridice din Braşov, Timişoara şi Constanţa, în anul precedent. d) Să se identifice riscurile care fac obiectul a cel puţin 5 tipuri de asigurări. e) În cazul poliţelor cu numerele 735 şi 773, să se modifice suma şi durata de valabilitate la valorile maxime posibile, conform tipului de asigurare aferent.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular pentru consultarea şi actualizarea datelor privitoare la tipurile de asigurări.

Având în verere că fiecare tip de asigurare este asociat cu una sau mai multe categorii de riscuri, pentru rezolvarea acestei cerinţe a fost creat un formular principal ce permite gestionarea tipurilor de asigurări, în cadrul căruia a fost plasat un subformular, pentru evidenţa riscurilor. Rezultatul este următorul:

Observaţii:

• Sursa de date (proprietatea Record Source) a formularului este reprezentată de tabela TipAsigurare, în timp ce subformularul are la bază următoarea cerere SQL: SELECT AsigurareRisc.CodRisc, DenumireRisc, Descriere, CodAsigurare FROM Risc INNER JOIN AsigurareRisc ON Risc.CodRisc = AsigurareRisc.CodRisc;

Page 101: Studii de Caz Access 2007

Baze de date Access 2007

101

• Sincronizarea dintre sursele de date ale celor două formulare este realizată pe baza atributului comun CodAsigurare. Drept urmare, în cadrul formularului principal, vor fi setate următoarele proprietăţi ale obiectului subformular RiscuriAcoperite:

- Link Master Fields: CodAsigurare - Link Child Fields: CodAsigurare

• Butoanele de comandă care permit deplasarea de la o înregistrare la alta, adăugarea sau ştergerea de înregistrări, precum şi anularea modificărilor efectuate asupra înregistrării curente, au fost realizate prin utilizarea asistentului (wizard) specializat, disponibil în MS Access 2007. Butonul de comandă pentru editarea înregistării curente (cmdEditeaza) determină, prin procedura ataşată evenimentului Click (pe care, din motive de spaţiu, nu o redăm aici), „comutarea” formularului din modul „consultare” în modul „editare”, inhibând sau activând, în mod alternativ, anumite controale, în funcţie de valoarea proprietaţii Enabled (True sau False): în modul „editare”, câmpurile formularului, ca şi butoanele pentru salvarea sau anularea modificărilor sunt active (Enabled = True), în timp ce butoanele pentru navigare, adăugare, ştergere, ca şi cmdEditeaza, sunt inactive (Enabled = False); desigur, situaţia se inversează în modul „consultare”, proprietatea Enabled a fiecărui control fiind setată la valoarea opusă celei din modul „editare”.

• Caseta combinată cboCodAsigurare permite regăsirea rapidă a datelor privitoare la tipul de asigurare al cărui cod a fost selectat. Proprietăţi:

- Control Source: “ ” (Unbound) - Row Source Type: Table/Query; - Row Source: SELECT CodAsigurare, DenumireAsigurare FROM TipAsigurare;

- Procedura asociată evenimentului AfterUpdate: Private Sub cboCodAsigurare_AfterUpdate()

'Este creata o copie a setului de inregistrari din tabelul-sursa al formularului

Dim rsAsigurari As Recordset Set rsAsigurari = Me.RecordsetClone 'Se avanseaza la inregistrarea ce contine codul asigurarii selectate

rsAsigurari.FindFirst ("[CodAsigurare]=" & Me.cboCodAsigurare.Value) Me.Bookmark = rsAsigurari.Bookmark

End Sub

• Butonul de comandă cmdSalveaza permite salvarea modificărilor aduse tipului de asigurare vizat de înregistrarea curentă, ţinînd-se seama de faptul că acesta trebuie să acopere cel puţin o categorie de riscuri şi că limitele de durată şi valoare trebuie să fie valide. Procedura asociată evenimentului Click este următoarea:

Page 102: Studii de Caz Access 2007

Studii de caz

102

Private Sub cmdSalveaza_Click()

On Error Resume Next Dim msg_eroare As String

If Me.DurataMaxima < Me.DurataMinima Then _ msg_eroare = "Durata Max. trebuie sa fie cel putin egala cu Min.!" & vbCrLf

If Me.ValoareMaxima < Me.ValoareMinima Then _

msg_eroare = msg_eroare & "Val. Max. trebuie sa fie macar egala cu Min.!" & vbCrLf 'Se verifica existenta inregistrarilor la nivelul subformularului RiscuriAcoperite

Dim rsRiscuri As Recordset

Set rsRiscuri = Me.RiscuriAcoperite.Form.Recordset

If rsRiscuri.RecordCount = 0 Then _ msg_eroare = msg_eroare & "Nu ati mentionat nici o categorie de riscuri!" & vbCrLf

If msg_eroare <> "" Then MsgBox msg_eroare & "Inregistrarea nu a fost salvata!", vbCritical

Else DoCmd.RunCommand acCmdSaveRecord ' In caseta combinata cboCodAsigurare sunt actualizate datele privitoare la asigurari

Me.cboCodAsigurare.Requery

MsgBox "Inregistrarea a fost salvata!", vbInformation End If

End Sub

V.b) Realizaţi un formular pentru consultarea şi actualizarea datelor privind poliţele de asigurare.

Deoarece poliţele de asigurare trebuie corelate, din punctul de vedere al duratei şi sumei, cu valorile specifice categoriei de asigurări de care aparţin şi pentru că gestiunea poliţelor implică şi gestiunea primelor aferente, s-a optat pentru realizarea unui formular cu următoarea structură:

Page 103: Studii de Caz Access 2007

Baze de date Access 2007

103

După cum se poate observa, formularul include un subformular (numit Prime) care permite evidenţa primelor de asigurare şi a documentelor de plată utilizate pentru achitarea acestora. Câteva precizări privind soluţia prezentată:

- Sursa de date (proprietatea Record Source) a formularului principal este reprezentată de următoarea cerere SQL:

SELECT NrPolita, DataPolita, PolitaAsigurare.CodAsigurare, PolitaAsigurare.CodClient, DataInceputValabilitate, DurataValabilitate, ValoareAsigurata, ObiectAsigurare, DenumireAsigurare, DurataMinima, DurataMaxima, ValoareMinima, ValoareMaxima, TipClient, DATEADD("m", DurataValabilitate, DataInceputValabilitate) -1 AS DataExpirare, IIF(TipClient = "PF", Nume & " " & Prenume, Denumire) AS NumeClient FROM TipAsigurare INNER JOIN (Client INNER JOIN PolitaAsigurare ON Client.CodClient = PolitaAsigurare.CodClient) ON TipAsigurare.CodAsigurare = PolitaAsigurare.CodAsigurare;

• În cazul subformularului, valoarea proprietăţii Record Source este reprezentată de tabela PrimaAsigurare.

• Sincronizarea dintre cele sursele de date ale celor două formulare este realizată pe baza atributului comun NrPolita. Drept urmare, în cadrul formularului principal, vor fi setate următoarele proprietăţi ale obiectului subformular Prime:

- Link Master Fields: NrPolita - Link Child Fields: NrPolita

• După cum se poate observa, codul tipului de asigurare aferent poliţei este selectat din lista de valori a unui control ComboBox, cu următoarele proprietăţi:

- Control Source: CodAsigurare - Row Source Type: Table/Query - Row Source:

SELECT CodAsigurare, DenumireAsigurare FROM TipAsigurare;

• De asemenea, codul clientului titular al poliţei este selectat din lista de valori a unui alt control ComboBox, cu următoarele proprietăţi:

- Control Source: CodClient - Row Source Type: Table/Query - Row Source:

SELECT CodClient, TipClient, Nume, Prenume, Denumire FROM Client;

• Datorită faptului că formularul are ca sursă o interogare, odată cu selectarea unui cod de client, se actualizează în mod automat conţinutul câmpurilor TipClient şi NumeClient. De asemenea, la selectarea codului aferent unui tip de asigurare, se actualizează conţinutul tuturor câmpurilor care depind de acesta (DenumireAsigurare, DurataMinima, DurataMaxima, ValoareMinima, ValoareMaxima). Din acest motiv, toate controalele ce au ca sursă câmpurile amintite (proprietatea Control Source) au fost dezactivate, servind doar la afişarea

Page 104: Studii de Caz Access 2007

Studii de caz

104

datelor, nu şi la editarea acestora (proprietatea Enabled = False). Un tratament similar a fost aplicat şi controlului ce are ca sursă câmpul DataExpirare, valoarea sa fiind calculată în mod automat, în funcţie de DurataValabilitate şi DataInceputValabilitate. În plus, atunci când asigurarea selectată are valoarea şi/sau durata predeterminate, câmpurile ValoareAsigurata şi DurataValabilitate sunt dezactivate şi completate în mod automat, după cum se poate observa din procedura asociată evenimentului AfterUpdate al controlului ComboBox ce oferă lista tipurilor de asigurări:

Private Sub CodAsigurare_AfterUpdate() If Me.DurataMaxima = Me.DurataMinima Then

Me.DurataValabilitate = Me.DurataMaxima Me.DurataValabilitate.Enabled = False

Else Me.DurataValabilitate.Enabled = True

End If If Me.ValoareMaxima = Me.ValoareMinima Then

Me.ValoareAsigurata = Me.ValoareMaxima Me.ValoareAsigurata.Enabled = False

Else

Me.ValoareAsigurata.Enabled = True

End If End Sub

• Butoanele de comandă au fost realizate prin utilizarea asistentului (wizard) specializat disponibil în MS Access 2007 şi, exceptând butonul cmdSalveaza, au funcţii similare celor descrise în cazul cerinţei precedente.

• Butonul de comandă cmdSalveaza permite salvarea modificărilor aduse poliţei curente, luând în calcul corelaţia dintre durata de valabiliate şi valoarea poliţei, pe de-o parte, şi limitele de durată şi valoare, determinate de tipul asigurării, pe de altă parte. De asemenea, pentru a fi validă, o poliţă trebuie asociată cu primele de asigurare ce trebuie achitate în contul său. În continuare este redată procedura asociată evenimentului Click:

Private Sub cmdSalveaza_Click() On Error Resume Next Dim msg_eroare As String

If Me.DataInceputValabilitate < Me.DataPolita Then _

msg_eroare = "Data debut valabil. trebuie sa fie ulterioara datei politei!" & vbCrLf

If (Me.ValoareAsigurata < Me.ValoareMinima) Or _ (Me.ValoareAsigurata > Me.ValoareMaxima) Then _

msg_eroare = msg_eroare & "Valoarea politei depaseste limitele admise!" & vbCrLf If (Me.DurataValabilitate < Me.DurataMinima) Or _

Page 105: Studii de Caz Access 2007

Baze de date Access 2007

105

(Me.DurataValabilitate > Me.DurataMaxima) Then _

msg_eroare = msg_eroare & "Durata valabil.depaseste limitele admise!" & vbCrLf 'Se verifica existenta inregistrarilor la nivelul subformularului Prime

If Me.Prime.Form.Recordset.RecordCount = 0 Then _

msg_eroare = msg_eroare & "Nu au fost inregistrate prime de asigurare!" & vbCrLf If msg_eroare <> "" Then

MsgBox msg_eroare & "Inregistrarea nu a fost salvata!", vbCritical Else

DoCmd.RunCommand acCmdSaveRecord MsgBox "Inregistrarea a fost salvata!", vbInformation

End If

End Sub • La nivelul subformularului, la adăugarea unei noi prime pentru poliţa afişată la

nivelul formularului principal, codul primei este atribuit în mod automat, pe baza numărului înregistrării curente. Astfel, în cazul fiecărei poliţe, primele vor fi codificate în mod automat sub forma: 1, 2, 3 etc:

Private Sub Form_Current()

If Me.NewRecord Then Me.CodPrima = Me.CurrentRecord

End Sub

• De asemenea, tot la nivelul subformularului, la adăugarea sau modificarea primelor de asigurare, se verifică dacă acestea sunt introduse în ordine cronologică şi dacă scadenţele lor se încadrează în intervalul de valabilitate al poliţei de care aparţin:

Private Sub Form_BeforeUpdate(Cancel As Integer) Dim msg_eroare As String If (Me.Scadenta < Me.Parent.Form!DataInceputValabilitate) Or _

(Me.Scadenta > CDate(Me.Parent.Form!DataExpirare.Value)) Then _

msg_eroare = "Data excede perioada de valabilitate a politei!" & vbCrLf ‘ Daca nu ne aflam la prima inregistrare, se cauta scadenta primei anterioare

Dim sir_scadenta As String

sir_scadenta = "CodPrima=" & Me.CurrentRecord - 1 & " And NrPolita=" & Me.NrPolita If Me.CurrentRecord > 1 Then

If DLookup("[Scadenta]", "PrimaAsigurare", sir_scadenta) >= Me.Scadenta Then _ msg_eroare = msg_eroare & "Primele se introduc in ordine cronologica!"

End If

If msg_eroare <> "" Then

MsgBox msg_eroare, vbCritical ‘ Se anuleaza operatia de salvare a inregistrarii curente

Cancel = True

End If End Sub

Page 106: Studii de Caz Access 2007

Studii de caz

106

Studiu individual:

Să se realizeze formularele (şi eventualele subformulare asociate acestora) care îndeplinesc următoarele funcţii: a) Consultarea şi actualizarea tabelei Client; b) Înregistarea documentelor de încasare aferente primelor de asigurare.

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Să se obţină situaţia încasărilor din prime de asigurare la nivelul unui an, respectiv al unei categorii de clienţi, care urmează să fie precizate la deschiderea raportului. Datele vor fi prezentate grupat, la nivelul de poliţelor individuale, precum şi al categoriilor de asigurări de care acestea aparţin, determinându-se totalul încasărilor pentru fiecare din nivelurile indicate.

Întrucât datele necesare obţinerii unei astfel de situaţii trebuie extrase din mai multe tabele, sursa raportului (proprietatea Record Source) este reprezentată de o interogare, al cărei cod SQL este următorul:

SELECT TipAsigurare.CodAsigurare, DenumireAsigurare, PolitaAsigurare.NrPolita, PrimaAsigurare.CodPrima, PolitaAsigurare.CodClient, TipClient, IIF(TipClient = "PF", Nume & " " & Prenume, Denumire) AS TitularPolita, PrimaAsigurare.NrDocumentIncasare, TipDocument, DataDocument, IIF(Scadenta < DataDocument, ValoarePrima, 0) AS PrimeRestante, ValoarePrima, Scadenta FROM TipAsigurare INNER JOIN ((Client INNER JOIN PolitaAsigurare ON Client.CodClient = PolitaAsigurare.CodClient) INNER JOIN (DocumentIncasare INNER JOIN PrimaAsigurare ON DocumentIncasare.NrDocumentIncasare = PrimaAsigurare.NrDocumentIncasare) ON PolitaAsigurare.NrPolita = PrimaAsigurare.NrPolita) ON TipAsigurare.CodAsigurare = PolitaAsigurare.CodAsigurare WHERE YEAR(DataDocument)= IIF(ISNULL([Specificati anul]), YEAR (DataDocument),[Specificati anul]) AND TipClient= IIF(ISNULL([Specificati tipul clientilor]),TipClient,[Specificati tipul clientilor]);

Structura raportului, după cum se prezintă în modul Design, este prezentată în figura de pe pagina următoare.

Page 107: Studii de Caz Access 2007

Baze de date Access 2007

107

Observaţii:

• Informaţiile de detaliu, privitoare la documentele de încasare şi primele pe care aceste le achită, sunt plasate în secţiunea Detail, gruparea acestora în vederea prezentării şi centralizării fiind realizată după criteriile menţionate în cerinţă: numărul poliţei de care aparţin, şi codul tipului de asigurare asociat poliţei. Expresiile care returnează valoarea totală a încasărilor sunt incluse în subsolul fiecărui grup şi în cel al raportului, valorile returnate având semnificaţii diferite, în funcţie de nivelul pe care ne plasăm: 1.total aferent unei anumite poliţe, 2. total calculat pentru toate poliţele de un anumit tip, 3. total general, pentru toate tipurile de asigurări, la nivel de raport.

• În secţiunea Report Header, în expresiile ce reprezintă sursele de date ale casetelor text aferente anului (txtAn) şi categoriei de clienţi (txtTipClient), au fost utilizaţi parametrii din interogarea ce stă la baza raportului, astfel încât, dacă au fost specificate, criteriile de filtrare a înregistrărilor vor fi afişate în antetul raportului. Astfel, în cazul celor două controale, valorile proprietăţii Control Source au fost setate după cum urmează:

- pentru txtAn: = IIF(ISNULL([Specificati anul]), "" , "Anul: " & [Specificati anul]) - pentru txtTipClient: = IIF(ISNULL([Specificati tipul clientilor]), "" ,

IIF([Specificati tipul clientilor] = "PF", "Tip clienti: Persoane fizice", IIF([Specificati tipul clientilor]="PJ", "Tip clienti: Persoane juridice","")))

La deschiderea raportului, după cum sunt, sau nu, furnizate valori pentru cei doi parametrii, anul şi/sau tipul clienţilor vor fi, sau nu, folosite drept criterii de filtrare a înregistrărilor ce constituie sursa de date a raportului. Spre exemplu, figura următoare prezintă conţinutul raportului în cazul în care se solicită situaţia încasărilor aferente persoanelor juridice, în 2009.

Page 108: Studii de Caz Access 2007

Studii de caz

108

VI.b) Să se afişeze poliţele de asigurare încheiate în anul curent, determinând, la nivelul fiecărui tip de asigurare, valoarea totală şi cea medie a poliţelor, respectiv durata medie a perioadei de asigurare.

Pentru rezolvarea acestei cerinţe se poate realiza un raport unic, bazat pe o interogare ce extrage toate datele necesare din tabelele în care acestea se află, sau se poate recurge la o soluţie ce implică utilizarea subrapoartelor, după cum reiese din figura următoare:

Observaţii:

• Sursa de date (proprietatea Record Source) a raportului principal este reprezentată de tabelul TipAsigurare, iar cea a subraportului Poliţe1, de următoarea cerere SQL:

Page 109: Studii de Caz Access 2007

Baze de date Access 2007

109

SELECT PolitaAsigurare.*, IIF(TipClient="PF", Nume & " " & Prenume, Denumire) AS Titular FROM Client INNER JOIN PolitaAsigurare ON Client.CodClient = PolitaAsigurare.CodClient WHERE YEAR(DataPolita) = YEAR(DATE());

• Sincronizarea dintre sursa de date a raportului principal şi cea subraportului Polite1 este realizată pe baza atributului comun CodAsigurare. Drept urmare, în cadrul raportului principal, vor fi setate următoarele proprietăţi ale obiectului subraport:

- Link Master Fields: CodAsigurare - Link Child Fields: CodAsigurare

• În cadrul subraportului a fost inclusă o casetă-text ce permite afişarea numărului înregistrării curente la nivelul sursei de date a subraportului, astfel că fiecărei poliţe i se va ataşa un număr de ordine (1,2,3...).

• În secţiunea Detail a raportului principal au fost plasate informaţiile referitoare la tipurile de asigurări, precum şi subraportul Poliţe1, ce conţine datele de detaliu şi totalurile aferente poliţelor propriu-zise. Întrucât datele subraportului sunt corelate cu cele din raportul principal, reiese că poliţele vor fi prezentate în mod grupat, iar valorile agregate calculate la nivelul subraportului vor corespunde unui anumit tip de asigurare, de la nivelul raportului.

• Agregarea la nivel general, de raport, a datelor privind poliţele, nu este posibilă întrucât atributele ale căror valori fac obiectul centralizării nu sunt disponibile la nivelul raportului principal, ci doar al subraportului Poliţe1. În plus, funcţiile de grup, precum SUM, COUNT, AVG, MIN etc. nu admit ca argumente nume de controale, pentru a fi posibilă agregarea valorilor disponibile în subraportul Polite1. Pentru a putea totuşi afişa totalurile la nivelul raportului principal, în subsolul acestuia a fost plasat un al doilea subraport, Polite2, a cărui unică menire este să furnizeze totalurile pentru ansamblul poliţelor. Sursa de date (proprietatea Record Source) a acestui subraport este reprezentată de următoarea interogare, ce returnează poliţele încheiate la nivelul anului curent (conform cerinţei): SELECT PolitaAsigurare.* FROM PolitaAsigurare WHERE YEAR(DataPolita)=YEAR(DATE());

Întrucât nu interesează datele de detaliu, aferente poliţelor individuale, ci doar valorile centralizate, singura secţiune afişabilă a subraportului Poliţe2 este Report Footer; aici au fost plasate casetele-text asociate, prin proprietarea Control Source, cu expresiile ce permit centralizări la nivelul sursei de date, în ansamblul său. În plus, având în vedere rolul şi amplasarea subraportului Poliţe2 în cadrul raportului principal (secţiunea Report Footer), între cele două rapoarte nu trebuie şi nici nu poate fi stabilită nici o corelaţie; cu alte cuvinte, în cazul acestui subraport nu vor fi setate proprietăţile Link Master Field şi Link Child Field.

Page 110: Studii de Caz Access 2007

Studii de caz

110

Figura următoare redă modul în care este afişat raportul atunci când este deschis în vederea consultării.

Studiu individual:

Să se realizeze rapoartele (şi eventualele subrapoarte asociate acestora) care permit afişarea următoarelor informaţii: a) Poliţele aferente unui anumit tip de asigurare, specificat la deschiderea raportului; datele vor fi organizate pe ani şi pe categorii de titulari (persoane fizice şi juridice). b) Primele restante aferente poliţelor expirate, cu determinarea duratei efective a întârzierii (pentru fiecare primă în parte), respectiv a duratei medii a întârzierii (la nivel de poliţă, tip de asigurare şi pe ansamblu).

Page 111: Studii de Caz Access 2007

Baze de date Access 2007

111

Bază de date pentru evidenţa operaţiunilor efectuate prin casierie

Firma Specialistul SRL are ca obiect de activitate realizarea de cursuri de pregătire şi perfecţionare în domeniul limbilor străine. Se doreţte realizarea unei baze de date pentru evidenţa operaţiilor realizate în lei în cadrul casieriei.

Zilnic se va realiza registrul de casă ce va conţine data realizării operaţiei, explicaţia operaţiei, suma operaţiei şi tipul operaţiei (încasare sau plată) precum şi numărul şi tipul documentului (cec de numerar, chitanţa, foaie de vărsământ, dispoziţie de plata sau încasare, state de salarii, etc.). Registrul de casă va conţine soldul iniţial al zilei, totalul sumelor încasate, totalul sumelor plătite precum şi soldul final al zilei. Fiecare operaţie înregistrată în baza de date va primi un număr unic folosit la identificare.

Încasările pot să provină din vânzarea de serviciilor proprii (taxele cursanţilor ce participă la cursurile de limbi străine) sau ridicări de numerar de la bancă, aport de capital. Plăţile se pot face pentru achitarea drepturilor salariale, avansuri spre decontare, cumpărări de bunuri, depuneri de numerar la bancă. Operaţiile sunt grupate pe categorii în funcţie de sursa acestora, reţinându-se pentru fiecare operaţie codul categoriei, denumirea acesteia şi tipul. Principalele categoriile de operaţii sunt taxa curanţi, ridicare numerar banca, aport capital, achitare drepturi salariale, avans spre decontare, cumpărare bunuri, depunere de numerar la bancă la care pot fi adăugate ulterior (in timpul exploatării bazei de date) ţi alte plăţi sau încasări.

O categorie specială de operaţii o reprezintă avansurile spre decontare. Acestea trebuie sa fie justificate prin intermediul unor documente în cadrul deconturilor de cheltuieli. Pentru fiecare decont de cheltuieli este necesară reţinerea numărului şi datei acestuia, a documentelor (număr, data, suma, tip) ce justifică cheltuirea avansului precum şi a datelor titularului avansului. Pot să beneficieze de avansuri spre decontare salariaţii firmei. Datele fiecărui salariat (nume, data naţtere, adresă) vor fi înregistrate în cadrul bazei de date o singură dată, acesta fiind identificat cu ajutorul mărcii. Avansul neutilizat este restituit la casierie pe baza documentului de încasare. Documentele justificate pentru avansuri se vor scana şi se vor arhiva.

Reguli de gestiune:

• O operaţie este încadrată într-o singură categorie, dintr-o categorie putând face parte mai multe operaţii.

• Un decont poate presupune mai multe operaţii prin casierie (ridicare avans şi posibile diferenţe), o operaţie ce poate presupune ridicarea unui avans sau restituirea diferenţelor este înregistrată pe un singur decont.

• Un decont de cheltuieli poate să conţină mai multe documente justificativ, un document poate justifica cheltuielile de pe un singur decont.

• Un salariat poate avea mai multe deconturi, un decont aparţinând unui singur angajat.

VI

Page 112: Studii de Caz Access 2007

Studii de caz

112

I. Realizaţi modelul realizaţi al bazei de date şi implementaţi în MS Access Realizarea modelului relaţional al bazei de date presupune parcurgerea mai multor etape. Plecând de la informaţiile de bază respectiv atributele, pe baza relaţiilor stabilite între acestea (dependenţe funcţionale) se realizează succesiv formele normalizate ale bazei de date (FN1, FN2, FN3). Trebuie stabilite în primul rând atributele elementare şi nerepetitive ce vor constitui baza procesului de normalizare. Deoarece baza de date va fi realizată cu ajutorul ACCESS 2007 se vor folosi noile funcţionalităţi ale acestuia şi se va defini un câmp denumit FisierDocument în care se va reţine fiţierul ce conţine copia documentului justificativ. Pe baza analizei cerinţelor funcţionale ale bazei de date se identifică următorul dicţionar preliminar al datelor:

NrOperatie, DataOperatiei, ExplicatieOperatie, SumaOperatie, TipOperatie, NrDocument, TipDocument, CodCategorie, DenCategorie, TipCategorie, NrDecont, DataDecont, NrDocJustificativAvans, DataDocJustificativAvans, SumaDocJustificativAvans, TipDocJustificativAvans, NumeSalariat, MarcaSalariat, DataNastereSalariat, AdresaSalariat, FisierDocument, TotalIncasariZilnice, TotalPlatiZilnice, SoldFinalZilnic, SoldIinitialZilnic.

Prin respectarea cerinţelor impuse de către FN1, din dicţionarul atributelor se vor elimina atributele calculate:

• TotalIncasariZilnice deoarece se calculează prin însumarea sumelor încasate zilnic

• TotalPlatiZilnice obţinută prin însumarea sumelor plăţilor zilnice • SoldFinalZilnic obţinută prin diferenţa încasărilor şi a plaţilor zilnice la care se

adăugă soldul iniţial. • SoldInitialZilnic fiind de fapt soldul final al zilei precedente. • TipOperatie are aceleaţi valori ca şi TipCategorie respectiv încasare sau plată. S-a

optat pentru eliminarea atributului TipOperatie deoarece operaţia este inclusă într-o categorie, tipul ei fiind acelaţi cu cel al categoriei din care face parte.

Respectând cerinţele impuse cheilor primare (unicitate, ireductibilitate) se identifică în cadrul dicţionarul atributelor următoarele atribute candidat:

Atribut Candidat Descriere

NrOperatie Acest atribut are valori unice, identificând în mod unic o operaţie.

NrDecont Fiecare decont este numerotat în mod unic.

CodCategorie Acest atribut are valori unice, identificând în mod unic o categorie de operaţii.

NrDocJustificativ, TipDocJustificativ

Pot exista mai multe tipuri de documente justificative, numerele fiind unice în cadrul acestor tipuri.

MarcaSalariat Reprezintă atributul pe baza căruia este identificat un salariat

Page 113: Studii de Caz Access 2007

Baze de date Access 2007

113

Următoarea etapă în cadrul normalizării o reprezintă identificarea dependenţelor funcţionale. Este recomandat ca din mulţimea dependenţelor funcţionale să se reţină doar cele în care determinatul este cheie primară.

La înregistrarea unei operaţii i se atribuie un număr unic existând dependenţe funcţionale între atributul NrOperatie şi atributele ExplicatieOperatie, SumaOperatie, NrDocument, TipDocument. Deoarece o operaţie este încadrată într-o singură categorie, există dependenţe funcţionale între atributul NrOperatie şi atributele CodCategorie, DenCategorie, TipCategorie. O operaţie este înregistrată doar pe un singur decont, existând dependenţe funcţionale între atributul NrOperatie şi atributele NrDecont, DataDecont.

O operaţie de tipul acordare avans sau restituire diferenţe se realizează pentru singur salariat existând o dependenţă funcţională între atributul NrOperatie şi atributul MarcaSalariat ţi dependenţe funcţionale tranzitive între atributul NrOperatie ţi atributele NumeSalariat, DataNastereSalariat, AdresaSalariat.

Fiecare decont este numerotat în mod unic, atributul NrDecont implicând funcţional atributul DataDecont . Pentru că un decont aparţine unui singur angajat există dependenţe funcţionale între atributul NrDecont şi atributele NumeSalariat, MarcaSalariat, NumeSalariat, DataNastereSalariat, AdresaSalariat.

Un document poate justifica cheltuielile de pe un singur decont, acest lucru generând dependenţe funcţionale totale între grupul de atribute NrDocJustificativ, TipDocJustificativ şi atributele NrDecont, DataDecont. Pentru fiecare document trebuie memorate data, suma şi fiţierul ce conţine arhiva electronică existând dependenţe funcţionale totale între grupul de atribute NrDocJustificativ, TipDocJustificativ şi atributele DataDocJustificativ, SumaDocJustificativ, FisierDocument.

Figura următoare ilustrează dependenţele funcţionale:

Page 114: Studii de Caz Access 2007

Studii de caz

114

Pentru simplificare în scop didactic s-au reprezentat în cadrul matricei dependenţelor funcţionale doar dependenţele funcţionale totale şi dependenţele funcţionale tranzitive în care determinatul este cheie primară, nereprezentându-se dependenţele funcţionale multivaloare sau cele parţiale.

Analizând dependenţele funcţionale se observă existenţa dependenţelor funcţionale tranzitive. Prin eliminarea acestora se obţin tabelele ce respectă forma normală trei.

Categorie (CodCategorie, DenCategorie, TipCategorie)

Salariat (MarcaSalariat, NumeSalariat, AdresaSalariat, DataNastereSalariat)

Decont (NrDecont, DataDecont, MarcaSalariat)

Operatie (NrOperatie, DataOperatiei, SumaOperatie, ExplicatieOperatie, NrDocument, TipDocument, NrDecont, CodCategorie)

DosumentJustificativ (NrDocJustificativ, TipDocJustificativ, DataDocJustificativ, SumaDocJustificativ, NrDecont, FisierDocument)

Implementarea în ACCESS 2007 a tabelelor şi a relaţiilor dintre acestea este prezentată în figura următoare:

Page 115: Studii de Caz Access 2007

Baze de date Access 2007

115

Studiu individual:

Se doreţte extinderea activităţii firmei, operaţie ce necesită realizarea operaţiunilor prin casierie şi în valută. Evidenţa operativă a numerarului în devize se ţine cu ajutorul “Registrul de casă” care va avea coloane atât pentru încasări, plăţi, sold în lei, cât şi pentru asemenea operaţii în devize. Pentru fiecare fel de valută se realizează câte un registru de casă. Este important să se reţină în baza de date codul, denumirea

valutei şi cursul de schimb pentru fiecare operaţie. O operaţie se face într-o singură valută la un singur curs de schimb, într-o anumită valută putând să se realizeze mai multe operaţii. Adăugaţi modelului relaţional tabelul sau tabelele necesare pentru a permite memorarea datelor privind valuta şi cursul de schimb aferent operaţiilor din casierie.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi:

II.a) Tipul categoriei va putea să aibă doar două valori „încasare” sau „plată”, valori ce se vor alege dintr-o listă derulantă.

Pentru realizarea listei derulante ce va conţine valorile încasare şi plata se va folosi proprietatea Lookup Wizard a câmpului TipCategorie din tabelul Categorie. În cadrul ferestrei Lookup Wizard se va alege opţiunea „I will type in the values that I want”, iar în cadrul etapelor ulterioare se introduc valorile Încasare şi Plată.

II.b) Suma operaţiei va avea valori cuprinse între 0 şi 1000.

Pentru a restricţiona valorile câmpului suma operaţie se va folosi proprietatea Validation Rule asociată acestui câmp din tabelul Operatie. Realizarea acestei restricţiei referitoare la domeniul de valori acceptate de atributul SumaOperatie

Page 116: Studii de Caz Access 2007

Studii de caz

116

presupune atribuirea valorii ”between 0 and 1000” proprietăţii Validation Rule. Proprietatea Validation Text va conţine mesajul personalizat de eroare afiţat în cazul nerespectării condiţiei impusă prin Validation Rule.

II.c) Angajaţii vor fi codificaţi în funcţie de departamentul unde lucrează. Marca angajatului va fi alcătuită din 5 caractere primele 2 fiind codul compartimentului, iar ultimele trei reprezintă numărul angajatului în cadrul departamentului. De exemplu angajatul cu marca CO005 lucrează în departamentul contabilitate. Să se realizeze un şablon de introducere a mărcii angajatului în acest format.

Realizarea unui şablon de introducere a mărcii angajatului formatul dorit (două caractere obligatorii alfabetice urmate de trei caractere obligatoriu numerice) se realizează cu ajutorul proprietăţii Input Mask. Pentru caractere obligatorii alfabetice se foloseţte simbolul „L”, iar pentru cele numerice obligatorii se foloseţte caracterul „0”.

Valorile câmpului SumaOperatie trebuie să fie

cuprinse între 0 şi 1000.

Realizarea formatului de introducere

a mărcii angajatului.

Studiu individual:

a) Tipul documentului va putea să ia valorile DP, DI, C, FV, StatSalarii ce se vor alege dintr-o listă derulantă. b) Valoarea implicită pentru data operaţiei să fie data curentă.

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afiţeze în coloane distincte sumele încasate şi cele restituite pentru fiecare din operaţiile din categoriile "Avansuri spre decontare" ţi "Retur avans spre decontare".

Se va folosi funcţia IIF pentru a afiţa sumele încasate (acelea pentru care tipul operaţiei este încasare) şi sumele plătite (acelea pentru care tipul operaţiei este plată). În cadrul secţiunii Criteria pentru câmpul DenumireCategorie se vor introduce cele

Page 117: Studii de Caz Access 2007

Baze de date Access 2007

117

două condiţii "Avansuri spre decontare", "Retur avans spre decontare" folosind operatorul OR.

III.b) Să se afiţeze angajaţii care în lunile ianuarie, februarie şi martie ale anului 2007 au justificat sume totale mai mari de 200 Ron pe mai puţin de 2 deconturi.

Pentru condiţia impusă datei decontului s-a folosit operatorul BETWEEN. Datele calendaristice sunt marcate cu ajutorul caracterului “#”.

III.c) Să se afiţeze sumele totale aferente operaţiilor desfăţurate în anul 2007 grupate pe luni şi categorii. Se va folosi o interogare de tipul analiză încruciţată (Crosstab Query). Pentru afiţarea în rezultatul cererii a tuturor lunilor anului 2007 numerotate de la 1 la 12 se va folosi proprietatea Column Headings asociată obiectului de tip interogare ( Query). Funcţia MONTH se foloseţte pentru extragerea lunii din data operaţiei. Prin concatenarea tipului şi denumirii categoriei folosind operatorul „&”se obţin valorile unui nou câmp ce va avea eticheta „Operaţie”.

Page 118: Studii de Caz Access 2007

Studii de caz

118

III.d) Să se afiţeze soldurile iniţiale pentru o anumita zi introdusă ca parametru.

Soldul iniţial al unei zile se calculează prin însumarea încasărilor din care se scad totalul plaţilor pentru perioada precedentă zilei introduse ca parametru. Totalul sumelor încasate se calculează folosind funcţia agregată SUM şi funcţia IIF astfel

SUM(IIF([TipCategorie]="Incasare";[SumaOperatie];0)). În mod asemănător se calculează şi totalul sumelor plătite.

Studiu individual:

a) Să se afiţeze numele şi vârsta în ani a salariaţilor care au realizat deconturi de cheltuieli. b) Să se afişeze denumirile categoriilor pentru care în anul 2007 s-au realizat mai mult de 20 operaţii. c) Să se afişeze numărul deconturilor de cheltuieli pe angajaţi şi pe luni. Se va folosi o interogare de tipul analiză încruciţată (Crosstab Query).

Page 119: Studii de Caz Access 2007

Baze de date Access 2007

119

IV. Realizaţi interogări SQL pentru următoarele cerinţe: IV.a) Să se afiţeze tipurile de categorii de operaţii. Un tip se va afiţa o singură dată.

SELECT DISTINCT TipCategorie FROM Categorie ORDER BY TipCategorie;

IV.b) Să se afiţeze primele trei documente justificative cu cele mai mari sume. Pentru a afiţa doar primele trei documente se ordonează descrescător înregistrările în funcţie de sumă şi se foloseţte cuvântul cheie TOP urmat de numărul de înregistrări dorite.

SELECT TOP 3 * FROM DocumentJustificativ ORDER BY SumaDocJustificativ DESC

IV.c) Să se afiţeze alfabetic categoriile de operaţii ce fac parte din cadrul unui anumit tip introdus ca parametru. Valoarea parametrului este introdusă prin intermediul unui control de tip listă derulantă denumit CmbTip din formularul Operatie.

Referinţa la valoarea unui către un control al unui formular se realizează astfel [Forms]![NumeFormular]![NumeControl].

SELECT CodCategorie, DenumireCategorie FROM Categorie WHERE TipCategorie=[Forms]![Operatie]![CmbTip] ORDER BY TipCategorie;

IV.d) Să se afiţeze lista operaţiilor realizate între anumite date introduse ca parametru, evidenţiindu-se în coloane distincte sumele plătite şi cele încasate

SELECT NrOperatie, DataOperatie, ExplicatieOperatie, [TipDocument] & [NrDocument] AS Document, IIF([TipCategorie]="Incasare",[SumaOperatie],0) AS Incasare, IIF([TipCategorie]="Plata",[SumaOperatie],0) AS Plata FROM Categorie INNER JOIN Operatie ON Categorie.CodCategorie = Operatie.CodCategorie WHERE Operatie.DataOperatie Between [Datainceput] And [DataSfarsit] ORDER BY Operatie.DataOperatie;

IV.e) Să se afiţeze numărul de salariaţi pe fiecare categorie de vârstă. SELECT COUNT(MarcaSalariat) AS Nr, YEAR(Date())-YEAR([DataNastereSalariat]) AS Varsta FROM Salariat GROUP BY YEAR(Date())-YEAR([DataNastereSalariat]);

IV.f) Să se afiţeze categoriile de operaţii pentru care suma totală pentru anul 2007 a depăţit 500 RON. Înregistrările se vor ordona în funcţie de valoarea totală.

SELECT Categorie.CodCategorie, FIRST(DenumireCategorie) AS Denumire, SUM(Operatie.SumaOperatie) as SumaTotala FROM Categorie INNER JOIN Operatie ON Categorie.CodCategorie = Operatie.CodCategorie

Page 120: Studii de Caz Access 2007

Studii de caz

120

WHERE YEAR([DataOperatie])=2007 GROUP BY Categorie.CodCategorie HAVING SUM(SumaOperatie)>500 ORDER BY SUM(SumaOperatie) DESC;

IV.g ) Să se afiţeze totalul sumelor justificate precum şi operaţiile efectuate prin casierie pentru fiecare decont. Se vor afiţa numărul decontului, data acestuia, total sume justificate sau suma operaţiei (coloana denumita Suma), tipul categoriei operaţiei (pentru sumele totale justificate se va afiţa Justificare), denumirea categoriei din care face parte operaţia (pentru sumele totale justificate se va afiţa Justificare avans), pentru sumele totale justificate şi pentru operaţiile de tip încasare se va afiţa în coloana separata semnul +1, iar pentru operaţiile de tip plată semnul -1. În ultima coloana denumită Total se va afiţa produsul dintre suma totală justificată sau suma operaţiei şi semnul +1 sau -1.

Deoarece trebuie reunite informaţii ce se pot obţine folosind cereri distincte se foloseţte operatorul UNION. Numărul de coloane din fiecare cerere ce participa la reuniune cu ajutorul operatorului UNION trebuie să fie acelaţi.

Prima cerere va returna suma totală justificata pe fiecare decont afiţând numărul şi data decontului, suma totală calculată cu ajutorul funcţiei SUM, tipul operaţiei fiind „Justificatoare”, coloana Descriere afiţând mesajul „Justificare avans”, semnul este +1, iar coloana „Total” se obţine prin preluarea valorii sumei totale. Ce de a doua cerere afiţează lista operaţiilor participante la decont.

SELECT Decont.NrDecont, FIRST(DataDecont) AS Data,SUM(SumaDocJustificativ) AS Suma, "Justificatore" AS Tip, "Justificare avans" AS Descriere, "+1" AS Semn, SUM(SumaDocJustificativ) AS Total FROM Decont INNER JOIN DocumentJustificativ ON Decont.NrDecont = DocumentJustificativ.NrDecont GROUP BY Decont.NrDecont UNION SELECT Decont.NrDecont, DataOperatie AS Data, SumaOperatie AS Suma, TipCategorie, DenumireCategorie, IIf(TipCategorie="Incasare","+1","-1") AS Semn,Suma*Semn AS Total FROM Decont, Categorie, Operatie WHERE Decont.NrDecont=[Operatie].[NrDecont] AND Categorie.CodCategorie=[Operatie].[CodCategorie] ORDER BY Data;

IV.h) Să se modifice explicaţia operaţiei generată de chitanţa numărul 45 din 12-07-2007, noua explicaţie fiind “Plata C 45”

UPDATE Operatie SET ExplicatieOperatie = "Plata C 45" WHERE Operatie.NrDocument=45 AND Operatie.TipDocument="C" AND Operatie.DataOperatie=#7/12/2007#;

Page 121: Studii de Caz Access 2007

Baze de date Access 2007

121

IV.i) Să se afiţeze categoriile pentru care nu s-au realizat operaţii în anul 2005. SELECT * FROM Categorie WHERE CodCategorie NOT IN (SELECT Categorie .CodCategorie FROM Categorie INNER JOIN Operatie ON Categorie.CodCategorie = Operatie.CodCategorie WHERE YEAR([DataOperatie])=2005);

IV.j) Să se afiţeze categoriile pentru care sunt efectuate cele mai multe operaţii. SELECT Operatie.CodCategorie, FIRST(DenumireCategorie) AS Denumire, COUNT(NrOperatie) AS Numar FROM Categorie INNER JOIN Operatie ON Categorie.CodCategorie = Operatie.CodCategorie GROUP BY Operatie.CodCategorie HAVING COUNT(NrOperatie) >=ALL (SELECT COUNT(Operatie.NrOperatie) FROM Categorie INNER JOIN Operatie ON Categorie.CodCategorie = Operatie.CodCategorie GROUP BY Operatie.CodCategorie);

Studiu individual:

a) Să se afişeze cronologic toate operaţiile pentru care documentul este de tip factură vânzare codificat “FV” b) Să se afişeze numărul de categorii de operaţii pe fiecare tip de categorie. c) Afişaţi lunile din anul 2007 în care s-au justificat sume totale mai mari de 500 RON. d) Să se afişeze salariaţii care în anul 2007 nu au beneficiat de deconturi de cheltuieli. e) Să se afişeze categoria de operaţii pentru care în anul 2007 s-au efectuat tranzacţii cu cea mai mare valoare totală.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular cu subforumular pentru actualizarea deconturilor de cheltuieli, a avansurilor spre decontare şi a documentelor justificative.

Formularul principal va avea ca sursă tabelul Decont, subformularul AvansuriDecontare va avea ca sursă interogarea Avansuri_decontare rezolvată în cadrul cerinţei III.a, iar subformularul DocumentJustificativ va avea ca sursă tabelul cu acelaţi nume. Legătura dintre formular şi cele doua subformulare se va realiza prin intermediul cheii primare respectiv externe NrDecont.

Page 122: Studii de Caz Access 2007

Studii de caz

122

Formular pentru actualizarea deconturilor de cheltuieli

În cadrul formularului principal se va realiza o listă derulantă ce permite selecţia salariatului la care se referă decontul de cheltuieli. În cadrul subformularelor se vor afişa totalurile avansurilor fără restituiri şi respectiv totalul sumelor justificate. Calculul avansului total fără sumele restituite se realizează în cadrul secţiunii Form Footer a subformularului AvansuriDecontare cu ajutorul unei casete text (control TextBox) pentru care valoarea Control Source va fi egală cu

.Pentru acest control proprietatea Name va avea valoarea txtSuma Pentru calculul totalului sumelor justificate se va folosi un control de tip casetă text( TextBox) pentru care valoarea Control Source va fi egală cu

, iar valoarea proprietăţii Name va fi txtSumaJustificata.

În cadrul formularului principal se vor prelua valorile celor două controale txtSuma şi txtSumaJustificata făcându-se referire la numele subformularelor din care provin. Controalele formularului principal care vor prelua sumele totale date ca avans şi cele justificate vor avea proprietatea Name egală cu txtSAvans, respectiv txtSJustificata. Afişarea mesajului „diferenţă de încasat” sau „diferenţă de plătit” se realizează cu ajutorul funcţiei IIF astfel valoarea proprietăţii Control Source a controlului casetă text ce va afiţa acest mesaj va fi egală cu

Pentru calculul sumelor ce trebuiesc restituite sau încasate se va folosi funcţia IIF. Controlul de tip casetă text va avea proprietatea Control Source egală cu

Formularul pentru actualizarea deconturilor de cheltuieli în modul Design View este prezentat în figura următoare:

Page 123: Studii de Caz Access 2007

Baze de date Access 2007

123

V.b) Realizaţi un formular pe baza tabelei operaţie ce va permite actualizarea înregistrărilor din această tabelă.

Se va realiza un control de tip listă derulantă ce va permite alegerea tipului de operaţie (încasare sau plată). Proprietatea Name a acestui control va avea valoarea CmbTip. În funcţie de tipul operaţiei se va alege o categorie. Pentru încasare se pot alege vânzarea de serviciilor proprii, ridicări de numerar de la bancă, aport de capital sau alte încasări, iar pentru plăţi se poate alege achitarea drepturilor salariale, avansuri spre decontare, cumpărări de bunuri, depuneri de numerar la bancă sau alte plăţi. Pentru selecţia categoriei se va realiza o listă derulantă ce va avea ca sursă interogarea rezolvată în cadrul cerinţei IV.c. Proprietatea Name a acestui control va avea valoarea CmbCategorie.

Page 124: Studii de Caz Access 2007

Studii de caz

124

Pentru actualizarea valorilor controlului CmbCategorie .după actualizarea valorilor controlului CmbTip se va folosi procedura următoare în cadrul evenimentului After Update asociat controlului CmbTip.

Private Sub CmbTip_AfterUpdate()

Me.CmbCategorie.Requery

End Sub

Studiu individual:

a) Să se realizeze un formular Startup ce va permite deschiderea formularelor realizate în cadrul aplicaţiei.

b) Să se realizeze un formular pe baza tabelului salariat ce permite actualizarea înregistrărilor. Se va realiza o listă derulantă ce va permite căutarea salariaţilor. Se vor adăuga butoane de navigare, de ştergere a unui angajat şi de adăugare a unei noi înregistrări precum şi închiderea formularului.

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Să se afişeze registrul de casă ce va prezenta situaţia zilnică a operaţiilor realizate prin casierie între anumite date introduse ca parametru. Se vor afiţa pentru fiecare dată calendaristică soldul iniţial (soldul final al zilei precedente), operaţiile efectuate în acea zi (număr şi tip document) sumele încasate respectiv plătite precum şi soldul final al zilei.

Sursa acestui raport o constituie interogarea rezolvată la cerinţa IV.d. În cadrul raportului se vor grupa înregistrările pe zile (data operaţiei fiind câmpul de grupare).

Page 125: Studii de Caz Access 2007

Baze de date Access 2007

125

Totalul încasărilor zilnice se va calcula în cadrul secţiunii DataOperatie Footer cu ajutorul unui control de tip caseta text pentru care proprietatea Control Source va avea valoarea =Sum([Incasare]). În acelaţi fel se va proceda şi pentru calculul totalului plaţilor. Soldul final al zile se calculează astfel =Sum([Incasare]-[Plata])+[txtSI], unde txtSI este numele controlului caseta text în care s-a afiţat valoarea soldului iniţial al zilei Raportul Registru casă vizualizat în mod Design View este prezentat în figura următoare:

Pentru aflarea soldului iniţial al unei anumite zile se realizează o funcţie în cadrul unui modul VBA. Funcţia va avea ca argument data pentru care se doreţte calcularea soldului iniţial. În cadrul acestei funcţii se va defini o variabilă de tip QueryDef care va corespunde interogării SolduriInitiale rezolvată în cadrul cerinţei III.d. O variabilă de tip Recordset se va defini pentru a se face referire la obiectul Recordset ataţat obiectului QueryDef "SolduriInitiale". În formular soldul iniţial al unei zile este afiţat cu ajutorul unei casete text amplasate în cadrul secţiunii DataOperatie Header pentru care valoarea Control Source are valoarea =SoldInitial([DataOperatie]).

Public Function SoldInitial(data As Date) As Double ‘se declara o variabila de tip QueryDef

Dim q As QueryDef ‘se iniţializează variabila de tip QueryDef cu obiectul de tip interogare SolduriInitiale

Set q = CurrentDb.QueryDefs("SolduriInitiale") ‘se atribuie valorile pentru parametrii interogării

Page 126: Studii de Caz Access 2007

Studii de caz

126

q.Parameters(0) = data ‘se declara o variabila de tip Recordset

Dim rs As Recordset ‘se iniţializează obiectul de tip recordset asociat interogării

Set rs = q.OpenRecordset

If Not rs.EOF Then ‘dacă există înregistrări ce corespund cerinţelor, funcţia va returna valoarea atributului ‘SoldIZi

SoldInitial = Nz(rs("SoldZi"))

Else ‘dacă nu există înregistrări ce corespund cerinţelor, funcţia va returna valoarea 0

SoldInitial = 0 End If

End Function

VI.b) Să se afişeze situaţia decontărilor pe salariaţi. Se vor afişa pentru fiecare decont avansurile, retururile precum şi sumele justificate şi diferenţele de încasat sau restituit.

Raport ce prezintă situaţia decontărilor pe salariaţi

Sursa acestui raport o constituie interogarea rezolvată în cadrul cerinţei IV.g. Înregistrările se vor grupa în funcţie de numărul decontului. În cadrul secţiunii NrDecont Header se va afiţa diferenţa de plătit sau încasat prin însumarea (figura următoare) valorilor câmpului Total din interogarea sursă a raportului. Câmpul total nu se va afiţa în cadrul raportului, valoarea proprietăţii Visible fiind False.

Page 127: Studii de Caz Access 2007

Baze de date Access 2007

127

Raport ce prezintă situaţia decontărilor pe salariaţi vizualizat

în modul mod Design View

Studiu individual:

a) Să se realizeze un raport ce prezintă cronologic lista operaţiilor realizate între doua date introduse ca parametrii. Se va afişa numărul curent al fiecărei operaţii, numărul şi tipul documentului, data operaţiei, suma încasată respectiv plătită. Se vor calcula totalurile încasate, plătite şi diferenţa dintre încasări şi plăţi.

b) Să se realizeze un raport ce prezintă situaţia tuturor documentelor justificative. Se vor calcula totalul sumelor şi numărul de documente.

Page 128: Studii de Caz Access 2007

Studii de caz

128

VII Bază de date pentru gestiunea costurilor proiectelor

Având ca principal obiectiv consultanţă în domeniul economic, firma Consult SRL doreşte realizarea unei baze de date pentru gestionarea costurilor proiectelor pe care le dezvoltă. Atunci când se iniţiază un proiect este necesară reţinerea titlului şi a descrierii acestuia, precum şi a datelor de început şi de finalizare precum şi a codului unic la nivelul firmei atribuit de sistem. Descrierea proiectului este completată cu ajutorul unei documentaţii sub forma unei resurse electronice (fişier Word, document scanat, etc.).

Resursele implicate în derularea proiectelor pot să fie încadrate în doua categorii: umane, materiale. Pentru fiecare resursa implicată în desfăşurarea proiectului se va retine în sistem codul şi denumire. Din fiecare resursă se va consuma în cadrul unui proiect un anumit număr de unităţi de măsura (ore lucrate pentru resursa umană, respectiv cantitatea de materiale folosite). Resursele materiale folosite în cadrul proiectelor pot să fie încadrate în mai multe categorii (materiale, electronice, etc.). Costul unitar precum şi tariful orar al resurselor consumate diferă în funcţie de proiect. De exemplu la proiectul intitulat„ Modalităţi de perfecţionare prin e-learning pentru personalul departamentului contabilitate” vor colabora un expert contabil, un expert resurse umane, un analist IT şi un manager de proiect ce lucrează fiecare câte 20 ore, fiind plătiţi cu un tarif orar de 7 RON, 10 RON, 15 RON, respectiv 20 RON. În acelaşi proiect se vor consuma 2 topuri de hârtie al cărui cost este de 8,63 RON şi 1 toner imprimantă ce costă 328,6 RON, în timp ce valoarea cheltuielile de regie (indirecte) este 1000 RON, iar alte cheltuieli în valoare de 44,3 RON.

În funcţie de complexitatea proiectului şi resursele folosite, costul total al acestuia este obţinut prin însumarea costurilor totale pentru fiecare categorie de cheltuieli: cheltuielile directe (cu manopera, cu materialele) şi cheltuielile indirecte. Cheltuielile indirecte codificate în mod unic la nivelul firmei participă la calculul costului a mai multor proiecte, pentru fiecare în parte având o anumite valoare.

Reguli de gestiune:

• În cadrul unui proiect se consumă mai multe resurse, o resursă poate să fie alocată mai multor proiecte, cantitatea (numărul de ore) şi costul unitar (tariful) variind în funcţie de proiect.

• Costul total al unui proiect se obţine prin însumarea costurilor categoriilor de cheltuieli participante (cu manopera, cu materialele, cheltuielile indirecte), cheltuielile indirecte participă la calculul costului a mai multor proiecte, pentru fiecare în parte având o anumită valoare.

Page 129: Studii de Caz Access 2007

Baze de date Access 2007

129

I. Realizaţi modelul relaţional al bazei de date şi implementaţi în MS Access Realizarea modelului relaţional al bazei de date presupune parcurgerea mai multor etape. Plecând de la informaţiile de bază respectiv atributele pe baza relaţiilor stabilite între acestea (dependente funcţionale) se realizează succesiv formele normalizate ale bazei de date (FN1, FN2, FN3). Trebuie stabilite în primul rând atributele elementare şi nerepetitive ce vor constitui baza procesului de normalizare. Deoarece baza de date va fi realizată cu ajutorul ACCESS 2007 se vor folosi noile funcţionalităţi ale acestuia şi se va defini un câmp denumit Documentaţie în care se vor retine fişierul ce conţine descrierea proiectului. Pe baza analizei cerinţelor funcţionale ale bazei de date se identifică următorul dicţionar preliminar al datelor:

Cod Proiect, Denumire Proiect, Descriere, Data Început, Data Sfârşit, Cod Resursa Umana, Denumire Resursa Umana, Cod Resursa Materiala, Denumire Resursa Materiala, Unitate Măsură, Cod Cheltuiala indirecta, Denumire Cheltuiala indirecta, Cantitate, Număr Ore Lucrate, Tarif Orar, Cost Unitar, Cost Total Resursa Materiala Consumata, Cost Total Proiect, Valoare cheltuieli indirecte pe proiect, Valoare totala cheltuieli indirecte, Categorie Resursa Materiala, Documentaţie. Prin respectarea cerinţelor impuse de către FN1, din dicţionarul atributelor se vor elimina atributele calculate

• Cost Total Resursa Materiala Consumata deoarece se calculează prin înmulţirea cantităţii cu costul unitar

• Cost Total Proiect obţinută prin însumarea valorilor tuturor cheltuielilor implicate în proiect

• Valoare totala cheltuieli indirecte calculată prin însumarea valorilor tuturor cheltuielilor indirecte implicate în proiect

Respectând cerinţele impuse cheilor primare (unicitate, ireductibilitate) se identifică în cadrul dicţionarul atributelor următoarele atribute candidat:

Atribut Candidat Descriere

Cod Proiect Acest atribut are valori unice, identificând în mod unic un proiect.

Cod Resursa Umana Fiecare resursă umană implicată în desfăşurarea proiectelor va fi codificată în mod unic. Aceasta codificare se va folosi pentru fiecare implicare a acestei resurse în orice proiect.

Cod Resursa Materiala

Fiecare resursa materială implicată în desfăşurarea proiectelor va fi codificată în mod unic. Aceasta codificare se va folosi pentru fiecare utilizare a acestei resurse în orice proiect.

Cod Cheltuiala indirecta

Pentru fiecare proiect se pot folosi mai multe categorii de cheltuieli indirecte. Pentru identificarea uşoară şi clasificarea acestora se codifică fiecare categorie.

Page 130: Studii de Caz Access 2007

Studii de caz

130

Următoarea etapă în cadrul normalizării o reprezintă identificarea dependenţelor funcţionale. Este recomandat ca din mulţimea dependenţelor funcţionale să se reţină doar cele în care determinatul este cheie primară. Deoarece la iniţierea unui proiect i se atribuie un cod unic ce îl va identifică în mod unic, există dependente funcţionale între atributul Cod Proiect şi atributele Denumire Proiect, Descriere, Data Început, Data Sfârşit şi Documentaţie.

Fiecare resursă umană implicată în desfăşurarea proiectelor va fi codificată în mod unic, acest lucru determinând dependenţă funcţională între atributele Cod Resursa Umana şi Denumire Resursa Umana. Atributul Cod Resursa Materiala va determina funcţional atributele Denumire Resursa Materiala, Unitate Măsură şi Categorie Resursa Materiala.

Fiecare categorie de cheltuieli indirecte( în afara de cele generate de resursele umane sau materiale) va fi identificată cu ajutorul atributului Cod Cheltuiala indirecta ce va determina funcţional atributul Denumire Cheltuiala Indirecta. Cantitatea dintr-o resursă (numărul de ore) şi costul unitar (tariful) variază în funcţie de proiect determinând dependenţa funcţională totală între grupul de atribute Cod Proiect, Cod Resursa Umana şi atributele Număr Ore Lucrate, Tarif Orar precum şi între grupul de atribute Cod Proiect, Cod Resursa Materiala şi atributele Cantitate şi Cost Unitar. Pentru fiecare proiect se pot folosi mai multe categorii de cheltuieli indirecte, fiecare în parte având o anumite valoare.

Dependenţe funcţionale funcţionale sunt evidenţiate în figura următoare:

Pentru simplificare în scop didactic s-au reprezentat în cadrul matricei dependenţelor funcţionale doar dependenţele funcţionale totale în care determinatul este cheie primară, nereprezentându-se dependenţele funcţionale multivaloare, dependenţele funcţionale tranzitive sau cele parţiale.

Matricea dependenţelor funcţionale este prezentată pe pagina următoare:

Page 131: Studii de Caz Access 2007

Baze de date Access 2007

131

Analizând dependenţele funcţionale se observa ca nu există dependenţe funcţionale tranzitive obţinându-se astfel tabelele ce respectă forma normală trei.

Proiecte (CodProiect, DenumireProiect, Descriere, DataInceput, DataSfarsit, Documentatie)

CheltuieliIndirecte (CodCheltuialaIndirecta, DenumireCheltuialaIndirecta)

CheltuieliIndirecteProiect (CodProiect, CodCheltuialaIndirecta, ValoareCheltuialaIndirecta)

ResurseUmane (CodResursaUmana, DenumireResursaUmana)

ResurseUmaneProiect (CodProiect, CodResursaUmana, NumarOreLucrate, TarifOrar)

ResurseMateriale (CodResursaMateriala, DenumireResursaMateriala, UnitateMasura, CategorieResursaMateriala)

ResurseMaterialeProiect (CodProiect, CodResursaMateriala, Cantitate, Cost Unitar)

Implementarea modelului în Microsoft Access este prezentată în figura din pagina următoare.

Page 132: Studii de Caz Access 2007

Studii de caz

132

Studiu individual:

Beneficiarii proiectelor pot să fie persoane fizice sau juridice pentru care trebuie reţinut în sistem denumirea şi tipul. Fiecare beneficiar va fi codificat, codul ajutând la identificarea ulterioară a acestuia. Un beneficiar poate avea mai multe proiecte, un proiect este realizat pentru un singur beneficiar. Adăugaţi modelului relaţional tabelul sau tabelele necesare pentru a permite memorarea datelor aferente beneficiarilor proiectelor.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) Data început trebuie să fie anterioară datei de finalizare a proiectului.

II.b) Valoarea cheltuielilor indirecte trebuie să fie pozitivă.

II.c) Data de început a unui proiect să aibă valoare implicită data curentă.

Restricţiile ce presupun implicarea mai multor câmpuri din cadrul aceluiaşi tabel se vor implementa în cadrul proprietăţilor tabelului la Validation Rule.

Implementarea restricţiei data început anterioară datei de finalizare la nivelul tabelului Proiect

Page 133: Studii de Caz Access 2007

Baze de date Access 2007

133

Pentru ca data de început a proiectului să fie implicit data curentă se va folosi funcţia Date() în cadrul proprietăţii Default Value. Restricţia asupra valorilor unui singur atribut din cadrul unui tabel se implementează la proprietatea Validation Rule a acelui atribut .

Implementarea restricţiei Valoare Cheltuieli Indirecte pozitivă

Valoare implicita pentru atributul Data Început

Studiu individual:

a) Valorile pentru unitatea de măsură să se poată selecta dintr-o listă derulantă ce conţine cele mai utilizate valori (bucată, kg, litru), lăsând posibilitatea adăugării ulterioare şi a altor valori. b) Cantitatea, numărul de ore lucrate precum şi costul materialelor trebuie să admită doar valori pozitive c) Tariful orar trebuie sa se încadreze între 10 şi 150.

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afişeze săptămânile în care sunt programate să înceapă proiectele

Page 134: Studii de Caz Access 2007

Studii de caz

134

III.b) Să se afişeze suma totală a cheltuielilor indirecte pentru proiectele începute în lunile ianuarie sau februarie 2005 în care sunt implicate mai mult de două tipuri de cheltuieli indirecte.

Modalitatea de referire la o dată calendaristică diferă în funcţie de setările regionale ale fiecărui calculator.

III.c) Să se afişeze situaţia costurilor resurselor materiale pe categorii şi proiecte. Se va folosi o cerere de tip analiză încrucişată (Crosstab Query).

III.d) Să se creeze un tabel ce conţine denumirea şi codul proiectele în cadrul cărora nu sunt implicate cheltuieli materiale.

Aceasta interogare este o interogare de acţiune Make Table. Pentru realizarea acesteia se apasă butonul

aflat în cadrul grupului Query

Specificarea numelui tabelului ce se va crea prin

Page 135: Studii de Caz Access 2007

Baze de date Access 2007

135

Type din meniul Design. intermediul interogării de tip Make Table

Pentru a afişa toate proiectele cele ce au precum şi cele ce nu au cheltuieli materiale trebuie schimbat tipul legăturii dintre tabelele Proiect şi ResurseMaterialeProiect..

Proprietăţile relaţiei dintre tabele Proiect şi

ResurseMaterialeProiect

Studiu individual:

a) Să se afişeze numărul de proiecte pe ani de începere şi de finalizare. Se va folosi o cerere de tip analiză încrucişată. b) Să se afişeze proiectele în care sunt implicate mai mult de 3 resurse materiale ce nu sunt din categoria „echipamente”. c) Sa se creeze un tabel ce conţine denumirea şi codul cheltuielilor indirecte neutilizate în cadrul proiectelor.

IV. Realizaţi interogări SQL pentru următoarele cerinţe: IV.a) Să se afişeze categoriile resurselor materiale. O categorie se va afişa doar o singură dată

SELECT DISTINCT ResurseMateriale.CategorieResursaMateriala FROM ResurseMateriale;

IV.b) Să se afişeze durata proiectului în luni şi zile. În funcţie de perioada de desfăşurare se va afişa categoria proiectului astfel: proiect pe termen scurt dacă perioada este mai mica de 2 luni, altfel fiind încadrat în categoria proiectelor pe termen lung)

Funcţia DateAdd permite adăugarea unei valori numerice la o anumita dată calendaristică obţinându-se tot o dată. Funcţia DateDiff permite calcularea diferenţei între două date calendaristice, această diferenţă fiind afişată în zile (caz în care se foloseşte valoarea „d” pentru parametrul funcţiei) sau luni (ceea ce implică folosirea parametrului „m”).

Page 136: Studii de Caz Access 2007

Studii de caz

136

SELECT CodProiect, DATEDIFF("m",[DataInceput],[DataSfarsit]) AS NrLuni, [DataSfarsit]-DateAdd("m",[NrLuni],[DataInceput]) AS NrZile, IIF([Nrluni]<=2,"termen scurt","termen lung") AS Tip FROM Proiecte

IV.c) Să se afişeze proiectele în care s-au folosit resurse materiale din categoria „echipamente”

SELECT Proiecte.CodProiect, DenumireProiect FROM ResurseMateriale, Proiecte, ResurseMaterialeProiect WHERE CategorieResursaMateriala="Echipamente" AND Proiecte.CodProiect = ResurseMaterialeProiect.CodProiect AND ResurseMateriale.CodResursaMateriala = ResurseMaterialeProiect.CodResursaMateriala

IV.d) Să se calculeze totalul cheltuielilor indirecte pentru fiecare proiect SELECT CodProiect, SUM(ValoareCheltuieliIndirecte) AS CostChInd FROM CheltuieliIndirecteProiect GROUP BY CodProiect;

IV.e) Să se afişeze denumirea primelor cinci resurse umane ce au cel mai mare cost total.

Costul total se obţine prin însumarea valorilor costurilor pentru fiecare proiect la care a participat. Costul unei resurse este obţinut pe baza tarifului orar şi a numărului de ore lucrate. Pentru a afişa doar primele cinci resurse se ordonează descrescător înregistrările în funcţie de costul total pe resursă şi cu ajutorul cuvântului cheie TOP urmat de numărul de înregistrări dorite.

SELECT TOP 5 ResurseUmane.CodResursaUmana, FIRST(DenumireResursaUmana) as ResursaUmana, SUM([NumarOreLucrate]*[TarifOrar]) AS CostResursaUmana FROM ResurseUmane INNER JOIN ResurseUmaneProiect ON ResurseUmane.CodResursaUmana = ResurseUmaneProiect.CodResursaUmana GROUP BY ResurseUmane.CodResursaUmana ORDER BY SUM([NumarOreLucrate]*[TarifOrar]) DESC;

IV.f) Să se afişeze toate resursele implicate (resurse umane, materiale) şi cheltuielile indirecte implicate în cadrul proiectelor. Se va afişa codul proiectului, denumirea resursei, costul resursei şi tipul resursei (umană, materială, cheltuială indirectă).

Înregistrările ce vor fi afişate ca rezultat al acestei cereri provin din trei tabele diferite folosindu-se pentru a rezolva aceasta cerinţă operatorul UNION. Ordonarea s-a făcut global pentru întregul set de înregistrări în funcţie de codul proiectului şi tipul resurselor.

SELECT CodProiect, DenumireResursaMateriala, [Cantitate]*[CostUnitar] AS CostResursa, "Resursa materiala" as Tip FROM ResurseMateriale INNER JOIN ResurseMaterialeProiect ON ResurseMateriale.CodResursaMateriala = ResurseMaterialeProiect.CodResursaMateriala UNION SELECT CodProiect, DenumireResursaUmana, [NumarOreLucrate]*[TarifOrar] AS CostResursa, "Resursa umana" as Tip

Page 137: Studii de Caz Access 2007

Baze de date Access 2007

137

FROM ResurseUmane INNER JOIN ResurseUmaneProiect ON ResurseUmane.CodResursaUmana = ResurseUmaneProiect.CodResursaUmana UNION SELECT CodProiect, DenumireCheltuialaIndirecta, ValoareCheltuieliIndirecte AS CostResursa, "Cheltuiala indirecta" as Tip FROM CheltuieliIndirecte INNER JOIN CheltuieliIndirecteProiect ON CheltuieliIndirecte.CodCheltuialaIndirecta = CheltuieliIndirecteProiect.CodCheltuialaIndirecta ORDER BY CodProiect ,Tip

IV.g) Să se adauge proiectul având codul “CJ5698” denumit „Modalităţi de perfecţionare a managementului proiectelor” pentru care data de începere este 1-12-2007 şi data de finalizare este 25-6-2008.

Pentru a adăuga date în cadrul unui tabel pe lângă numele tabelului se vor preciza numele câmpurilor şi valorile acestora. Pentru valorile de tip text se vor folosi ghilimelele (”) iar pentru date calendaristice se vor folosi caracterele diez (#) pentru a delimita valoarea acesteia.

INSERT INTO Proiecte ( CodProiect, DenumireProiect, DataInceput, DataSfarsit ) VALUES ("CJ5698", "Modalităţi de perfecţionare a managementului proiectelor", #1/12/2007#, #6/25/2008#)

IV.h) Să se mărească cu 10% tariful orar pentru resursele umane implicate în proiectele ce au început în martie 2005 şi au o durată mai mică de 30 zile .

Am folosit pentru a rezolva aceasta cerinţă o interogare de tip acţiune combinată cu o subinterogare ce are drept scop selecţia proiectelor începute în martie 2005 cu o durată mai mică de 30 zile. Funcţiile Month şi Year extrag luna, respectiv anul dintr-o dată calendaristică.

UPDATE ResurseUmaneProiect SET TarifOrar = TarifOrar*1.1 WHERE CodProiect IN (SELECT Proiecte.CodProiect FROM Proiecte INNER JOIN ResurseUmaneProiect ON Proiecte.CodProiect = ResurseUmaneProiect.CodProiect WHERE MONTH(DataInceput)=3 AND YEAR(DataInceput)=2005 AND DataSfarsit-DataInceput=30 )

IV.i) Să se şteargă resursele umane neimplicate în nici un proiect.

Resursele umane care nu participa la nici un proiect sunt acelea al căror cod se regăseşte în tabela ResurseUmane şi nu apare în tabela ResurseUmaneProiect.

DELETE * FROM ResurseUmane Where CodResursaUmana NOT IN (SELECT CodResursaUmana FROM ResurseUmaneProiect)

IV.j) Să se afişeze codurile şi denumirile proiectelor derulate în anul 2007 având valoarea totală a cheltuielilor materiale mai mare decât o valoare introdusă ca parametru.

În cadrul unui proiect sunt consumate mai mute resurse materiale. Pentru a calcula totalul costurilor materiale pe proiect se va folosi funcţia agregată SUM.

Page 138: Studii de Caz Access 2007

Studii de caz

138

SELECT Proiecte.CodProiect, FIRST(DenumireProiect) AS Denumire, SUM([Cantitate]*[CostUnitar]) AS [Cost Resurse Materiale] FROM Proiecte, ResurseMateriale ,ResurseMaterialeProiect WHERE Proiecte.DataInceput>=#1/1/2007# AND Proiecte.DataSfarsit<=#12/31/2007# AND ResurseMateriale.CodResursaMateriala = ResurseMaterialeProiect.CodResursaMateriala AND Proiecte.CodProiect = ResurseMaterialeProiect.CodProiect GROUP BY Proiecte.CodProiect HAVING SUM([Cantitate]*[CostUnitar])>=[Introduceti valoarea]

Studiu individual:

a) Să se afişeze proiectele începute între anumite date introduse ca parametrii.

b) Să se afişeze pentru fiecare proiect stadiul desfăşurării (în desfăşurare, finalizat sau neînceput). Observaţie se va folosi funcţia IIF. c) Să se afişeze numărul de resurse materiale pe categorii. d) Să se afişeze codurile şi denumirile proiectelor începute în anul 2007 având valoarea totală a cheltuielilor resurselor umane mai mare decât 200. e) Să se şteargă proiectele finalizate care nu implică nici un fel de resurse.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular cu subformular pentru a introduce detaliile unui proiect precum şi costurile principalelor resurse implicate în dezvoltarea acestuia. Formularul principal va actualiza tabelul Proiect şi va avea trei subformulare pentru actualizarea resurselor materiale (tabel ResurseMaterialeProiect), a celor umane (tabel ResurseUmaneProiect) şi a cheltuielilor indirecte (tabel CheltuieliIndirecteProiect) implicate în proiect. Se va realiza o listă derulantă ce permite căutarea rapidă a unui anumit proiect.

Fiind necesară afişarea mai multor categorii de informaţii precum şi sintetizarea acestora (afişarea costurilor totale din fiecare categorie) se va folosi un control de tip Tab (figura următoare). Controale disponibile în cadrul Microsoft ACCESS 2007 se regăsesc uşor în meniul Design în categoria Controls.

Page 139: Studii de Caz Access 2007

Baze de date Access 2007

139

Formularul ce permite gestionarea costurilor proiectelor

Realizarea subformularelor se face cu ajutorului controlului Subform/ Subreport din cadrul grupului de butoane Controls din meniul Design. Proprietatea Default View a subformularelor va avea valoarea Datasheet.

Controlul Subform/ Subreport

Realizarea subformularului ResurseUmaneProiect

Legătura dintre formularul principal (Proiect) şi subformularul ResurseUmaneProiect se face prin intermediul câmpului CodProdus. Deoarece valoarea codului de proiect se va afişa în cadrul formularului principal nu mai este necesară afişarea acestei valori şi în cadrul subformularului.

În subformulare se vor realiza liste derulante pentru cheile externe. În cazul subformularului ResurseUmaneProiect afişarea costul fiecărei resursei umane

implicate în proiect se realizează cu ajutorul unui control caseta text (TextBox ) a

cărui proprietate ControlSource este . Numărul total al orelor lucrate se calculează în cadrul subsolului formularului (secţiunea Form Footer) cu ajutorul unei casete text (TextBox) pentru care proprietatea ControlSource este

.

Page 140: Studii de Caz Access 2007

Studii de caz

140

Pentru a se putea prelua valoarea numărului total de ore în cadrul formularului principal, controlul casetă text se va redenumi txtTotalOre.

Subformular ResurseUmaneProiect afişat în modul Design View

Costul total al resurselor umane se calculează în cadrul subsolului formularului ResurseUmaneProiect (secţiunea Form Footer) cu ajutorul unei casete text( TextBox)

pentru care proprietatea ControlSource este . Pentru a se putea prelua aceasta valoare în cadrul formularului principal controlul caseta text se va redenumi txtTotalCostRU.

In formularul principal, ce permite editarea proiectelor, pentru afişarea numelui şi codului proiectului se foloseşte un control de tip Text Box pentru care proprietatea

Control Source va avea valoarea . Pentru afişarea în cadrul formularului principal a valorilor totale ale costurilor resurselor umane, materiale şi cheltuielilor indirecte se vor folosi casete text (Text Box) pentru care proprietatea Control Source va avea valoarea =[NumeSubformular].[Form]![NumeControlSubformular] .

În cazul în care un proiect nu are cheltuieli dintr-o anumita categorie (umană, materială sau indirecte) în cadrul costului total acestea au pondere 0. Pentru a converti valoare NULL la valoarea 0 se foloseşte funcţia NZ.

Page 141: Studii de Caz Access 2007

Baze de date Access 2007

141

Calculul costului total al resurselor materiale în cadrul subformularului ResurseUmaneProiect şi preluarea acestuia în cadrul formularului principal Proiecte( vizualizare în modul Design View).

Realizarea listei derulante ce permite căutarea rapidă a unui contract se realizează cu ajutorul controlului ComboBox (figura precedentă). În cadrul ferestrei Combo Box Wizard se alege opţiunea „Find a record on my form based on the value I selected in my combo box” (figura următoare). Se aleg câmpurile CodProeict şi DenumireProiect pentru a fi afişate în listă şi se adaugă eticheta vizibilă pe formular.

Fereastra Combo Box Wizard

Selecţia câmpurilor pentru lista derulantă ce

permite căutarea unui proiect

Page 142: Studii de Caz Access 2007

Studii de caz

142

V.b) Realizaţi un formular ce va permite selectarea unui proiect dintr-o listă derulantă şi exportul bugetului acestuia în MS Excel.

Formularul AfisareBugetRaport ce permite exportul bugetului unui proiect în MS Excel

Formularul (denumit AfisareBugetRaport) conţine o listă derulantă (control de tip ComoBox a cărui nume este CmbProiecte) ce afişează codul şi denumirea proiectelor. Evenimentului On Click aferent butonului Btnexport i se va ataşa obiectul MacroExport. Acest obiect realizează următoarea succesiune de activităţi:

• Deschidere interogare (Query) BugetProiect (cerinţa IV.f )

• Selectează doar înregistrările al căror cod de proiect este egal cu cel selectat în lista derulantă.

• Executa comanda de export în MS EXCEL.

• Închide interogarea BugetProiect.

Studiu individual:

a) Să se realizeze un formular ce permite actualizarea cheltuielilor materiale. b) Să se realizeze un formular de tip PivotChart ce va prezenta grafic structura cheltuielilor în cadrul proiectelor. (Observaţie Sursa formularului este interogarea din cadrul cerinţei IV.f )

Page 143: Studii de Caz Access 2007

Baze de date Access 2007

143

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Afişarea bugetului pentru un anumit proiect ales dintr-o listă derulantă.

Sursa raportului o constituie interogare (Query) BugetProiect (cerinţa IV.f ). În cadrul raportului vor fi afişate toate câmpurile sursei de date. Datelor vor fi afişate grupat în funcţie de codul proiectului şi de tipul cheltuielilor.

Fereastra Report Wizard în care se selectează

sursa raportului şi câmpurile acestuia

Nivelurile de grupare în cadrul raportului

Pentru calculul totalului cheltuielilor pe fiecare tip în cadrul secţiunii Tip Header se foloseşte o caseta text( control de tip TextBox) pentru care valoarea proprietăţii

ControlSource este . Aceiasi proprietate va avea şi controlul caseta text folosit în cadrul sectiunii CodProiect Header dar efectul va fi calculul valorii costului total pe proiect (figura următoare).

Page 144: Studii de Caz Access 2007

Studii de caz

144

Numerotarea tipurilor de cheltuielilor în cadrul unui proiect se va face cu ajutorul unul control de tip TextBox pentru care proprietatea ControlSource are valoarea =1, iar proprietatea Running Sum are selectată valoarea OverGroup.

Raportul “Buget Proiecte” vizualizat în modul Design View

Deschiderea raportului se realizează la declanşarea evenimentului On Click al butonului btnAfisRaport de pe formularul AfisareBugetRaport( realizat în cadrul cerinţei V b). Pentru a se afişa doar datele referitoare la proiectul selectat în lista derulantă de pe formular, proprietatea Filter a raportului va avea valoarea

.

În cazul în care nu exista informaţii despre bugetul unui proiect se va afişa un mesaj de eroare, raportul numai fiind afişat. Se va folosi în acest scop evenimentul NoData al raportului pentru care se va adăuga următorul cod VBA.

Private Sub Report_NoData(Cancel As Integer) ‘afisare mesaj de eroare

MsgBox "Nu exista informatiile cerute!" ‘anulare afişare raport

Cancel = 1

End Sub

Page 145: Studii de Caz Access 2007

Baze de date Access 2007

145

VI.b) Afişarea listei resurselor umane implicate în proiecte.

Sursa raportului o constituie tabelul ResurseUmane. În secţiunea Report Footer se va calcula numărul de înregistrări afişate în raport cu ajutorul unei casete text (control

TextBox) pentru care proprietatea ControlSource are valoarea

Raportul ce afişează lista resurselor deschis în modul Design View

Studiu individual:

a) Să se realizeze un raport ce va afişa calendarul începerii proiectelor

b) Să se realizeze un raport ce va afişa lista resurselor materiale pe categorii

Page 146: Studii de Caz Access 2007

Studii de caz

146

Bază de date pentru evidenţa personalului

Se doreşte realizarea unei baze de date pentru evidenţa salariaţilor. Angajaţii vor fi înregistraţi o singură dată în cadrul bazei de date. Pentru identificare fiecare angajat va primi un cod unic denumit

marca angajat. În baza de date se vor memora numele, data naştere, telefonul, vârsta. Salariu de încadrare poate varia lunar, reţinându-se data modificării şi noul cuantum al salariului. Venitul lunar net este obţinut prin diminuarea salariului de încadrare cu eventuale reţineri aferente acelei luni. O categorie de reţineri poate să se aplice mai multor salariaţi. Reţinerile sunt un procent din salariul de încadrare şi sunt specifice fiecărui salariat. Se vor retine în baza de date denumirea reţinerii, procentul reţinerii precum şi perioada pentru care se aplică (data început, data de sfârşit). Fiecare categorie de reţinere memorată în baza de date se va codifica. Angajaţi sunt organizaţi în departamente. Departamentele vor avea un cod unic folosit pentru identificare. Angajaţii pot să lucreze în decursul timpului în cadrul unui singur departament sau a mai multora. Trebuie reţinută în baza de date data începerii activităţii pentru fiecare departament în care şi-a desfăşurat sau îşi desfăşoară activitatea. Alocarea sarcinilor se va face ţinând cont de vechimea angajatului în cadrul departamentului şi de pregătirea profesională a fiecăruia. Pentru fiecare angajat se vor reţine în baza de date detalii legate de pregătirea profesională, adică denumirile studiilor şi stagiilor la care a participat, datele de finalizare şi tipul acestora. Fiecare etapă a pregătirii profesionale a unui angajat va fi identificată cu ajutorul unui cod.

Reguli de gestiune:

• Salariul de încadrare al unui salariat se poate modifica în timp.

• Fiecare salariat poate să nu aibă reţineri sau să aibă mai multe reţineri, o reţinere putându-se aplica mai multor salariaţi ( unei categorii de salariaţi). Procentele de reţinere sunt specifice fiecărui salariat şi se aplică salariului de încadrare.

• Angajaţii pot să lucreze în decursul timpului în cadrul unui singur departament sau a mai multora. în cadrul unui departament pot să lucreze mai mulţi angajaţi

• Un angajat poate avea mai multe studii sau stagii de pregătire.

I. Realizaţi modelul realizaţi al bazei de date şi implementaţi în MS Access

Realizarea modelului relaţional al bazei de date presupune parcurgerea mai multor etape. Plecând de la informaţiile de bază respectiv atributele, pe baza relaţiilor stabilite între acestea (dependenţe funcţionale) se realizează succesiv formele normalizate ale bazei de date (FN1, FN2, FN3). Trebuie stabilite în primul rând atributele elementare şi nerepetitive ce vor constitui baza procesului de normalizare. Deoarece baza de date va fi realizată cu ajutorul ACCESS 2007 se vor folosi noile funcţionalităţi ale acestuia şi se va defini un câmp denumit Fotografie în care se va

VIII

Page 147: Studii de Caz Access 2007

Baze de date Access 2007

147

reţine fişierul ce conţine fotografia salariatului. Pe baza analizei cerinţelor funcţionale ale bazei de date se identifică următorul dicţionar preliminar al datelor:

Marca, Nume, Telefon, DataNastere, Varsta, Fotografie, SalariuIncadrare, DataModificareSalariuIncadrare, CodRetinere, DenumireRetinere, ProcentRetinere, DataInceputReţinere, DataSfârşitRetinere, SalariuNet, CodDepartament, DenumireDepartament, DataIncepereActivitate, VechimeAngajare, CodPregatireProfesionala, DenumirePregatireProfesionala, DataFinalizare, TipPregatire.

Prin respectarea cerinţelor impuse de către FN1, din dicţionarul atributelor se vor elimina atributele calculate

• Varsta se calculează pentru fiecare persoana în funcţie de data curenta şi data naşterii

• SalariuNet se obţine prin diminuarea salariului de încadrare cu procentele aferente reţinerilor

• VechimeAngajare se calculează pentru fiecare angajat în funcţie de data curentă şi data de începere a activităţii

Respectând cerinţele impuse cheilor primare (unicitate, ireductibilitate) se identifică în cadrul dicţionarul atributelor următoarele atribute candidat din care se vor alege cheile primare:

Atribut Candidat Descriere

Marca Acest atribut are valori unice, identificând în mod unic un angajat

CodRetinere Fiecare reţinere este codificată în mod unic.

Cod Departament La nivelul bazei de date fiecare departament are un cod unic.

CodPregatire Profesionala

Reprezintă atributul pe baza căruia este identificat un stagiu de pregătire profesională.

În etapa următoare se vor identifica dependenţele funcţionale în care determinatul este cheie primară.

La înregistrarea unui angajat i se atribuie un cod unic existând dependenţe funcţionale între atributul Marca şi atributele Nume, Telefon, DataNastere, Fotografie. Salariul de încadrare al unui salariat se poate modifica la anumite date existând dependenţe funcţionale totale între grupul de atribute Marca, DataModificareSalariuIncadrare şi atributul SalariuIncadrare. Pentru reţinerea istoricului etapelor de pregătire profesională fiecare dintre acestea este codificată generând astfel dependenţe funcţională între atributul CodPregatireProfesionala şi atributele DenumirePregatireProfesionala, DataFinalizare, TipPregatire. O etapă de pregătire profesională corespunde unui singur angajat generând dependenţa funcţională între atributul CodPregatireProfesionala şi atributele Marca, Nume, Telefon, DataNastere,

Page 148: Studii de Caz Access 2007

Studii de caz

148

Fotografie. Dependenţa dintre atributul CodPregatireProfesionala şi atributele Nume, Telefon, DataNastere, Fotografie este tranzitivă.

Istoricul reţinerilor fiecărui angajat se va memora cu ajutorul unui tabel pentru care se va alege o cheie surogat IdRetinereSalariat. Există o dependenta funcţională între atributul IdRetinereSalariat şi atributele Marca, CodRetinere, ProcentRetinere, DataInceputReţinere, DataSfârşitRetinere.

Angajaţii pot să lucreze în decursul timpului în cadrul unui singur departament sau a mai multora, un angajat putând reveni la unul din departamentele anterioare.

Istoricul angajării salariaţilor în cadrul departamentelor se va memora în cadrul unui tabel ce va avea drept cheie primară o cheie surogat IdAngajare, existând o dependenţă funcţională între atributul IdAngajare şi Marca, CodDepartament şi DataIncepereActivitate.

Pentru simplificare în scop didactic s-au reprezentat în cadrul matricei dependenţelor funcţionale doar dependenţele funcţionale totale şi dependenţele funcţionale tranzitive în care determinatul este cheie primară, nereprezentându-se dependenţele funcţionale multivaloare sau cele parţiale.

Matricea dependenţelor funcţionale

Page 149: Studii de Caz Access 2007

Baze de date Access 2007

149

Graful dependenţelor funcţionale simple (nu s-au reprezentat dependentele tranzitive)

Analizând dependenţele funcţionale se observă existenţa dependenţelor funcţionale tranzitive. Prin eliminarea acestora se obţin tabelele ce respectă forma normală trei.

Angajat (Marca, Nume, Telefon, DataNastere, Fotografie) IstoricSalariu (DataModSal, Marca, SalariuIncadrare) Retinere (CodRetinere, DenumireRetinere) RetineriSalariat (IdRetinereSalariat, Marca, CodRetinere, ProcentRetinere,

DataInceputRetinere, DataSfarsitRetinere) Departament (CodDepartament, DenumireDepartament) AngajareSalariat (IdAngajare, CodDepartament, Marca,

DataIncepereActivitate) Pregatire (CodPregatireProfesionala, DenumirePregatireProfesionala,

DataFinalizare, TipPregatire, Marca)

Implementarea în ACCESS 2007 a tabelelor şi a relaţiilor dintre acestea

Page 150: Studii de Caz Access 2007

Studii de caz

150

Studiu individual:

Fiecare salariat poate să beneficieze între anumite date de început şi de sfârşit de anumite sporuri sau prime, un spor putându-se aplica unuia sau mai multor salariaţi. Procentele sporurilor sunt specifice fiecărui salariat şi se aplică la salariu de încadrare. La introducerea în baza de date fiecare categorie de sporuri sau prime (ce va avea o denumire) se va codifica. Adăugaţi modelului relaţional tabelul sau tabelele necesare pentru a permite memorarea datelor privind sporurile acordate salariaţilor şi calcului sumelor totale datorate sporurilor.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) Data sfârşit reţinere să fie mai mare decât data început reţinere cu cel puţin 30 zile

Data de început şi de sfârşit sunt atribute ale tabelului RetineriSalariat. Restricţiile ce implică mai mule câmpuri din cadrul aceluiaşi tabel se vor implementa în cadrul proprietăţilor tabelului la Validation Rule (figura următoare).

II.b) Procentul reţinerii să fie cuprins între 0 şi 15 %

Realizarea restricţiei referitoare la domeniul de valori acceptate de atributul ProcentRetinere presupune atribuirea valorii ”between 0 and 0,15” proprietăţii Validation Rule). Proprietatea Validation Text va conţine mesajul personalizat de eroare afişat în cazul nerespectării condiţiei impusă prin Validation Rule (rezolvarea pe pagina următoare).

II.c) Codul departamentelor trebuie să conţină maxim 5 caractere.

Deoarece codul departamentului este limitat doar la 5 caractere proprietatea Field Size a acestui atribut va lua valoarea 5 (rezolvarea pe pagina următoare).

Page 151: Studii de Caz Access 2007

Baze de date Access 2007

151

Proprietăţile atributului ProcentRetinere

Proprietăţile atributului CodDepartament

Studiu individual:

a) Salariul încadrare trebuie să aibă valori între 300 şi 3000. b) Tipul pregătirii să se poate selecta dintr-o listă derulantă ce conţine valorile „facultate”, „liceu”, „masterat”, „doctorat”, „stagiu pregătire”, putându-se adăuga ulterior şi alte valori.

III. Realizaţi interogări (Queries) pentru următoarele cerinţe:

III.a) Să se clasifice salariaţii în funcţie de vârsta în două categorii: persoane până în 35 ani şi persoane peste 35 ani. Se va folosi funcţia IIF pentru a afişa tipul categoriei. Vârsta s-a calculat ca diferenţă între anul curent şi anul naşterii.

III.b) Să se afişeze procentul total al reţinerilor pentru un salariat a cărui marcă se introduce ca parametru şi pentru o anumită dată introdusă tot ca parametru.

O reţinere poate să fie pe o perioadă fixă şi în acest caz se cunosc datele de început sau finalizare sau poate să fie o perioada neterminată, cunoscându-se doar data de început, data sfârşit având valoarea NULL.

Page 152: Studii de Caz Access 2007

Studii de caz

152

III.c) Să se afişeze numărul angajaţilor pe tipuri de pregătire şi ani de finalizare.

Se va folosi o cerere de tip analiză încrucişată (Crosstab Query).

Pe linie (Row Heading) se vor afişa categoriile de pregătire profesională, iar pe coloana (Column Heading) se vor afişa anii de absolvire obţinuţi cu ajutorul funcţiei YEAR(). Numărul de angajaţi se va calcula cu ajutorul funcţiei agregate COUNT.

III.d) Să se afişeze reţinerile care nu aparţin nici unui salariat.

Fiind necesară afişarea tuturor reţinerilor trebuie schimbat tipul legăturii dintre tabelele Retinere şi RetineriSalariat. Din totalul înregistrărilor se vor selecta doar acelea pentru care valoarea atributului Marca este NULL.

Fereastra Join Proprieties

Page 153: Studii de Caz Access 2007

Baze de date Access 2007

153

Studiu individual:

a) Să se afişeze numele şi vârsta în ani a angajaţilor care au lucrat sau lucrează în cadrul departamentului contabilitate. b) Să se afişeze salariaţii care în prima lună a lui 2006 au înregistrat procente totale ale reţinerilor mai mari decât 20%. c) Să se afişeze angajaţii care nu au avut şi nu au înregistrate reţineri.

IV. Realizaţi interogări SQL pentru următoarele cerinţe:

IV.a) Să se afişeze tipurile de pregătire a angajaţilor. Fiecare tip se va afişa doar o singură dată.

SELECT DISTINCT TipPregatire FROM Pregatire IV.b) Să se afişeze prima literă cu care începe numele fiecărui angajat. Se va folosi funcţia MID ce va permite extragerea caracterului de pe prima poziţie a şirului de caractere conţinut de atributul Nume.

SELECT Marca, Angajat.Nume, Telefon, DataNastere, MID ([Nume],1,1) AS Litera FROM Angajat;

IV.c) Să se afişeze salariul de încadrare la o dată introdusă ca parametru pentru un angajat a cărui marcă se va introduce ca parametru.

PARAMETERS Data DateTime, MarcaAng Text ( 255 ); SELECT TOP 1 DataModSal, SalariuIncadrare, Marca FROM IstoricSalariu WHERE DataModSal<=[Data] AND Marca=[MarcaAng] ORDER BY IstoricSalariu.DataModSal DESC;

IV.d) Să se afişeze cronologic pregătirea profesională a fiecărui angajat finalizată după data angajării.

SELECT DISTINCT TipPregatire & " - " & DenumirePregatireProfesionala AS Pregatire, AngajareSalariat.Marca, DataFinalizare FROM Angajat , AngajareSalariat, Pregatire WHERE Angajat.Marca = AngajareSalariat.Marca AND Angajat.Marca = Pregatire.Marca AND DataIncepereActivitate<= DataFinalizare ORDER BY AngajareSalariat.Marca, DataFinalizare;

IV.e) Să se afişeze numărul angajaţilor pentru fiecare tip de pregătire profesională. SELECT TipPregatire, COUNT(Angajat.Marca) AS NumarAngajati FROM Angajat INNER JOIN Pregatire ON Angajat.Marca = Pregatire.Marca GROUP BY TipPregatire;

IV.f) Să se afişeze marca salariaţilor care din anul 2005 au fost angajaţi la mai mult de două departamente.

Page 154: Studii de Caz Access 2007

Studii de caz

154

SELECT Marca, COUNT(CodDepartament) AS NrDepartamente FROM AngajareSalariat WHERE YEAR([DataIncepereActivitate])>=2005 GROUP BY Marca HAVING COUNT(CodDepartament)>=2

IV.g ) Pentru salariatul cu marca 3258 să se înregistreze o majorare salarială, noul salariu fiind 1200, începând 1-11-2007

INSERT INTO IstoricSalariu ( DataModSal, Marca, SalariuIncadrare ) VALUES (#1/11/2007#,"3258",1200)

IV.h) Să se afişeze salariaţii care nu au reţineri în anul 2007. SELECT Angajat.Marca, Nume FROM Angajat WHERE Marca NOT IN (SELECT Marca FROM RetineriSalariat WHERE YEAR([DataInceputReţinere])=2007 AND (YEAR([DataSfârşitRetinere])=2007 OR YEAR([DataSfârşitRetinere]) IS NULL))

IV.i) Să se afişeze printr-o singură interogare istoricul departamentelor în care au lucrat precum şi modificările de salariu pentru fiecare angajat. Evenimentele se vor afişa cronologic.

SELECT IstoricSalariu.Marca, Nume, DataModSal AS Data, SalariuIncadrare, "Modificare Salariu" AS Tip FROM Angajat INNER JOIN IstoricSalariu ON Angajat.Marca = IstoricSalariu.Marca UNION SELECT Angajat.Marca, Nume, DataIncepereActivitate AS Data, "-" AS Sal, "Angajare departament " & DenumireDepartament FROM Departament ,Angajat,AngajareSalariat WHERE Angajat.Marca = AngajareSalariat.Marca AND Departament.CodDepartament = AngajareSalariat.CodDepartament ORDER BY Marca, Data

IV.j) Să se afişeze numele angajaţilor şi salariile de încadrare pentru o anumită dată introdusă ca parametru. Valoarea parametrului se va prelua din controlul txtData al formularul denumit FrmSelectieData. Salariul ce trebuie afişat este cel care corespunde celei mai mari date de modificare ce nu depăşeşte valoarea parametrului

SELECT A.Marca, Nume AS Numele, SalariuIncadrare AS Salariu, DataModSal AS DataModificareSalariu FROM Angajat AS A, IstoricSalariu AS IstoricS WHERE A.Marca=IstoricS.Marca and DataModSal<=[Forms]![FrmSelectieData]![txtData] AND DataModSal>= ALL (SELECT DataModSal FROM IstoricSalariu WHERE IstoricSalariu.Marca=A.Marca)

Page 155: Studii de Caz Access 2007

Baze de date Access 2007

155

Studiu individual:

a) Să se afişeze angajaţii al căror număr de telefon începe cu “0723” b) Să se afişeze departamentul unde lucrează angajatul Popescu Marian în luna curentă precum şi vechimea în cadrul acestui departament. c) Să se afişeze reţinerile care se aplică la mai mult de 5 angajaţi la o anumită dată introdusă ca parametru. d) Să se afişeze cu ajutorul unei singure interogări istoricul salariilor obţinute şi a pregătirii profesionale. Se vor afişa marca, numele, data schimbării salariului sau a finalizării pregătirii şi descrierea activităţii (modificare salariu sau tipul pregătirii).

e) Să se şteargă departamentele unde nu lucrează nici un angajat.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe:

V.a) Realizaţi un formular cu subformular pentru actualizarea tabelei angajat şi actualizarea reţinerilor salariatului. Pentru o anumită dată (valoare implicita fiind data curentă) se va calcula procentul total al reţinerilor.

Formularul ce permite actualizarea angajaţilor şi a reţinerilor acestora

Pentru câmpul CodRetinere de pe subformularul RetineriSalariat se va realiza o listă derulantă din care se va putea selecta reţinerea, afişându-se în formular numele acesteia. Legătura dintre formular şi subformular se va realiza prin intermediul câmpului Marca.

Formularul Angajat prezentat în modul Design View

txtData

Subformular

Apelare funcţie TotalRetineri

Page 156: Studii de Caz Access 2007

Studii de caz

156

Controlul ce va permite introducerea datei este o caseta text (TextBox) pentru care proprietatea Name este txtData, proprietatea Default Value este DATE(), iar proprietatea Format are valoarea ShortDate.

Pentru calculul procentului total al reţinerilor se va realiza funcţia TotalRetineri în cadrul unui obiect modul. Această funcţie va avea ca argumente marca angajatului şi data pentru care se doreşte calcului procentului total al reţinerilor. În cadrul funcţiei se vor declara doua variabile, una de tip Recordset şi cealaltă de tip QueryDef ce va permite deschiderea interogării ProcentTotalRetineriAngajat, obiect ce este descris în cadrul cerinţei III.b.

Function TotalRetineri(marca As String, data As Date) As Double ‘se declara o variabila de tip QueryDef şi una de tip Recordset

Dim qRetineri As QueryDef Dim rs As Recordset ‘se iniţializează variabila qRetineri cu obiectul de tip interogare ProcentTotalRetineriAngajat

Set qRetineri = CurrentDb.QueryDefs("ProcentTotalRetineriAngajat") ‘se atribuie valorile pentru parametrii interogării

qRetineri.Parameters("data") = data qRetineri.Parameters("MarcaAngajat") = marca ‘se iniţializează obiectul de tip recordset asociat interogării

Set rs = qRetineri.OpenRecordset If Not rs.EOF Then ‘dacă există înregistrări ce corespund cerinţelor, funcţia va returna valoarea atributului PTotal

TotalRetineri = rs("PTotal")

Else ‘dacă nu există înregistrări ce corespund cerinţelor, funcţia va returna valoarea 0

TotalRetineri = 0

End If

End Function

Pe formular se va apela funcţia în cadrul proprietăţii ControlSource a unui control caseta text, având drept argumente Marca şi txtData (figura de mai sus).

V.b) Realizaţi un formular pentru actualizarea tabelei reţineri.

Pentru realizarea acestui formular se va accesa opţiunea Form Wizard din cadrul grupului de butoane Forms din meniul Create. Sursa formularului o constituie tabelul Retinere, iar aşezarea înregistrărilor în formular va fi tabelară.

Page 157: Studii de Caz Access 2007

Baze de date Access 2007

157

Alegerea tabelului sursă pentru formular

Alegerea modului de afişare a înregistrărilor în

cadrul formularului

Formularul obţinut permite adăugarea, modificarea şi ştergerea înregistrărilor din tabelul Retinere.

Formular ce permite actualizarea reţinerilor

Studiu individual:

a) Realizaţi un formular cu subformular pentru actualizarea tabelei pregătire profesională.

b) Realizaţi un formular pentru actualizarea tabelei departamente.

Page 158: Studii de Caz Access 2007

Studii de caz

158

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Să se realizeze un raport ce afişează situaţia reţinerilor pentru o lună selectată în cadrul unei liste derulante (figura următoare).

Pentru realizarea formularul FrmSelectieData se va crea un obiect de tip formular cu ajutorul opţiunii Create Design Form din grupul Forms al meniului Create. Pe acest formular se va adăuga un control de tip caseta text pentru care proprietatea Format va avea valoarea “mm/yyyy”, proprietatea Name va fi txtData. Pentru a afişa în mod implicit data curentă proprietatea Default Value a casetei text va fi egala cu DATE().

Următorul pas îl constituie realizarea raportului având ca sursă interogarea descrisă la cerinţa (IV.j).

Raportul ce afişează situaţia reţinerilor salariaţilor pentru luna selectată în listă

Preluarea datei din formular se va face folosind numele formularului şi al controlului conţinut de acesta ce conţine valoarea datei în următorul format [Forms]![NumeFormular]![NumeControl]. în cazul nostru referirea se va face în felul următor [Forms]![FrmSelectieData]![txtData]). Pentru afişarea datei în format luna/an se va folosi funcţia FORMAT având ca parametru “mm/yyyy”.

Pentru calculul reţinerilor fiecărui salariat se va adăuga în secţiunea Detail a raportului un control de tip caseta text (TextBox) pentru care proprietatea Control Source se va apela funcţia TotalRetineri descrisă la cerinţa (V.a) având ca argumente marca angajatului şi valoarea datei preluată din formular astfel: =TotalRetineri([Marca];[Forms]![FrmSelectieData]![txtData]).

Pentru proprietatea Name a acestui control se va stabili valoarea ProcentRetinere. Afişarea valorii sumei reţinerii pentru fiecare salariat se va realiza cu ajutorul unui control de tip caseta text având proprietatea Control Source egală cu

Page 159: Studii de Caz Access 2007

Baze de date Access 2007

159

=[ProcentRetinere]*[Salariu]. Salariul net se va afişa în cadrul unei casete text având proprietatea Control Source egală cu =(1-[ProcentRetinere])*[Salariu].

Raportul ce afişează situaţia reţinerilor deschis în modul Design View

Pentru a realiza legătura dintre formular şi raport se va realiza un obiect de tip Macro denumit MacroParametru. Structura acestuia este prezentată în figura următoare. Afişarea coloanei Macro Name în modul Design al obiectului macro denumit MacroParametru, se va apăsa butonul Macro Names din categoria Show/Hide a meniului Design.

Structura obiectului de tip macro denumit MacroParametru

Prima categorie Macro Name din structura obiectului Macro va realiza deschiderea formularului şi va fi ataşat evenimentului On Open al raportului. A doua categorie Macro Name va realiza închiderea formularului ce permite preluarea parametrului fiind ataşat evenimentului On Close a raportului.

Fereastra de proprietăţi a raportului

Ataşarea acestor obiecte de tip macro evenimentelor On Open şi On Close ale raportului au ca efect deschiderea formularului la deschiderea raportului şi respectiv închiderea formularului o dată cu închiderea raportului.

Următoarele două categorii Macro Name se vor ataşa evenimentelor On Click butoanelor Afişează respectiv Anulează din formularul FrmSelectieData. Apăsarea butonului Afişează din cadrul formularului FrmSelectieData are ca efect ascunderea acestuia ca urmare a setării valorii proprietarii Visible a formularului la valoarea No prin intermediul obiectului macro MacroParametru.

Page 160: Studii de Caz Access 2007

Studii de caz

160

VI.b) Să se realizeze un raport ce afişează numele şi telefonul tuturor angajaţilor grupaţi alfabetic .

Situaţia va afişa marca, numele şi telefonul angajaţilor grupaţi în funcţie de prima literă a numelui.

Raportul are ca sursă interogarea descrisă în cadrul cerinţei (IV.b). Se va realiza gruparea în funcţie de atributul Litera. Datele se vor afişa pe două coloane. În cadrul figurii următoare sunt prezentate proprietăţile modificate ferestrei Page Setup pentru afişarea pe două colane a înregistrărilor din raport.

Prezentarea raportului în modul Design View

Fereastra Page Setup ce permite afişarea înregistrărilor pe două coloane

Studiu individual:

a) Să se realizeze un raport ce afişează istoricul salariilor pentru fiecare salariat.

Page 161: Studii de Caz Access 2007

Baze de date Access 2007

161

b) Să se realizeze un raport cu subraport ce afişează toate etapele pregătirii profesionale pentru fiecare angajat. Se va afişa numărul de stagii de pregătire pentru fiecare angajat.

Page 162: Studii de Caz Access 2007

Studii de caz

162

Bază de date pentru evidenţa contractelor cu clienţii la o firmă de consultanţă

Se doreşte realizarea unei baze de date pentru o firmă ce are ca obiect de activitate acordarea de consultanţă în domeniul IT. La firmă lucrează mai mulţi angajaţi pentru care se cunosc: codul numeric personal (CNP), numele, data naşterii, data angajării, adresa de e-mail şi competenţele în domeniul IT ale angajatului Competenţele se referă la abilităţile angajatului în diverese ramuri ale domeniului IT (de exemplu programare, administrare reţele, baze de date, etc.) şi sunt codificate într-un nomenclator la nivelul firmei. Fiecărui angajat i se memorează o fotografie scanată, precum şi CV-ul redactat ca document Microsoft Word.

Clienţii cărora le sunt oferite servicii de consultanţă sunt persoane juridice pentru care se cunosc: cod unic de identificare (CUI), denumire firmă, localitate, adresa, şi telefon contact. Cu clienţii se întocmesc contracte care sunt numerotate, datate şi în care se specifică valoarea contractului şi termenul de finalizare. Pe perioada de desfăşurare a unui contract angajaţii firmei se deplasează la sediul clientului şi întocmesc fişe zilnice de pontaj pe care consemnează numărul de ore lucrate la client şi contractul pentru care s-a lucrat. Fişele de pontaj sunt datate şi codificate în mod unic la nivelul firmei.

• Un contract se încheie cu un singur client, dar există clienţi cu care s-au încheiat mai multe contracte.

• La un contract pot lucra mai muţi angajaţi, iar un angajat poate lucra la mai multe contracte.

• O fişă de pontaj se întocmeşte pentru orele lucrate într-o singură zi, la un singur client, pentru un anumit contract (angajaţii care, în decursul aceleiaşi zile lucrează pentru două contracte diferite, vor întocmi fişe de pontaj diferite.

• Un angajat poate avea mai multe competenţe în domeniul IT.

I. Realizaţi modelul relaţional al bazei de date şi implementaţi în MS Access

Pe baza informaţiilor din enunţul problemei şi a regulilor de gestiune, se poate constitui dicţionarul atributelor şi se pot analiza dependenţele funcţionale dintre atribute. Aceste aspecte sunt redate sintetic prin intermediul matricei dependenţelor funcţionale. Observaţie: Numele unora dintre atribute au fost prescurtate (de exemplu denumire firmă client � DenClient, codificare competenta � CodComp, etc.).

IX

Page 163: Studii de Caz Access 2007

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 1 CNP 1 1 1 1 1 1 2 Nume 3 DataNastere 4 DataAngajare 5 MailAngajat 6 Competenta 7 CodComp 1 8 Foto 9 CV 10 CUI 1 1 1 1 11 DenClient 12 OrasClient 13 AdresaClient 14 TelefonClient 15 NrContract 1 1t 1t 1t 1t 1 1 1 16 DataContract 17 ValoareContract 18 TermenFinalizare 19 CodFisaPontaj 1 1t 1t 1t 1t 1t 1t 1 1t 1t 1t 1t 1 1t 1t 1t 1 1 20 DataPontaj 21 OreLucrate

Observaţii:

• Potenţialele chei primare (atributele determinante) sunt evidenţiate în prima coloană a matricei. • Dependenţele funcţionale au fost marcate cu simbolul 1, iar cele tranzitive cu 1t. • Câmpurile în care urmează să fie memorate fişiere în baza de date (fotografiile şi CV-urile angajaţilor) nu pot fi luate în

calcul ca potenţiale chei primare (vor fi câmpuri de tip Attachment în baza de date).

Page 164: Studii de Caz Access 2007

Studii de caz

164

După marcarea dependenţelor funcţionale se poate contura următorul model relaţional al bazei de date (cheile primare sunt subliniate cu linie continuă, iar cheile externe cu linie punctată)1:

ANGAJATI (CNP, Nume, DataNastere, DataAngajare, MailAngajat, CV, Foto)

COMPETENTE (CodComp, Competenta)

CLIENTI (CUI, DenClient, OrasClient, AdresaClient, TelefonClient )

CONTRACTE (NrContract, CUI, DataContract, ValoareContract, TermenFinalizare)

PONTAJE (CodFisaPontaj, CNP, CUI, NrContract, DataPontaj, OreLucrate)

Studiind legăturile existente între tabele şi revenind la enunţul problemei, se constată că nu există suficiente legături cheie primară – cheie externă pentru a determina care sunt competenţele fiecărui angajat.

Întrucât între cheile primare ale tabelelor Angajati şi Competente există dependenţe multivaloare reciproce (un angajat poate avea competenţe multiple, iar o competenţă poate fi deţinută de mai mulţi dintre angajaţi) se va adăuga modelului un tabel intermediar care să asigure legătura. Am numit acest tabel Angajati_Competente

Angajati_Competente (CNP, CodComp)

Rezultatul implementării modelului relaţional în Microsoft Access 2007 este prezentat în figura următoare:

1 Conform metodologiei, se crează un tabel pentru fiecare atribut determinant marcat în matricea dependenţelor funcţionale şi atributele determinate netranzitiv de către acesta.

Page 165: Studii de Caz Access 2007

Baze de date Access 2007

165

Studiu individual:

1. Se doreşte extinderea modelului bazei de date pentru a face posibilă evidenţa încasărilor pe care firma le realizează în contul contractelor cu clienţii. Clienţii plătesc contravaloarea contractelor prin ordine de plată. Pe fiecare ordin de plată se consemnează numărul ordinului de plată, data efectuării plăţii şi suma achitată de client. În cele mai multe cazuri, contravaloarea unui contract este achitată în tranşe, firma primind mai multe ordine de plată pentru acelaşi contract. Adăugaţi modelului relaţional tabelul, sau tabelele, ce permit memorarea datelor privind sumele pe care firma le primeşte pentru activitatea desfăşurată.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi: II.a) Se doreşte ca, în loc de acronimul CNP, la introducerea datelor în tabelul Angajati să se afişeze pentru acest câmp titlul Cod numeric personal.

În acest sens se va modifica proprietatea Caption:

II.b) Pentru codurile fişelor de pontaj s-a stabilit un standard la nivelul firmei, astfel încât orice cod va fi alcătuit din: 3 caractere alfanumerice, urmate simbolul “.“, apoi de 6 cifre urmate de simbolul “.” şi, în final, doua litere.

Pentru a preveni nerespectarea acestui format impus, se va modifica la nivelul câmpului CodFisaPontaj proprietatea Input Mask astfel:

Page 166: Studii de Caz Access 2007

Studii de caz

166

II.c) Pentru fiecare angajat se va verifica dacă a împlinit vârsta de 18 ani în momentul angajării.

Întrucât acestă validare se realizează prin compararea unor valori din câmpuri diferite (data naştere şi data angajare), regula va fi implementată la nivelul validărilor tabelului. În acest scop se va deschide tabelul în modul Design şi se va apăsa butonul Properties din bara de instrumente.

Studiu individual:

Impuneţi următoarele reguli de validare la nivel de câmp sau tabel: a) Numărul de ore completat de un angajat pe o fişă de pontaj nu poate depăşi 10. b)Termenul de finalizare a contractelor nu poate fi anterior datei semnării contractului c) Valoarea contractelor se va încadra între 1.000 lei şi 900.000 lei. d) Valorile posibile pentru câmpul OrasClient se vor limita la lista Bucuresti, Ploiesti, Brasov, Constanta. e) Datele de pe fişele de pontaj nu pot fi ulterioare datei curente (data sistemului).

Validare la nivel de tabel

Page 167: Studii de Caz Access 2007

Baze de date Access 2007

167

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afişeze lista angajaţilor care nu au realizat până în prezent nici un pontaj la contractele încheiate de firmă în anul 2009.

Într-o primă etapă se va realiza o interogare pe baza tabelelor Pontaje şi Contracte pentru a obţine o listă cu CNP-urile angajaţilor care au lucrat la contractele din anul 2009. Această interogare va fi salvata cu numele “Pontaje la contracte din 2009”.

Ulterior se va realiza o a doua interogare ce va avea ca sursă tabelul Angajaţi şi interogarea precedentă.

Observaţie: Pentru a evidenţia care sunt angajaţii care figurează în tabelul Angajati şi nu apar pe fişele de pontaj obţinute prin interogarea “Pontaje la contracte din 2009” se va specifica, mai întâi, preluarea în setul de rezultate a tuturor angajaţilor din tabel, prin modificarea proprietăţilor legăturii (Join Properties). Ulterior, se va completa în câmpul de criterii condiţia Is Null pentru câmpul CodFisaPontaj.

Page 168: Studii de Caz Access 2007

Studii de caz

168

III.b) Să se calculeze total ore pontate de fiecare angajat în decembrie 2008 la clientul ABC SA.

Observaţie: Pentru câmpul DataPontaj, în rândul Total al interogării, s-a specificat opţiunea Where, întrucât acest câmp este necesar doar pentru impunerea condiţiilor, nu şi pentru gruparea datelor.

III.c) Să se calculeze pentru fiecare salariat vechimea în muncă şi totalul orelor pontate. Pentru cei cu vechime peste 1 an şi mai mult de 100 de ore pontate se va afişa într-un câmp calculat numit Observatii textul “Propus pentru prima”.

Observaţie:Pentru câmpul Observatii, în rândul Total al interogării, s-a utilizat opţiunea Expression deoarece este un câmp calculat pe baza altor câmpuri rezultate din agregarea datelor.

Observatii: IIf([TotalOre]>100 And [Vechime]>1; "Propus pentru prima" ; “ “)

Page 169: Studii de Caz Access 2007

Baze de date Access 2007

169

III.d) Să se afişeze numărul total de ore pontate pentru angajaţii care au mai mult de 5 competenţe.

Observaţie:

Această cerinţă, pentru a conduce la rezultate corecte, este necesar să fie rezolvată prin două interogări succesive.

Într-o primă etapă se va determina care sunt angajaţii care au mai mult de 5 competenţe (se va salva interogarea cu numele Angajati Selectati)

A doua interogare va avea ca sursă tabelul de Pontaje şi interogarea precedentă:

Observaţie:Dacă interogarea s-ar fi rezolvat printr-un singur Query, rezultatele nu ar fi fost cele corecte întrucât, datorită legăturilor de tip 1-n între tabelul Angajati şi tabelele Pontaje, respectiv Angajati_Competente, numărul de competenţe calculat nu ar fi fost cel real (competenţele s-ar fi multiplicat în funcţie de numărul de pontaje).

Page 170: Studii de Caz Access 2007

Studii de caz

170

Studiu individual:

Realizaţi următoarele interogări : a) Calculaţi totalul de ore pontate pe fiecare contract în ultima lună . b) Calculaţi numărul mediu de ore pontate de fiecare angajat în fiecare lună a anului 2008. Interogarea va fi de tip CrossTab Query. c) Printr-o interogare de tip Make Table

IV. Realizaţi interogări SQL pentru următoarele cerinţe:

IV.a) Care sunt clienţii firmei din oraşele Iaşi sau Braşov care nu au telefonul memorat în baza de date ?

SELECT DenClient FROM CLIENTI WHERE (OrasClient="Iasi" OR OrasClient="Brasov") AND TelefonClient Is NULL

Observaţie: A fost necesară utilizarea parantezelor rotunde pentru a încadra cele două condiţii legate prin operatorul OR pentru a indica prioritatea criteriilor din clauza WHERE. O soluţie alternativă ar fi fost utilizarea operatorului IN (“Iasi”, “Brasov”)

IV.b) Se doreşte atribuirea unui cod la nivelul firmei pentru fiecare contract. Acest cod va fi unul alfanumeric şi va conţine: primele 3 litere din numele oraşului din care provine clientul, caracterele de pe pozitia a doua si a treia din denumirea clientului, numărul de cifre care alcătuiesc valoarea contractului şi, în final, ultimele două cifre din anul în care s-a încheiat contractul .

SELECT CONTRACTE.NrContract, Left(OrasClient,2) & Mid(DenClient,2,2) & Len(ValoareContract) & Right(Year(DataContract),2) AS CodContract FROM CLIENTI INNER JOIN CONTRACTE ON CLIENTI.CUI = CONTRACTE.CUI;

Observaţie: Pentru informaţii suplimentare privind funcţiile LEFT, RIGHT, MID şi LEN se recomandă consultarea sistemului de asistenţă (Help) oferit de Microsoft Access.

IV.c) Care sunt angajaţii care au înregistrat pontaje la contractul cu numerele 101 sau 102. Lista se va ordona alfabetic.

SELECT DISTINCT Nume FROM ANGAJATI INNER JOIN PONTAJE ON ANGAJATI.CNP=PONTAJE.CNP WHERE NrContract in (3,4) ORDER BY NUME ASC

Observaţie: Clauza DISTINCT a fost utilizată, imediat după instrucţiunea SELECT pentru a preîntâmpina apariţia în lista de rezultate a unui angajat de mai multe ori (pentru fiecarre pontaj realizat).

Page 171: Studii de Caz Access 2007

Baze de date Access 2007

171

IV.d) Să se afişeze numele şi adresele cleinţilor la care a realizat pontaje angajatul “Ion Vasile”.

SELECT DISTINCT DenClient, OrasClient, AdresaClient FROM (ANGAJATI INNER JOIN PONTAJE ON ANGAJATI.CNP=PONTAJE.CNP) INNER JOIN CLIENTI ON PONTAJE.CUI=CLIENTI.CUI WHERE Nume="Ion Vasile""

IV.e) Să se afişeze numele angajaţilor care nu figurează cu nicio competenţă în baza de date.

SELECT Nume FROM ANGAJATI LEFT JOIN ANGAJATI_COMPETENTE ON ANGAJATI.CNP=ANGAJATI_COMPETENTE.CNP WHERE ANGAJATI_COMPETENTE.CNP IS NULL

Observaţie: Utilizarea LEFT JOIN în loc de INNER JOIN permite preluarea tuturor angajaţilor, indiferent dacă CNP-ul acestora figurează în tabelul ce conţine cheia externă. O altă variantă de rezolvare este următoarea:

SELECT Nume FROM ANGAJATI WHERE CNP NOT IN (SELECT CNP FROM ANGAJATI_COMPETENTE)

IV.f ) Calculaţi numărul total de ore pontate pentru fiecare client, la fiecare contract. SELECT CLIENTI.CUI, DenClient, NrContract, SUM(OreLucrate) As [Total ore] FROM CLIENTI INNER JOIN PONTAJE ON CLIENTI.CUI=PONTAJE.CUI GROUP BY CLIENTI.CUI, DenClient, NrContract

IV.g) Să se afişeze lista angajaţilor şi numărul de fişe de pontaj întocmite de fiecare pentru cei care nu au cumulat 50 de ore pontate.

SELECT ANGAJATI.CNP, Nume, COUNT(Fisa) AS [Total fise intocmite] FROM ANGAJATI INNER JOIN PONTAJE ON ANGAJATI.CNP=PONTAJE.CNP GROUP BY ANGAJATI.CNP, Nume HAVING SUM(OreLucrate)<50

Observaţie:

• Condiţia ce implică utilizarea funcţiei agregat SUM a condus la necesitatea utilizării clauzei HAVING.

IV.h) Să se modifice interogarea precedentă pentru a elimina din lista de rezultate angajaţii care au intocmit fişe de pontaj în ultimele două zile.

La interogare se va adăuga clauza WHERE care va conţine următoarea subinterogare: SELECT ANGAJATI.CNP, Nume, COUNT(Fisa) AS [Total fise intocmite] FROM ANGAJATI INNER JOIN PONTAJE ON ANGAJATI.CNP=PONTAJE.CNP WHERE ANGAJAT.CNP NOT IN (SELECT CNP FROM PONTAJ WHERE DataPontaj>Date()-10 ) GROUP BY ANGAJATI.CNP, Nume HAVING SUM(OreLucrate)<50

Page 172: Studii de Caz Access 2007

Studii de caz

172

IV.i) Să se şteargă din baza de date clienţii cu care nu există înregistrate contracte după data de 1 ianuarie 2000.

DELETE * FROM CLIENTI WHERE CUI NOT IN (SELECT CUI FROM CONTRACTE WHERE DataContract>#1/1/2000#)

IV.j) Care sunt angajatii care au înregistrat pontaje pentru contractul cu cea mai mare valoare ?

SELECT Nume FROM ANGAJATI INNER JOIN PONTAJE ON ANGAJATI.CNP = PONTAJE.CNP WHERE PONTAJE.NRcontract IN (SELECT NrContract FROM CONTRACTE WHERE ValoareContract>=ALL(SELECT ValoareContract FROM Contracte))

Studiu individual:

a) Să se calculeze un discount la valoarea fiecărui contract astfel: pentru contractele mai vechi de 90 de zile 1% din valoare, pentru cele cu vechime între 30 şi 90 de zile 2% din valoare, iar pentru celelalte 5%. b) Să se obţină lista angajaţilor care au realizat pontaje la contractele clientului START SRL în ultima lună. c) Să se şteargă pontajele aferente contractului cu numărul 100. d) Să se şteargă pontajele aferente contractelor cu clientul “ABC SRL”. d) Să se identifice care sunt angajaţii care au totalizat mai mult de 100 de ore lucrate. e) Să se calculeze valoarea totală a contractelor pe fiecare client.

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular cu subformular pentru a vizualiza pentru fiecare client lista contractelor. Se va adăuga pe formular o listă de căutare a clienţilor şi se va calcula valoarea totală a contractelor pe subformular. Tot pe subformular, pentru fiecare contract se va calcula durata în zile a fiecărui contract (diferenţa între termenul finalizării contractului şi data semnării contractului). Contractele cu o durata mai mare de 90 de zile se vor afişa pe fundal verde.

Se va realiza un buton de comandă pe subformular prin intermediul căruia să se poată vizualiza lista pontajelor la contractul respectiv, sub forma unui raport..

Page 173: Studii de Caz Access 2007

Baze de date Access 2007

173

Formularul realizat pe baza tabelului Clienţi, cu subformular având ca sursă tabelul Contracte, este prezentat în figura următoare în modul Design.

După cum se poate observa, pe subformular a fost adăugată în secţiunea Detail o casetă de tip TextBox (txtDurata), iar proprietatea Control Source pentru această casetă conţine formula de calcul pentru durata contractului exprimată în zile (=[TermenFinalizare]-[DataContract]).

Pentru această casetă s-a stabilit formatare condiţională solicitată în enunţul problemei (contractele cu durată peste 90 de zile se vor afişa pe fundal verde). În acest sens se va selecta caseta txtDurata şi, din bara de instrumente, se va apăsa

butonul

O altă casetă de tip TextBox (txtSuma) a fost plasată în subsolul subformularului. Pentru această casetă, proprietatea Control Source conţine expresia necesară calculării valorii totale a contractelor: =Sum(ValoareContract).

Lista de căutare pe formular după numele clientului (comboCauta) a fost realizată cu ajutorul programului wizzard. Figurile următoare ilsustrează succint paşii de ce trebuie parcurşi pentru realizarea unui ComboBox de căutare:

Name:TxtDurata

Name:TxtSuma

Name: btnPontaj

Name: comboCauta

Name: NrContract

Page 174: Studii de Caz Access 2007

Studii de caz

174

1. Se specifică faptul că se doreşte ca viitoare casetă tip ComboBox să aibă rol de căutare (se va genera automat codul VBA pentru căutarea înregistrărilor după elementul selecta în listă)

2. Se selectează câmpurile ce vor constitui sursa listei (se va genera automat o instrucţiune SQL de tip SELECT).

3. Se pot ajusta coloanele casetei de tip ComboBox.

4. Se precizează textul ce va fi afişat prin intermediul unui control de tip Label poziţionat pe formular în dreapta casetei de tip Combo Box.

Înainte de a realiza butonul btnPontaj în secţiunea Detail de pe subformular, cu rolul de a afişa o listă a pontajelor pentru contractul selectat, se va realiza lista pontajelor

Page 175: Studii de Caz Access 2007

Baze de date Access 2007

175

sub forma unui raport având drept sursă tabelele Pontaje şi Angajati. Raportul este prezentat în figura următoare în modul Design:

După cum s-a precizat, raportul va afişa toate fişele de pontaj, de pe toate contractele, însoţite de numele angajaţilor care le-au întocmit. Filtrarea pontajelor după numărul contractului selectat pe subformular (caseta TextBox se numeşte NrContract) se va realiza prin instrucţiunea VBA ce se declanşează în momentul apăsării butonului.

Private Sub btnPontaj_Click()

DoCmd.OpenReport "Raport Pontaje", acViewPreview , , "NrContract = " & NrContract

End Sub

Observaţie: Argumente instrucţiunii OpenReport sunt următoarele OpenReport <nume raport>, <mod de vizualizare>, [numele unui filtru], [condiţie de filtrare a datelor de pe raport]

Întrcât instrucţiunea utilizată în exemplu nu utilizează cel de-al treilea argument, ci precizează direct condiţia, în exemplu apar două virgule succesive după modul de vizualizare a raportului.

Studiu individual:

Să se realizeze următoarele formulare: a) Formular pentru tabelul Angajati cu subformular având ca sursă tabelul Pontaje. Se va calcula total ore pontate de către fiecare angajat în subsolul subformularului şi se va adăuga o listă de căutare a angajaţilor pe formularul principal b) Formular pentru tabelul Contracte cu subformular având ca sursă tabelul Pontaje. Se va cacula pentru fiecare contract numărul total de ore pontate, iar pe formularul principal codurile clienţilor (CUI) se vor selecta prin intermediul unei casete de tip Combo Box ce va conţine atât codurile cât şi numele clienţilor

Page 176: Studii de Caz Access 2007

Studii de caz

176

Bază de date pentru evidenţa activităţii unei clinici medicale

Se doreşte realizarea unei baze de date pentru gestiunea activităţii unei clinici medicale (din cadrul unui spital). Clinica este formată din mai multe secţii, fiecare secţie dispunând de un anumit număr de săli (pentru internarea şi tratamentul pacienţilor). Fiecare secţie din cadrul clinicii este identificată printr-un cod şi are o denumire. Unele secţii au posibilitatea de a accepta urgenţe, altele nu. O sală aparţine unei secţii, are un număr, este situată la un anumit etaj (din cele cinci ale clădirii) şi este dotată cu un anumit număr de paturi.

Personalul care deserveşte clinica este format din două categorii principale de angajaţi: medici şi asistenţi. Pentru fiecare medic se cunosc: valoarea identificatorului unic (codul), numele, prenumele, gradul (stagiar, rezident, primar, specialist etc.), precum şi specialitatea (domeniul său de competenţă). Fiecare medic deserveşte o singură secţie, răspunzând de pacienţii aflaţi în toate sălile respectivei secţii. Medicii sunt singurii angajaţi care au dreptul de a stabili diagnostice pentru pacienţi. Asistenţii care deservesc clinica sunt, de asemenea, identificaţi printr-un cod, înregistraţi cu nume, prenume şi calificare. Unii asistenţi pot avea gradul de asistent şef. Un asistent deserveşte anumite săli, existând situaţia în care mai mulţi asistenţi deservesc aceleaşi săli.

Evidenţa pacienţilor clinicii se realizează prin deschiderea unei fişe pentru fiecare pacient. Fişa pacientului are un număr unic şi conţine datele de identificare ale pacientului: nume, prenume, data naşterii, naţionalitate. Din motive legate de decontarea serviciilor medicale, se face distincţie între pacienţii de naţionalitate română şi cei de alte naţionalităţi. În cazul fiecărei fişe medicale se reţine şi data deschiderii, reprezentând momentul primei prezentări a unui pacient la clinică.

În funcţie de simptomele anunţate, fiecare pacient care se prezintă la clinică este îndrumat către un medic, care realizează o consultaţie şi îi stabileşte un diagnostic. În scopul urmăririi istoricului medical al unui pacient, diagnosticele stabilite de către medici sunt înregistrate în fişa medicală a acestuia. Fiecare diagnostic stabilit are un identificator, înregistrându-se de asemenea data stabilirii, conţinutul diagnosticului (explicaţia acestuia) şi tipul diagnosticului, care descrie condiţiile în care diagnosticul a fost stabilit (de urgenţă, preliminar, interimar, definitiv).

În situaţia în care condiţia pacientului implică spitalizarea acestuia, se va proceda la realizarea unui document (bilet) de internare. Fiecare asemenea document este identificat printr-un cod, specificându-se data internării, data externării, pacientul care beneficiază de internare şi sala unde acesta va sta pe perioada spitalizării. De asemenea, pentru fiecare internare se va stabili (în funcţie de tipul asigurării medicale a pacientului) procentul în care costul internării va fi subvenţionat de către stat (0, 25, 50, 75 sau 100% pentru cazul tratamentelor complet gratuite).

X

Page 177: Studii de Caz Access 2007

Baze de date Access 2007

177

Reguli de gestiune:

• Activitatea unei secţii a clinicii se desfăşoară în mai multe săli

• Fiecare sală din cadrul clinicii aparţine unei singure secţii

• O secţie a clinicii este deservită de mai mulţi medici

• Fiecare medic deserveşte o singură secţie în cadrul clinicii

• Fiecare asistent din personalul clinicii deserveşte mai multe săli

• Fiecare sală din cadrul clinicii este deservită de mai mulţi asistenţi

• Fiecare internare înregistrată se referă la un singur pacient (o singură fişă)

• Un pacient poate beneficia de mai multe internări succesive

• Fiecare internare se realizează într-o singură sală

• În aceeaşi sală se pot realiza mai multe internări (pentru pacienţi diferiţi)

• Fiecare diagnostic înregistrat se referă la un singur pacient (o singură fişă)

• Unui pacient i se pot stabili (în timp) mai multe diagnostice

• Un diagnostic este stabilit de către un singur medic

• Fiecare medic (indiferent de grad) poate stabili mai multe diagnostice

I. Realizaţi modelul relaţional al bazei de date şi implementaţi în MS Access Realizarea modelului relaţional presupune identificarea prealabilă a atributelor care vor intra în componenţa acestui model, precum şi centralizarea lor în forma dicţionarului de atribute. Pentru problema enunţată, dicţionarul de atribute are următorul conţinut (ordonat alfabetic):

DICŢIONAR DE ATRIBUTE

AsistentŞef

Calificare

CodAsistent

CodInternare

CodMedic

CodSectie

DataDeschidere

DataDiagnostic

DataExternare

DataInternare

DataNaştere

DenumireSecţie

EtajSală

Explicaţie

Grad

IDDiagnostic

Naţionalitate

NumărFişă

NumărPaturi

NumărSală

NumeAsistent

NumeMedic

NumePacient

PrenumeAsistent

PrenumeMedic

PrenumePacient

ProcentSubvenţie

Specialitate

TipDiagnostic

Urgenţe

În vederea obţinerii modelului relaţional aferent acestui dicţionar de atribute se va construi matricea dependenţelor funcţionale. Din cauza limitărilor de spaţiu, se va prezenta forma restrânsă a acestei matrice (pe una dintre dimensiuni vor fi specificate doar atributele cu rol de cheie primară, nu întregul conţinut al dicţionarului). În acest scop, se vor marca în listă acele atribute care au rol de identificare în cadrul modelului. Casetele de culoare neagră din cadrul matricei marchează dependenţele funcţionale triviale (faptul că fiecare atribut depinde funcţional de el însuşi). Casetele

Page 178: Studii de Caz Access 2007

Studii de caz

178

de culoare gri marchează dependenţele multivaloare, pe baza cărora nu se pot trage concluzii cu privire la forma finală a modelului relaţional. Marcajul „1T” indică existenţa unei dependenţe funcţionale tranzitive între cheia primară de pe coloană şi atributul corespunzător liniei, iar marcajul „1” indică existenţa unei dependenţe funcţionale directe între cele două elemente menţionate.

ATRIBUTE CHEI PRIMARE

Nr. Denumire 03 04 05 06 16 18 20

01 AsistentŞef 1 02 Calificare 1

03 CodAsistent 04 CodInternare

05 CodMedic 1

06 CodSectie 1T 1 1T 1

07 DataDeschidere 1T 1

08 DataDiagnostic 1 09 DataExternare 1

10 DataInternare 1 11 DataNaştere 1T 1

12 DenumireSecţie 1T 1T 1 1T 1T 13 EtajSală 1T 1

14 Explicaţie 1

15 Grad 1 1T 16 IDDiagnostic

17 Naţionalitate 1T 1 18 NumărFişă 1 1

19 NumărPaturi 1T 1 20 NumărSală 1

21 NumeAsistent 1

22 NumeMedic 1 1T

23 NumePacient 1T 1

24 PrenumeAsistent 1 25 PrenumeMedic 1 1T

26 PrenumePacient 1T 1 27 ProcentSubvenţie 1

28 Specialitate 1 1T

29 TipDiagnostic 1 30 Urgenţe 1T 1T 1 1T 1T

Page 179: Studii de Caz Access 2007

Baze de date Access 2007

179

Modelul relaţional al bazei de date este următorul:

Asistent (CodAsistent, NumeAsistent, PrenumeAsistent, Calificare, AsistentSef)

Internare (CodInternare, DataInternare, DataExternare, NumarFisa, NumarSala, ProcentSubventie)

Medic (CodMedic, NumeMedic, PrenumeMedic, Grad, Specialitate, CodSectie)

Sectie (CodSectie, DenumireSectie, Urgente)

Diagnostic (IDDiagnostic, CodMedic, NumarFisa, DataDiagnostic, Explicatie, TipDiagnostic)

FisaPacient (NumarFisa, DataDeschidere, NumePacient, PrenumePacient, DataNastere, Nationalitate)

Sala (NumarSala, EtajSala, NumărPaturi, CodSectie)

Deserveste (CodAsistent,NumărSala)

În scopul implementării în SGBD Microsoft Access 2007 a modelului relaţional obţinut, este necesară stabilirea tipului de date ce va fi atribuit fiecărui atribut. Opinia autorului cu privire la tipurile de date cele mai potrivite pentru cazul în discuţie este prezentată în tabelul următor:

ATRIBUTE DE TIP NUMERIC (Tipurile NUMBER şi AUTONUMBER) DENUMIRE ATRIBUT TIP DE DATE

CodAsistent Number, Long Integer CodInternare AutoNumber, Long Integer, Random CodMedic Number, Long Integer CodSecţie AutoNumber, Long Integer, Increment EtajSală Number, Byte IDDiagnostic AutoNumber, Long Integer, Random NumărFişă AutoNumber, Long Integer, Random NumărPaturi Number, Byte NumărSală Number, Integer ProcentSubvenţie Number, Byte ATRIBUTE DE TIP ALFANUMERIC (Tipul de date TEXT)

DENUMIRE ATRIBUT LUNGIME (CARACTERE) Calificare 30 DenumireSecţie 40 Explicaţie 255 Grad 20 Naţionalitate 20 NumeAsistent 30 NumeMedic 30 NumePacient 30 PrenumeAsistent 30 PrenumeMedic 30 PrenumePacient 30 Specialitate 20 TipDiagnostic 20 Urgenţe 2

Page 180: Studii de Caz Access 2007

Studii de caz

180

ATRIBUTE DE TIP DATĂ (Tipul de date DATE/TIME) DENUMIRE ATRIBUT TIP DE DATE

DatăDeschidere Date/Time DatăDiagnostic Date/Time DatăExternare Date/Time DatăInternare Date/Time DatăNaştere Date/Time ATRIBUTE DE TIP LOGIC (Tipul de date YES/NO)

DENUMIRE ATRIBUT TIP DE DATE AsistentŞef Yes/No

Notă: Implementarea modelului relaţional în SGBD Access se va realiza fără a utiliza caracterele diacritice specifice limbii române.

În opinia autorului, procesul de definire a atributelor şi alegere a tipurilor de date trebuie completat cu o serie de constrângeri suplimentare, pentru a asigura integritatea şi consistenţa datelor, dar şi pentru a facilita utilizarea bazei de date şi popularea acesteia. În acest sens se va propune şi exemplifica realizarea următoarelor tipuri de restricţii de integritate (constrângeri):

• Atributele Calificare (din tabela Asistent), TipDiagnostic (din tabela Diagnostic), Naţionalitate (din tabela FişăPacient), ProcentSubvenţie (din tabela Internare), Grad şi Specialitate (din tabela Medic), EtajSală (din tabela Sală) şi Urgenţe (din tabela Secţie) au un domeniu de valori bine definit şi, ca urmare, posibilităţile de introducere a datelor ar trebui limitate la lista de valori corespunzătoare fiecărui atribut. Cele două figuri care urmează exemplifică utilizarea instrumentului „LOOKUP” oferit de SGBD Access 2007 pentru realizarea unei liste de valori numerice (în primul caz), respectiv pentru realizarea unei liste de valori alfanumerice (în cel de-al doilea caz). În ambele cazuri, limitarea posibilităţilor de introducere de date la variantele prestabilite s-a realizat cu ajutorul proprietăţii „Limit To List”, care a primit valoarea „Yes”. Stabilirea valorilor predefinite pentru un atribut cu valori numerice (EtajSală):

Page 181: Studii de Caz Access 2007

Baze de date Access 2007

181

Stabilirea valorilor predefinite pentru un atribut cu valori alfanumerice (Urgenţe)

• Pentru atributele DataDiagnostic (din tabela Diagnostic), DataDeschidere (din tabela FişăPacient), DataInternare şi DataExternare (din tabela Internare), se intenţionează furnizarea unei valori implicite (considerată ca potrivită pentru o mare parte din situaţii), urmând ca aceasta să fie modificată liber de către utilizator în situaţiile în care nu este aplicabilă. În cazul primelor trei atribute, această valoare ar fi data curentă a sistemului, iar în cazul celui de-al patrulea (DataExternare), o dată ulterioară datei curente (cu trei zile), stabilită pe baza duratei medii a unei internări. Cea mai simplă metodă de a obţine acest tip de comportament este apelul la funcţia „Date”, care returnează data curentă a sistemului şi plasarea acestui apel în secţiunea „Default Value” a listei de proprietăţi pentru câmpul vizat (figura următoare):

Page 182: Studii de Caz Access 2007

Studii de caz

182

• În scopul de a facilita stabilirea valorilor pentru câmpurile cu rol de cheie externă, instrumentul „LOOKUP” oferit de SGBD Access 2007 poate fi utilizat pentru a afişa în cadrul câmpului-cheie externă toate valorile cheii primare corespunzătoare (toate valorile care respectă integritatea referenţială). În funcţie de situaţie, o asemenea afişare poate include şi alte câmpuri suplimentare, care nu fac parte din cheie dar facilitează înţelegerea valorilor cheii. Afişarea unor câmpuri suplimentare sau ascunderea câmpului cu rol de cheie externă nu afectează în nici un fel relaţiile dintre cele două tabele implicate, fiind doar o metodă de îmbunătăţire a ergonomiei interfeţei. De exemplu, adăugarea numelui şi prenumelui unui medic la codul acestuia poate elimina ambiguităţile în selectarea medicului care a stabilit un diagnostic (cheia externă CodMedic din tabela Diagnostic). În acest caz, proprietatea „Bound Column” stabileşte care dintre coloanele afişate conţine cheia externă propriu-zisă, proprietatea „Column Count” stabileşte numărul de coloane afişate, iar proprietatea „Column Widths” poate fi utilizată pentru a preciza explicit lăţimea fiecărei coloane (sau pentru a ascunde una dintre coloane). În figura următoare este exemplificată. Stabilirea detaliată a numărului şi dimensiunilor coloanelor pentru un câmp cu rol de cheie externă.

Varianta finală a bazei de date, conţinând atât tabelele, cât şi relaţiile dintre acestea, este prezentată în figura următoare:

Page 183: Studii de Caz Access 2007

Baze de date Access 2007

183

Studiu individual:

Completaţi modelul anterior, astfel încât să răspundă şi următoarei cerinţe: Baza de date trebuie să asigure evidenţa situaţiilor în care un pacient este transferat dintr-o cameră în alta pe parcursul internării. Adăugaţi modelului relaţional tabelul sau tabelele necesare pentru a permite memorarea datelor aferente transferurilor suferite de un pacient pe durata unei internări.

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi:

II.a) Deoarece durata medie a unei internări este de trei zile, se doreşte ca valoarea implicită a câmpului DataExternare (din tabela Internare) să fie cu trei zile mai mare decât data curentă a sistemului. În acest scop se va modifica proprietatea „Default Value” a câmpului DataExternare, cu ajutorul funcţiei „Date()”.

Stabilirea valorii implicite a datei de externare este prezentată în figura următoare:

Page 184: Studii de Caz Access 2007

Studii de caz

184

II.b) Deoarece clinica a început să funcţioneze la 1 ianuarie 2003, pentru fişele pacienţilor nu se vor accepta date de deschidere anterioare acestei valori. Condiţia ca valorile câmpului DataDeschidere să fie ulterioare datei de 1.1.2003 se va implementa în cadrul proprietăţii „Validation Rule” a acestui câmp. De asemenea, se recomandă utilizarea proprietăţii „Validation Text” pentru stabilirea unui mesaj de avertizare în cazul în care o valoare introdusă nu respectă regula menţionată anterior.

II.c) În scopul păstrării consistenţei datelor din baza de date, este necesară implementarea unei restricţii la nivel de tabelă care să verifice dacă data externării pentru un pacient este ulterioară datei de internare. Modul de stabilire a restricţiei este prezentat în figura următoare.

Page 185: Studii de Caz Access 2007

Baze de date Access 2007

185

Studiu individual:

a) Deoarece clinica nu dispune de echipamentul necesar tratamentului copiilor sub doi ani, se cere implementarea unei restricţii care să nu permită deschiderea de fişe pentru pacienţi a căror dată de naştere nu este anterioară cu cel puţin doi ani datei curente. b) Se cere modificarea condiţiei de la punctul II.c) pentru situaţia în care nu se acceptă internări pe perioade mai scurte de 3 zile.

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afişeze medicii a căror specialitate este „ORL”

Page 186: Studii de Caz Access 2007

Studii de caz

186

III.b) Să se afişeze numărul de internări înregistrate după 1 ianuarie 2007

III.c) Să se afişeze în ordine alfabetică numele, prenumele şi numărul de diagnostice stabilite, pentru medicii care au stabilit cel puţin trei diagnostice după 1 ianuarie 2007

Page 187: Studii de Caz Access 2007

Baze de date Access 2007

187

III.d) Să se afişeze numărul de asistenţi cu calificarea „Ortopedie” care deservesc fiecare sală

Studiu individual:

a) Să se afişeze numărul de asistenţi cu calificarea „ORL” care deservesc fiecare etaj b) Să se afişeze secţia deservită de cei mai mulţi medici

IV. Realizaţi interogări SQL pentru următoarele cerinţe: IV.a) Să se afişeze secţiile care primesc urgenţe

SELECT Sectie.CodSectie, Sectie.DenumireSectie FROM Sectie WHERE (Sectie.Urgente="DA");

IV.b) Să se afişeze cei mai tineri trei pacienţi SELECT TOP 3 FisaPacient.NumePacient, FisaPacient.PrenumePacient FROM FisaPacient ORDER BY FisaPacient.DataNastere DESC;

IV.c) Să se afişeze numărul de asistenţi cu funcţie de „asistent şef” care deservesc fiecare sală

SELECT Deserveste.NumarSala, Count(Deserveste.CodAsistent) AS NumărAsistenţi FROM Asistent INNER JOIN Deserveste ON Asistent.CodAsistent = Deserveste.CodAsistent WHERE Asistent.AsistentSef=Yes GROUP BY Deserveste.NumarSala;

IV.d) Să se afişeze numărul de pacienţi născuţi după 2000 SELECT Count(FisaPacient.NumarFisa) AS CountOfNumarFisa FROM FisaPacient WHERE FisaPacient.DataNastere >= #1/1/2000#;

Page 188: Studii de Caz Access 2007

Studii de caz

188

IV.e) Să se afişeze numărul de diagnostice stabilite în 2007 de către fiecare medic specialist

SELECT Medic.NumeMedic, Medic.PrenumeMedic, Count(Diagnostic.IDDiagnostic) AS NumărDiagnostice, Year([DataDiagnostic]) AS Anul FROM Medic INNER JOIN Diagnostic ON Medic.CodMedic = Diagnostic.CodMedic WHERE Medic.Grad="Specialist" GROUP BY Medic.NumeMedic, Medic.PrenumeMedic, Year([DataDiagnostic]) HAVING Year([DataDiagnostic])=2007;

IV.f ) Să se afişeze numărul de pacienţi născuţi în fiecare an SELECT Year([DataNastere]) AS AnNastere, Count(FisaPacient.NumarFisa) AS NumărPacienţi FROM FisaPacient GROUP BY Year([DataNastere]);

IV.g) Să se afişeze numele tuturor asistenţilor care deservesc săli deservite de medicul Sărdaru Liviu

SELECT Asistent.NumeAsistent, Asistent.PrenumeAsistent FROM Asistent INNER JOIN (((Sectie INNER JOIN Medic ON Sectie.CodSectie = Medic.CodSectie) INNER JOIN Sala ON Sectie.CodSectie = Sala.CodSectie) INNER JOIN Deserveste ON Sala.NumarSala = Deserveste.NumarSala) ON Asistent.CodAsistent = Deserveste.CodAsistent WHERE Medic.NumeMedic="Sardaru" AND Medic.PrenumeMedic="Liviu";

IV.h) Să se afişeze medicii primari, în ordinea descrescătoare a numărului de diagnostice stabilite

SELECT Medic.NumeMedic, Medic.PrenumeMedic, Count(Diagnostic.IDDiagnostic) AS NumărDiagnostice FROM Medic INNER JOIN Diagnostic ON Medic.CodMedic = Diagnostic.CodMedic WHERE Medic.Grad="Primar" GROUP BY Medic.NumeMedic, Medic.PrenumeMedic ORDER BY Count(Diagnostic.IDDiagnostic) DESC;

IV.i) Să se creeze tabela „PacienţiStrăini” care să conţină datele personale şi numărul de internări ale fiecărui pacient care nu este de naţionalitate română

SELECT FisaPacient.NumarFisa, FisaPacient.NumePacient, FisaPacient.PrenumePacient, FisaPacient.DataNastere, Count(Internare.CodInternare) AS NrInternări INTO PacientiStraini FROM FisaPacient INNER JOIN Internare ON FisaPacient.NumarFisa = Internare.NumarFisa WHERE FisaPacient.Nationalitate="Straina" GROUP BY FisaPacient.NumarFisa, FisaPacient.NumePacient, FisaPacient.PrenumePacient, FisaPacient.DataNastere;

IV.j) Să se şteargă din tabela creată anterior datele pacienţilor născuţi după 1960 DELETE Year([DataNastere]) AS AnulNastere FROM PacientiStraini WHERE Year([DataNastere]) > 1960;

Page 189: Studii de Caz Access 2007

Baze de date Access 2007

189

Studiu individual:

a) Să se afişeze numele pacienţilor de naţionalitate română născuţi după 1990 b) Să se afişeze numărul de medici aferenţi fiecărui grad c) Să se afişeze datele celui mai tânăr pacient internat într-o sală a secţiei „Chirurgie” d) Să se afişeze numărul maxim de diagnostice stabilite de către un medic în 1990 e) Să se şteargă datele pacienţilor care nu au avut nici o internare

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular pe baza tabelei Internare, prevăzut cu un buton de validare care să nu permită salvarea unei înregistrări atâta timp cât între data externării şi data internării nu este o diferenţă de cel puţin trei zile (data externării fiind, evident, ulterioară celei de internare).

Deoarece formularul va conţine toate câmpurile din tabela Internare, acesta va fi creat prin selectarea tabelei din lista de obiecte Access, urmată de alegerea butonului Form din secţiunea Create a barei cu butoane. Formularul astfel obţinut se salvează cu numele frmInternare, apoi se deschide în modul Design View pentru a se adăuga un buton de comandă (numit cmdVerifică). Aspectul final al formularului este prezentat în imaginea următoare.

Codul VBA aferent butonului cmdVerifică va realiza un test al condiţiei enunţate şi va salva înregistrarea numai în cazul în care condiţia este respectată.

În continuare este prezentată procedura eveniment aferentă butonului: Private Sub cmdVerifica_Click() If DataExternare - DataInternare < 3 Then MsgBox "Internarea se face pentru o perioada de minim 3 zile!" Else DoCmd.Save End If End Sub

Page 190: Studii de Caz Access 2007

Studii de caz

190

V.b) Realizaţi un formular cu subformular pentru afişarea istoricului medical al unui pacient (toate diagnosticele stabilite pacientului de la momentul deschiderii fişei, în ordine invers cronologică)

Formularul principal se va realiza pe baza tabelei FişăPacient, iar subformularul va fi realizat pe baza tabelei Diagnostic. Pentru o prezentare optimă, subformularul va fi afişat în modul „Multiple forms”. Aspectul final al formularului este prezentat în imaginea următoare.

Pentru obţinerea listei de diagnostice în ordine invers cronologică, este necesară precizarea acestei condiţii în cadrul proprietăţii „Order By” a subformularului, ca în figura alăturată.

Studiu individual:

a) Să se realizeze un formular cu subformular pentru afişarea asistenţilor care deservesc fiecare secţie a clinicii. b) Să se realizeze un formular cu subformular pentru afişarea tuturor internărilor precedente ale unui pacient.

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Afişarea asistenţilor care deservesc sălile din fiecare secţie a clinicii.

Conţinutul unui asemenea raport presupune centralizarea datelor din cel puţin trei tabele: Secţie, Sală şi Asistent. Din acest motiv, s-a optat pentru o structură pe mai multe nivele, aşa cum este prezentată în figura următoare:

Page 191: Studii de Caz Access 2007

Baze de date Access 2007

191

Structura pe mai multe nivele presupune definirea de secţiuni Header multiple în cadrul raportului, astfel:

• O secţiune destinată grupării la nivel de secţie (CodSecţie Header) • O secţiune destinată grupării la nivel de sală (NumărSală Header) • O secţiune destinată prezentării înregistrărilor de detaliu privind codul,

numele, prenumele şi specializarea fiecărui asistent (Detail) Pentru exemplificare se va prezenta şi un fragment din raport, în forma în care poate fi consultat pe ecran sau tipărit de către utilizatorul final.

Studiu individual:

a) Să se realizeze un raport pentru afişarea medicilor care deservesc fiecare secţie a clinicii. b) Să se realizeze un raport pentru afişarea istoricului medical al fiecărui pacient (fişa pacientului).

Page 192: Studii de Caz Access 2007

Studii de caz

192

Bază de date pentru evidenţa comenzilor primite de către un studio foto

Se doreşte realizarea unei baze de date pentru gestiunea comenzilor primite de către un studio foto.

Oferta de servicii a studioului este organizată sub forma unui catalog în cadrul căruia fiecare serviciu oferit este identificat printr-un cod, specificându-se, de asemenea, denumirea şi preţul unitar al serviciului.

Pentru fiecare comandă primită de către studioul foto se atribuie un număr unic (cu rol de identificare), înregistrându-se şi data la care a fost înregistrată. De asemenea, se impune existenţa unui atribut pentru stabilirea tipului de livrare a comenzii (la studio sau prin curier, la domiciliul clientului). Înregistrarea conţinutului fiecărei comenzi (necesar pentru calculul valorii acesteia şi apoi pentru încasare) presupune cunoaşterea cantităţii comandate din fiecare serviciu oferit (pe baza catalogului de servicii).

În vederea obţinerii unei evidenţe a clienţilor studioului, precum şi pentru a răspunde cerinţelor legate de livrarea la domiciliu, este necesară înregistrarea unor date personale ale acestora. Ca urmare, în momentul plasării primei comenzi, fiecărui client i se atribuie un cod de identificare, pe care îl va utiliza pentru toate comenzile ulterioare. În plus, va fi necesară cunoaşterea numelui, adresei şi oraşului de domiciliu, pentru situaţia în care o comandă nu va fi ridicată de la studio, ci va fi livrată prin curier direct la domiciliul clientului.

Reguli de gestiune:

• Un client al studioului poate plasa mai multe comenzi;

• O comandă aparţine unui singur client (este plasată de către un singur client);

• O comandă poate conţine mai multe servicii (în cantităţi diferite);

• Acelaşi serviciu (din catalog) se poate afla pe mai multe comenzi (în cantităţi diferite);

• Pe fiecare comandă, fiecare serviciu se înregistrează o singură dată;

• Preţurile serviciilor sunt fixe.

I. Realizaţi modelul relaţional al bazei de date şi implementaţi în MS Access

Realizarea modelului relaţional presupune identificarea prealabilă a atributelor care vor intra în componenţa acestui model, precum şi centralizarea lor în forma dicţionarului de atribute. Pentru problema enunţată, dicţionarul de atribute are următorul conţinut (ordonat alfabetic):

XI

Page 193: Studii de Caz Access 2007

Baze de date Access 2007

193

DICŢIONAR DE ATRIBUTE

Adresă

Cantitate

CodClient

CodServiciu

Data

Denumire

NrComandă

Nume

Oraş

Preţ

TipLivrare

În vederea obţinerii modelului relaţional aferent acestui dicţionar de atribute se va construi matricea dependenţelor funcţionale. Din cauza limitărilor de spaţiu, se va prezenta forma restrânsă a acestei matrice (pe una dintre dimensiuni vor fi specificate doar atributele cu rol de cheie primară, nu întregul conţinut al dicţionarului). În acest scop, se vor marca în listă acele atribute care au rol de identificare în cadrul modelului. Casetele de culoare neagră din cadrul matricei marchează dependenţele funcţionale triviale (faptul că fiecare atribut depinde funcţional de el însuşi). Casetele de culoare gri marchează dependenţele multivaloare, pe baza cărora nu se pot trage concluzii cu privire la forma finală a modelului relaţional. Marcajul „1T” indică existenţa unei dependenţe funcţionale tranzitive între cheia primară de pe coloană şi atributul corespunzător liniei, iar marcajul „1” indică existenţa unei dependenţe funcţionale directe între cele două elemente menţionate.

ATRIBUTE CHEI PRIMARE Nr. Denumire 03 04 07 04+07 01 Adresă 1 1T 1T 02 Cantitate 1 03 CodClient 1T 1T

04 CodServiciu 05 Data 1 1T 06 Denumire 1 1T

07 NrComandă 08 Nume 1 1T 1T 09 Oraş 1 1T 1T

10 Preţ 1 1T 11 TipLivrare 1 1T

Modelul relaţional al bazei de date este următorul:

Client (CodClient, Nume, Adresa, Oras)

Comanda (NrComanda, Data, TipLivrare, CodClient)

Continut (NrComanda, CodServiciu, Cantitate)

Serviciu (CodServiciu, Denumire, Pret)

Page 194: Studii de Caz Access 2007

Studii de caz

194

În scopul implementării în SGBD Microsoft Access 2007 a modelului relaţional obţinut, este necesară stabilirea tipului de date ce va fi atribuit fiecărui atribut. Opinia autorului cu privire la tipurile de date cele mai potrivite pentru cazul în discuţie este prezentată în tabelul următor:

ATRIBUTE DE TIP NUMERIC (Tipurile NUMBER şi AUTONUMBER)

DENUMIRE ATRIBUT TIP DE DATE

Cantitate Number, Long Integer

CodClient AutoNumber, Long Integer, Random

CodServiciu AutoNumber, Long Integer, Increment

NrComandă AutoNumber, Long Integer, Random

Preţ Number, Single

ATRIBUTE DE TIP ALFANUMERIC (Tipul de date TEXT)

DENUMIRE ATRIBUT LUNGIME (CARACTERE)

Adresă 255

Denumire 200

Nume 50

Oraş 30

TipLivrare 20

ATRIBUTE DE TIP DATĂ (Tipul de date DATE/TIME)

DENUMIRE ATRIBUT TIP DE DATE

Dată Date/Time

Observaţii:

1. Implementarea modelului relaţional în SGBD Access se va realiza fără a utiliza caracterele diacritice specifice limbii române.

2. În scopul păstrării compatibilităţii tipului de date dintre cheia primară a unei tabele şi cheile externe corespunzătoare, fiecărei chei primare de tip AutoNumber îi vor corespunde chei externe de tip Long Integer.

În opinia autorului, procesul de definire a atributelor şi alegere a tipurilor de date trebuie completat cu o serie de constrângeri suplimentare, pentru a asigura integritatea şi consistenţa datelor, dar şi pentru a facilita utilizarea bazei de date şi popularea acesteia. În acest sens se va propune şi exemplifica realizarea următoarelor tipuri de restricţii de integritate (constrângeri):

• Atributul TipLivrare (din tabela Comandă) are un domeniu de valori bine definit şi, ca urmare, posibilităţile de introducere a datelor ar trebui limitate la lista de valori corespunzătoare acestui domeniu. Figura următoare exemplifică utilizarea instrumentului „LOOKUP” oferit de SGBD Access 2007 pentru realizarea unei liste de valori alfanumerice (tipul de date „Text”). În plus,

Page 195: Studii de Caz Access 2007

Baze de date Access 2007

195

limitarea posibilităţilor de introducere de date la variantele prestabilite s-a realizat cu ajutorul proprietăţii „Limit To List”, care a primit valoarea „Yes”.

Figura de mai sus exemplifică stabilirea valorilor predefinite ale unui atribut de tip „Text” (TipLivrare).

• Pentru atributul Dată (din tabela Comandă) se intenţionează furnizarea unei valori implicite (considerată ca potrivită pentru o mare parte din situaţii), urmând ca aceasta să fie modificată liber de către utilizator în situaţiile în care nu este aplicabilă. În cazul acestui atribut, valoarea ar putea fi data curentă a sistemului. Cea mai simplă metodă de a obţine acest tip de comportament este apelul la funcţia „Date”, care returnează data curentă a sistemului şi plasarea acestui apel în secţiunea „Default Value” a listei de proprietăţi pentru câmpul vizat (figura următoare):

• În scopul de a facilita stabilirea valorilor pentru câmpurile cu rol de cheie

externă, instrumentul „LOOKUP” oferit de SGBD Access 2007 poate fi utilizat pentru a afişa în cadrul câmpului-cheie externă toate valorile cheii primare

Page 196: Studii de Caz Access 2007

Studii de caz

196

corespunzătoare (toate valorile care respectă integritatea referenţială). În funcţie de situaţie, o asemenea afişare poate include şi alte câmpuri suplimentare, care nu fac parte din cheie dar facilitează înţelegerea valorilor cheii. Afişarea unor câmpuri suplimentare sau ascunderea câmpului cu rol de cheie externă nu afectează în nici un fel relaţiile dintre cele două tabele implicate, fiind doar o metodă de îmbunătăţire a ergonomiei interfeţei. De exemplu, adăugarea numelui şi prenumelui unui client la codul acestuia poate elimina ambiguităţile în selectarea clientului care a plasat o anumită comandă (cheia externă CodClient din tabela Comandă). În acest caz, proprietatea „Bound Column” stabileşte care dintre coloanele afişate conţine cheia externă propriu-zisă, proprietatea „Column Count” stabileşte numărul de coloane afişate, iar proprietatea „Column Widths” poate fi utilizată pentru a preciza explicit lăţimea fiecărei coloane (sau pentru a ascunde una dintre coloane). Tehnica descrisă este exemplificată în figurile următoare:

Efectele procedurii descrise anterior sunt prezentate în figura următoare:

Tabelele şi relaţiile obţinute în urma implementării în Microsoft Access, sunt prezentate în figura din pagina următoare.

Page 197: Studii de Caz Access 2007

Baze de date Access 2007

197

Studiu individual:

Completaţi modelul anterior, astfel încât să răspundă şi următoarelor cerinţe: Baza de date trebuie să asigure evidenţa facturării şi încasării comenzilor primite de la clienţi. În acest sens, se vor implementa o serie de tabele adiţionale, conform cu următoarele reguli de gestiune: * O comandă (de facturat) apare pe o singură factură; * O factură poate centraliza mai multe comenzi ale aceluiaşi client; * O factură poate fi plătită prin intermediul a mai multe documente de plată; * Un document de plată poate achita mai multe facturi;

II. În tabelele modelului realizat la cerinţa anterioară se vor stabili următoarele proprietăţi:

II.a) Deoarece studioul foto şi-a început activitatea la 1 ianuarie 2003, pentru comenzile primite de la clienţi nu se vor accepta date de plasare anterioare acestei valori. Condiţia ca valorile câmpului Dată (din tabela Comandă) să fie ulterioare datei de 1.1.2003 se va implementa în cadrul proprietăţii „Validation Rule” a acestui câmp.

De asemenea, se recomandă utilizarea proprietăţii „Validation Text” pentru stabilirea unui mesaj de avertizare în cazul în care o valoare introdusă nu respectă regula menţionată anterior. Exemplul din figura alăturată ilustrează limitarea domeniului de valori pentru câmpul Dată

Page 198: Studii de Caz Access 2007

Studii de caz

198

II.b) În scopul păstrării consistenţei datelor din baza de date, este necesară implementarea unei restricţii la nivelul câmpului Cantitate (din tabela Conţinut) care să limiteze domeniul de valori la cele strict pozitive (cantitatea nu trebuie să ia valori negative sau să fie zero). De asemenea, lipsa unei valori (Null) pentru atributul Cantitate poate conduce la imposibilitatea de a calcula suma totală a unei comenzi şi, ca urmare de a înregistra încasarea acestei sume. Pentru a evita aceste situaţii, vor fi stabilite valorile corespunzătoare aferente proprietăţilor „Validation Rule”, „Validation Text” şi „Required”. Modul de stabilire a restricţiilor este prezentat în figura următoare. Exemplul ilustrează Implementarea unor restricţii la nivelul câmpului Cantitate.

Studiu individual:

a) Se cere completarea tabelei Comandă cu un atribut de tip dată, numit DataLivrare, precum şi stabilirea unor restricţii la nivel de tabelă, astfel: pentru comenzile care se preiau direct de la studio, data livrării este ulterioară cu cel puţin două zile datei comenzii, iar pentru comenzile care se livrează la domiciliu, data livrării este ulterioară cu cel puţin patru zile datei comenzii b) Se cere modificarea condiţiei de la punctul II.b) pentru situaţia în care se acceptă şi valori negative ale atributului Cantitate (în scop rectificativ).

Page 199: Studii de Caz Access 2007

Baze de date Access 2007

199

III. Realizaţi interogări (Queries) pentru următoarele cerinţe: III.a) Să se afişeze clienţii din Bucureşti

III.b) Să se afişeze numărul de comenzi înregistrate după 1 ianuarie 2007

III.c) Să se afişeze în ordine alfabetică numele, adresa şi numărul de comenzi plasate, pentru clienţii care au transmis cel puţin trei comenzi după 1 ianuarie 2007

Page 200: Studii de Caz Access 2007

Studii de caz

200

III.d) Să se afişeze numărul de comenzi cu livrare la domiciliu aferente fiecărui client

Studiu individual:

a) Să se afişeze serviciile din catalog în ordinea descrescătoare a cantităţii totale comandate b) Să se afişeze serviciul solicitat de cei mai mulţi clienţi

Page 201: Studii de Caz Access 2007

Baze de date Access 2007

201

IV. Realizaţi interogări SQL pentru următoarele cerinţe: IV.a) Să se afişeze datele clienţilor care nu sunt din Bucureşti

SELECT Client.CodClient, Client.Nume, Client.Adresa, Client.Oras FROM Client WHERE Client.Oras < > "Bucuresti";

IV.b) Să se afişeze cele mai noi trei comenzi SELECT TOP 3 Comanda.NrComanda, Comanda.Data FROM Comanda ORDER BY Comanda.Data DESC;

IV.c) Să se afişeze numărul de servicii de pe fiecare comandă SELECT Comanda.NrComanda, Count(Continut.CodServiciu) AS NrServicii FROM Comanda INNER JOIN Continut ON Comanda.NrComanda = Continut.NrComanda GROUP BY Comanda.NrComanda;

IV.d) Să se afişeze numărul de comenzi primite după 2005 SELECT Count(Comanda.NrComanda) AS NrComenzi FROM Comanda WHERE Comanda.Data >= #1/1/2006#;

IV.e) Să se afişeze numărul de comenzi plasate în 2007 pentru fiecare serviciu din catalog

SELECT Serviciu.Denumire, Count(Continut.NrComanda) AS NrComenzi FROM Comanda INNER JOIN (Serviciu INNER JOIN Continut ON Serviciu.CodServiciu = Continut.CodServiciu) ON Comanda.NrComanda = Continut.NrComanda WHERE Year([Data])=2007 GROUP BY Serviciu.Denumire;

IV.f ) Să se afişeze numărul de comenzi primite în fiecare an

SELECT Year([Data]) AS An, Count(Comanda.NrComanda) AS NrComenzi FROM Comanda GROUP BY Year([Data]);

IV.g) Să se afişeze anul în care s-au primit cele mai multe comenzi SELECT TOP 1 Year([Data]) AS An, Count(Comanda.NrComanda) AS NrComenzi FROM Comanda GROUP BY Year([Data]) ORDER BY Count(Comanda.NrComanda) DESC;

Page 202: Studii de Caz Access 2007

Studii de caz

202

IV.h) Să se afişeze clienţii, în ordinea descrescătoare a numărului de comenzi plasate SELECT Client.CodClient, Client.Nume, Client.Adresa, Client.Oras, Count(Comanda.NrComanda) AS NrComenzi FROM Client INNER JOIN Comanda ON Client.CodClient = Comanda.CodClient GROUP BY Client.CodClient, Client.Nume, Client.Adresa, Client.Oras ORDER BY Count(Comanda.NrComanda) DESC;

IV.i) Să se creeze tabela „ClientiProvincie” care să conţină datele personale şi numărul de comenzi ale fiecărui client din afara Bucureştiului

SELECT Client.CodClient, Client.Nume, Client.Adresa, Client.Oras, Count(Comanda.NrComanda) AS NrComenzi INTO ClientiProvincie FROM Client INNER JOIN Comanda ON Client.CodClient = Comanda.CodClient GROUP BY Client.CodClient, Client.Nume, Client.Adresa, Client.Oras HAVING Client.Oras < > "Bucuresti";

IV.j) Să se şteargă din tabela creată anterior datele clienţilor al căror nume începe cu litera „M”

DELETE ClientiProvincie.* FROM ClientiProvincie WHERE ClientiProvincie.Nume Like "M*";

Studiu individual:

a) Să se afişeze numele clienţilor din Bucureşti care au transmis comenzi înainte de 1 ianuarie 2006 b) Să se afişeze numărul de clienţi din fiecare oraş c) Să se afişeze datele celei mai noi comenzi care solicită serviciul „Retuşare” d) Să se afişeze numărul maxim de comenzi plasate din acelaşi oraş în 2008 e) Să se reducă cu 10% preţul tuturor serviciilor pentru care s-au înregistrat mai puţin de trei comenzi f) Să se şteargă datele pacienţilor care nu au plasat nici o comandă

V. Se vor realiza obiecte de tip formular pentru următoarele cerinţe: V.a) Realizaţi un formular pe baza tabelei Comandă, care să permită preluarea sau afişarea completă a unei comenzi.

În acest scop, formularul va trebui să conţină un subformular pentru afişarea datelor clientului (pe baza codului de client selectat din formularul principal), precum şi un subformular pentru selectarea şi afişarea conţinutului comenzii (datele cu privire la serviciile comandate). În plus, se impune prezentarea unor câmpuri suplimentare, cu valori calculate, pentru suma netă, taxa pe valoare adăugată şi suma brută aferentă fiecărui serviciu. Valoarea netă a serviciului se calculează prin înmulţirea cantităţii comandate (preluată din tabela Conţinut) cu preţul unitar al serviciului (preluat din

Page 203: Studii de Caz Access 2007

Baze de date Access 2007

203

tabela Serviciu). Pentru calculul TVA aferentă unui serviciu comandat, valoarea netă a serviciului se a înmulţi cu cota de TVA, iar pentru obţinerea valorii brute, valoarea netă a serviciului se va însuma cu valoarea TVA aferentă.

În scopul facilitării obţinerii acestor valori la nivelul formularului, se recomandă calculul lor prealabil, în cadrul unei interogări (numită Sursa), al cărui conţinut este prezentat în figura următoare:

Interogarea prezentată anterior se va utiliza ca sursă de date pentru un formular de tip „Multiple items”, care va afişa şi va permite actualizarea conţinutului comenzii. În subsolul acestui formular (secţiunea „Form Footer”) se vor adăuga trei casete text (controlul TextBox) cu scopul de a afişa valoarea totală (suma) aferentă fiecărei coloane totalizabile.

Structura şi modul de prezentare ale acestui formular, precum şi formulele de calcul aferente casetelor de total sunt descrise în figura de mai sus.

Pentru afişarea datelor clientului se va realiza un formular având ca sursă de date tabela Client, formular a cărui structură este prezentată în figura următoare.

Page 204: Studii de Caz Access 2007

Studii de caz

204

În final, se va crea un formular având ca bază tabela Comandă, în cadrul căruia vor fi integrate cele două subformulare descrise anterior. În acest scop se vor utiliza două controale Subform/Subreport, fiecare având rol de container pentru câte unul din cele două subformulare. Deoarece toate cele trei formulare implicate au sursele de date legate prin chei externe, SGBD Access va deduce relaţiile logice dintre ele, actualizând automat datele clientului şi conţinutul comenzii în momentul afişării acesteia. Formatul final al formularului este prezentat în figura alăturată.

Studiu individual:

a) Să se realizeze un formular pentru afişarea tuturor serviciilor oferite şi a tarifelor aferente). b) Să se realizeze un formular cu subformular pentru afişarea datelor şi valorilor comenzilor aferente unui client (fără a afişa şi conţinutul acestor comenzi).

VI. Se vor realiza obiecte de tip raport pentru următoarele cerinţe: VI.a) Afişarea conţinutului unei comenzi şi a datelor clientului care a transmis-o.

Conţinutul unui asemenea raport presupune centralizarea datelor din cel puţin trei tabele: Comandă, Client şi Conţinut. Din acest motiv, s-a optat pentru o structură pe mai multe nivele, aşa cum este prezentată în figura următoare:

Page 205: Studii de Caz Access 2007

Baze de date Access 2007

205

Structura pe mai multe nivele presupune definirea de secţiuni Header multiple în cadrul raportului. De asemenea, pentru o prezentare mai compactă a antetului comenzii, datele clientului au fost comasate în cadrul acestui antet. În scopul unei utilizări cât mai flexibile, se recomandă specificarea numărului comenzii printr-un parametru, astfel încât raportul să poată fi folosit pentru tipărirea unei singure comenzi. Pentru exemplificare se va prezenta şi un fragment din raport, în forma în care poate fi consultat pe ecran sau tipărit de către utilizatorul final.

Studiu individual:

a) Să se realizeze un raport pentru afişarea serviciilor solicitate în timp de către fiecare client. b) Să se realizeze un raport pentru afişarea serviciilor din catalog, în ordinea descrescătoare a popularităţii (dată de ordinea descrescătoare a numărului de comenzi).

Page 206: Studii de Caz Access 2007

Studii de caz

206

Bibliografie

• Microsoft Access 2007 Step By Step, Steve Lambert, Microsoft Press, 2007

• Baze de date, Florescu Vasile (coordonator), Ionescu Bogdan (coordonator) ; Cozgarea Gabriel, Vrincianu Marinela, Tudor Catalin, Aleca Ofelia, Rădulescu Cristina, Editura Infomega, 2009

• Baze de date – Fundamente teoretice şi practice, Grupul BDASEIG, Editura Infomega, 2002

• Tehnologia bazelor de date Access 2000, Pavel Năstase, Florin Mihai, Andrei Stanciu, Liana Covrig – Editura Economică, 2001

• http://databases.about.com

• http://office.microsoft.com

• http://www.ms-access2007.com