FACULTATEA DE MATEMATICA SI INFORMATICA
UNIVERSITATEA “OVIDIUS”
CONSTANTA
SPECIALIZAREA MATEMATICA – INFORMATICA
ANUL III
PROIECT LA BAZE DE DATE
TIPARITURI PERIODICE in Bucuresti”
Consideram subuniversul “ Tiparituri periodice in Bucuresti ”, in care intereseaza doar urmatoarele multimi de obiecte si proprietati ale acestora: tipografii (id, tipografie)(tipografiile in care se tiparesc ziarele/revistele), ziare/reviste (id,nume,nr.pag)(denumirile ziarelor si revistelor precum si numarul de pagini) , periodicitati (id, periodicitate)(periada publicarii ziarului/ revistei), tipuri_princ_info(id, tipZiar/Revista)(tipurile principale de informatii publicate de tipografii), persoane (CNP, Nume, Prenume, Adresa),
sponsorizari (id, persoane, ziar/reviste, suma in lei, data) (sponsorii ziarului/revistei si sumele platite de acestia pentru fiecare ziar/revista in parte precum si data la care a avut loc sponsorizarea).
Acest subunivers este supus urmatoarelor restrictii:
R1: nu pot exista doua ziare/reviste cu acelasi nume;
R2: nu pot exista doua persoane cu acelasi CNP;
R3: un ziar/revista poate fi de un singur tip;
R4: un ziar/revista poate fi sponsorizata de mai multe persoane;
R5: o persoana poate sponsoriza mai multe ziare;
R6: nu exista doua tipografii cu acelasi nume;
R7: nu exista doua tipuri de ziare/reviste cu acelasi nume;
Analizand acest subunivers, rezulta urmatoarele diagrame entitati-asociatii:
Atributele pentru fiecare entitate si asociatie in parte sunt:
Aplicand algoritmul de traducere din DEA in MMED si rafinand modelarea matematica astfel obtinuta, schema MMED finala corespunzatoare este urmatoarea:
TIPOGRAFII (Multimea tipografiilor in care se publica ziarul/revista.)
IdT ↔ NAT(4), total
Tipografie ↔ CHAR(64), total (denumire tipografiei; unica, cf. R6)
SPONSORIZARI = (ZIARE/REVISTE, PERSOANE) (Multimea perechilor de tip <z, p> cu semnificatia ca ziarul/revista z este sponzorizata de persoana p ; cf. R4 si R5.)
IdSp ↔ NAT(4), total
Suma → NAT(8), total (suma sponsorizarii; obligatoriu strict pozitiva si de maxim 99.999.999 (Lei))
Data →Data/Time,total (data sponsorizarii)
Persoana → NAT(32),total(numele, perenumele si CNP/CUI persoanei care sponsorizeaza ziarul/revista)
Algoritmul de proiectare a cheilor semantice:
n=3 (Suma ,Data, Persoana), kmax=C32=3
i=1 (j= C31=3):
1.1 Suma cheie ? NU
(Pot exista mai multe persoane care sponsorizeaza aceeasi suma.)
1.2 Data cheie? NU
(Pot exista mai multe pesoane care sponsorizeaza la aceeasi data.)
1.3 Persoana cheie? NU
(Aceeasi persoana poate sponsoriza de mai multe ori.)
i=2 (j= C32=3):
Suma ∙ Data cheie? NU
(Se pot face sponsorizari cu aceeasi suma la ceeasi data)
2.2 Suma ∙ Persoana cheie? NU
(Aceeasi persoana poate sponsoriza mai multe ziare/reviste cu aceeasi suma.)
2.3 Persoana∙ Data cheie? NU
(Aceeasi persoana poate sponsoriza mai multe ziare/reviste la aceeasi data.)
i=3 (j= C33=1):
Persoana ∙ Data∙ Suma cheie? DA
(Nu pot exista persoane care sponsorizeaza la aceeasi data aceeasi suma de bani)
ZIARE/REVISTE (Multimea ziarelor si revistelor.)
IdZR ↔ NAT(4), total
NumeZiare/Reviste ↔ CHAR(128), total (denumire ziar/revista; unica, cf. R1)
TipZiar : ZIARE/REVISTE → TIPURI_PRINC_INFO, total (tipul ziarului/revistei)
Tipografie : ZIARE/REVISTE → TIPOGRAFII, total (tipografia ziarului/revistei)
Algoritmul de proiectare a cheilor semantice:
k=1, K=, n=2 (TipZiar, Tipografie), kmax=C21=2
i=1 (j= C21=2):
1.1TipZiar cheie? NU
(Pot exista mai multe ziare de acelasi tip.)
1.2 Tipografie cheie? NU
(Mai multe ziare/reviste pot fi tiparite la aceeasi tipografie.)
i=2 (j= C22=1):
2.1 TipZiar ∙ Tipografie cheie? NU
(Mai multe ziare/reviste de acelasi tip pot fi tiparite la aceeasi tipografie.)
In concluzie: k=1, K=
PERIODICITATII (Multimea perechilor de tip <z, p> cu semnificatia ca ziarul z apare la perioada p)
IdPer ↔ NAT(8), total
Periodicitate → CHAR(128), total (perioada de tiparire (aparitie) a ziarului/revistei)
Periodicitate : ZIARE/REVISTE → PERIODICITATI, total (periodicitatea ziarului/revistei)
Algoritmul de proiectare a cheilor semantice:
n=2 (Ziar/Revista, Periodicitate), kmax=C21=2
i=1 (j= C21=2):
1.1 Ziar/Revista cheie? DA
Deoarece in campul ziar nu poate aparea de 2 sau mai multe ori ori aceasi valoare (exemplu(ziua si in alta casuta ziua))
1.2 Periodicitate cheie? NU
Deoarece in tabela ziare reviste aceasi valoare poate aparea de mai multe ori
i=2 (j= C22=1):
2.1 Ziar/Revista ∙ Periodicitate cheie? DA
( Un ziar/revista nu poate avea alt interval la care apare( exemplu saptamanal si lunar) in aceasi perioada de timp.)
In concluzie luam in calcul : k=1, K= pentru ca le cuprinde si pe celalalte in sensul ca:
Daca punem cheie Ziar/RevistePeriodicitate vom avea scris jurnalul - zilnic
jurnalul-saptamanal ceea ce putem evita doar daca punem cheia ziar/revista .. adica nu poate aparea de 2 ori jurnalul
PERSOANE Multimea sponsorilor ziarului/revistei .)
IdP ↔NAT(4), total
Nume → CHAR(255),total(numele sponsorilor ziarului/revistei fie el persoana fizica sau juridica)
Prenume → CHAR(255), (prenumele sponsorilor ziarului/revistei)
CNP/CUI ↔ CHAR(16), total (codul numeric personal unic in Europa se identificare sau codul unic In Europa de identificare pentru persoane juridice; unic, cf. R2)
Adresa → CHAR(255),total(adresa sponsorilor ziarului/revistei strada, numar, bloc, scara,apartament etc)
Algoritmul de proiectare a cheilor semantice:
k=1, K=, n=4 (Nume, Prenume,Adresa), kmax=C32=3
i=1 (j= C31=3):
1.1 Nume cheie? NU
(Pot exista mai multe persoane cu acelasi nume.)
1.2 Prenume cheie? NU
(Pot exista mai multe persoane cu acelasi prenume.)
1.3 Adresa cheie? NU
(Pot exista mai multe persoane care locuiesc la aceeasi adresa.)
i=2 (j= C32=3):
2.1 Nume ∙ Prenume cheie? NU
(Pot exista mai multe persoane cu aceleasi nume si prenume.)
2.2 Nume ∙ Adresa cheie? NU
(Mai multe persoane cu acelasi nume pot locui la aceeasi adresa.)
2.3 Prenume ∙ Adresa cheie? NU
(Mai multe persoane cu acelasi prenume pot locui la aceeasi adresa.)
i=3 (j= C33=1):
3.1 Nume ∙ Prenume ∙ Adresa cheie? NU
(Mai multe persoane cu acelasi nume si acelasi prenume pot avea aceeasi adresa.)
In concluzie: k=1, K=
TIPURI_PRINC_INFO (Multimea tipurilor de ziare/reviste tparite de tipografii.)
IdZiar/Revista ↔ NAT(4), total
TipZiar/Revista ↔ CHAR(64), total (denumire tip ziar/revista; unica, cf. R8)
Aplicand algoritmul de traducere din MMED in MRD, schema relationala rezultata este urmatoarea
TIPOGRAFII (IdT, Tipografie )
Φ├ Tipografie
PERSOANE ( IdP, CNP)
Φ├Nume, Φ├Prenume, Φ├CNP, Φ├ Adresa
TIPURI_PRINC_INFO ( IdTipZiar/Revista, TipZiar/Revista)
Φ├TipZiar/Revista
ZIARE/REVISTE (IdZR, NumeZiare/Reviste)
Φ├NumeZiare/Reviste, Φ├NrPag ,
TipZiarIdZiar/Revista, TipografieIdT,PeriodicitateIdPer
SPONSORIZARI (IdSp,Suma∙Persoana∙Data)
Φ├Suma, Φ├ Data,
PersoanaId P , Ziar/RevistaSponsIdZR
Suma > 0, Suma
PERIODICITATI( IdPer, Periodicitate)
Φ├Periodicitate, PeriodicitateIdZR
Aplicand algoritmul de traducere a schemelor MRD in scheme Access 2003, se obtine implementarea prezentata in acest capitol (observatie: ea poate fi facuta folosind interfata grafica Access, inclusiv „magicienii” la dispozittie pentru, de exemplu, realizarea legaturilor intre tabele pentru cheile straine sau folosind instructiuni SQL pentru crearea tabelelor, adaugarea cheilor semantice si a celor straine, inserarea datelor in tabele etc.; am preferat, ca exercitiu, varianta SQL, indicand insa, drept exemple si modalitatea alternativa oferita de interfata grafica).
Mai intai trebuie creata o bd Access vida (numita TiparituriPeriodice.mdb, de exemplu).
Crearea tabelelor (inclusiv cheile primare si constrangerile de not null) in bd TiparituriPeriodice.mdb utilizand instructiuni SQL se face astfel:
CREATE TABLE PERSOANE(
IdP counter (1,1) primary key,
Nume char(255) not null,
Prenume char (255) not null,
CNP char (16) unique,
Adresa char (255) not null,
CREATE TABLE TIPURI_PRINC_INFO(
Id Ziar/Revista counter(1,1) primary key,
TipZiar/Revista char(64) not null unique);
CREATE TABLE SPONSORIZARI(
IdSp counter(1,1) primary key,
Persoane int not null,
Ziare/Reviste int not null,
Suma int not null
Data int not null);
CREATE TABLE ZIARE/REVISTE(
IdZR counter(1,1) primary key,
NumeZiare/Reviste char(128) not null unique,
NrPag Long Integer not null,
TipZiar int not null,
Tipografie int not null );
CREATE TABLE PERIODICITATII(
IdPer counter(1,1) primary key,
Ziar/Revista int not null,
Periodicitate char(64) unique );
CREATE TABLE TIPOGRAFII(
IdT counter(1,1) primary key,
Tipografie char(64) not null unique);
In urma executiei acestor instructiuni, directorul Tables al bd va arata astfel:
De exemplu, alternativ, utilizarea interfetei grafice pentru a crea tabela PERSOANE presupune lucrul interactiv in urmatoarea fereastra de proiectare a schemei acestei tabele:
In urma acestor modificari, diagrama relatiilor intre tabele este urmatoarea:
Vizualizand, de exemplu, cheile ZIARE/REVISTE se obtine fereastra urmatoare (atentie: a se observa faptul ca pentru cheile multiple trebuie completat IndexName cu numele cheii respective doar pentru prima coloana a cheii, si, mai ales, faptul ca proprietatea Unique trebuie sa fie obligatoriu Yes pentru ca indexul respectiv sa constituie o cheie – si nu doar un index de cautare):
Desigur ca atat cheile straine, cat si cele surogat pot fi definite si/sau modificate si cu ajutorul interfetei grafice a Access.
a se observa faptul ca pentru cheile multiple trebuie completat IndexName cu numele cheii respective doar pentru prima coloana a cheii, si, mai ales, faptul ca proprietatea Unique trebuie sa fie obligatoriu Yes pentru ca indexul respectiv sa constituie o cheie – si nu doar un index de cautare):
Deoarece in SQL Jet al Access nu exista posibilitati de exprimare a constrangerilor tuplu, a celor de domeniu (si nici, de exemplu, a valorilor implicite), trebuie folosita obligatoriu in acest scop interfata grafica a Access.
De exemplu, pentru pentru impunerea in SPONSORIZARI a constrangerii de domeniu Suma > 0 Suma 99.999.999, trebuie folosite proprietatile omonime ale coloanei Suma:
De exemplu, alternativ, fortarea integritatii referintelor pentru Persoana din SPONSORIZARI este urmatoarea (de notat ca in absenta ei, s-ar putea sterge orice linie din tabela PERSOANE, chiar daca ea ar fi referita de una sau oricate linii din SPONSORIZARI in coloana Persoana, ceea ce ar lasa pointeri „zabauci” („dangling”) in aceste linii; fortarea ei obliga Access sa respinga automat orice asemenea tentativa, deci asa pot fi sterse din SPONSORIZARI doar liniile pe care nici o linie din PERSOANE nu le refera):
De remarcat ca:
Executia instructiunilor SQL ALTER TABLE CONSTRAINT FOREIGN KEY forteaza automat integritatea referintelor.
Bifarea Cascade Update Related Fields este absolut inutila, intru-cat Persoana refera cheia primara cu auto-numarare #P(IdP)(ale carei valori nu pot fi niciodata modificate).
Bifarea Cascade Delete Related Records ar fi extrem de periculoasa: chiar si cu Enforce Referential Integrity setat, daca se seteaza si cascadarea stergerilor, atunci nu doar ca utilizatorul poate sterge din SPONSORIZARI orice linii, inclusiv cele referite de Persoana din PERSOANE, ci Acces va sterge automat in asemenea cazuri si toate liniile din PERSOANE care refera linia stearsa din SPONSORIZARI .
Urmatoarele instructiuni SQL populeaza bd cu un prim set de date de test:
INSERT INTO TIPOGRAFII ( Tipografie )
VALUES ('Ringier Print ');
INSERT INTO TIPOGRAFII (Tipografie)
VALUES ('Mega Press Holdings ');
INSERT INTO TIPOGRAFII (Tipografie )
VALUES ('Info Press Group ');
INSERT INTO TIPOGRAFII (Tipografie)
VALUES ('Crystal Publishing Group ');
INSERT INTO TIPOGRAFII (Tipografie )
VALUES ('Kopa Publicatii ');
INSERT INTO TIPOGRAFII (Tipografie )
VALUES ('Ping Press Bucuresti ');
INSERT INTO PERIODICITATI ( Periodicitate )
VALUES ('Anual ');
INSERT INTO PERIODICITATI (Periodicitate )
VALUES ('Bilunar ');
INSERT INTO PERIODICITATI (Periodicitate )
VALUES ('Saptamanal ');
INSERT INTO PERIODICITATI (Periodicitate )
VALUES ('Zilnic ');
INSERT INTO PERIODICITATI (Periodicitate )
VALUES ('Semestrial ');
INSERT INTO PERSOANE(CNP/CUI, Nume, Prenume,Adresa)
VALUES (2801017123424, ' Popescu ', 'Andreea', Str. Dimitrie Pompeiu);
INSERT INTO PERSOANE (CNP/CUI, Nume, Prenume, Adresa,)
VALUES (1652547896325, ' Martin ', 'Ionela', Str.Ion Campineanu);
INSERT INTO PERSOANE (CNP/CUI ,Nume, Prenume Adresa)
VALUES (R 12680679, 'Coca Cola', Str.Mangalia);
INSERT INTO PERSOANE (CNP/CUI ,Nume, Prenume, Adresa)
VALUES (18050788, 'Izvorul Viu', Str.Avionului 15B);
INSERT INTO PERSOANE (CNP/CUI, Nume, Prenume, Adresa)
VALUES (1654896363562 ,'Gheorghe', 'Daniel', Str.Septimiu Albini);
INSERT INTO PERSOANE (CNP/CUI, Nume, Prenume, Adresa)
VALUES (2885666749898, 'Barbu', 'Catalin', Str.Piata Montreal);
INSERT INTO PERSOANE (CNP/CUI ,Nume, Prenume, Adresa)
VALUES (3656985 ,'Bucegi', Str.Abatorului);
INSERT INTO TIPURI_PRINC_INFO ( TipZiar/Revista )
VALUES ('timp liber ');
INSERT INTO TIPURI_PRINC_INFO (TipZiar/Revista )
VALUES ('pentru femei ');
INSERT INTO TIPURI_PRINC_INFO (TipZiar/Revista )
VALUES ('vedete&tv ');
INSERT INTO TIPURI_PRINC_INFO (TipZiar/Revista )
VALUES ('publicitate ');
INSERT INTO SPONSORIZARI ( Ziar/RevistaSpons,Persoana)
SELECT PERSOANE.IdP, ZIARE/REVISTE.IdZR
FROM PERSOANE, ZIARE/REVISTE
WHERE Nume like '*Barbu*' AND Ziar/RevistaSpons like '* Academia Catavencu *';
INSERT INTO SPONSORIZARI(Ziar/RevistaSpons,Persoana)
SELECT PERSOANE.IdP, ZIARE/REVISTEI.IdZR
FROM PERSOANE, ZIARE/REVISTE
WHERE Nume like '*Vasile*' AND Ziar/RevistaSpons like '* Beau Monde *';
INSERT INTO SPONSORIZARI(Ziar/RevistaSpons,Persoana )
SELECT PERSOANE.IdP, ZIARE/REVISTE.IdZR
FROM PERSOANE, ZIARE/REVISTE
WHERE Nume like '*Poenaru*' AND Ziar/RevistaSpons like '* Cosmopolitan *';
Observatie: aceste date de test initiale au fost ulterior actualizate cu ocazia testarii aplicatiei.
Golirea tuturor tabelelor de instanta lor curenta (si obtinerea deci a unei instante vide a bd) se poate obtine cu ajutorul urmatoarelor instructiuni SQL:
DELETE * FROM PERIODICITATI;
DELETE * FROM PERSOANE;
DELETE * FROM TIPURI_PRINC_INFO;
DELETE * FROM ZIARE/REVISTE;
DELETE * FROM TIPOGRAFIII;
DELETE * FROM SPONSORIZARI;
Desigur ca golirea (tuturor sau doar a unei parti) a tabelelor trebuie facuta doar la instalarea aplicatiei la un nou client (caruia, pentru demonstratie, trebuie sa-i prezentam initial functionarea aplicatiei asupra unor date test). Chiar si in acest caz, e posibil ca datele (de test) din TIPOGRAFII, TIPURI_PRINC_INFO si PERIODICITATI sa intereseze clientul si astfel sa nu se doreasca stergerea lor.
Stergerea tuturor tabelelor bd (si obtinerea deci a unei bd vide) se poate obtine cu ajutorul urmatoarelor instructiuni SQL:
DROP TABLE PERSOANE;
DROP TABLE TIPURI_PRINC_INFO;
DROP TABLE ZIARE/REVISTE;
DROP TABLE PERIODICITATI;
DROP TABLE SPONSORIZARI;
DROP TABLE TIPOGRAFII;
Desigur ca stergerea (tuturor sau doar a unei parti a) tabelelor fundamentale nu trebuie facuta niciodata pentru aceasta aplicatie.
5.9 Vizualizarea cheilor straine cu ajutorul listelor derulante
Atentie: Daca nu se foloseste magicianul Lookup Wizard, trebuie obligatoriu sortate crescator valorile din lista derulanta (altfel utilizatorii nu vor putea cauta binar, deci usor, valorile dorite), ascunsa coloana cheii primare (setandu-i latimea 0) si setat Limit to list la Yes (astfel incat utilizatorii sa nu poata alege decat una dintre valorile din lista derulanta); de exemplu, pentru cheia straina SumaZiarPersKey(Suma∙Persoana∙Data) setarile listei derulante trebuie sa fie urmatoarele:
Instructiunea SQL pentru completarea valorilor cheii straine TipZiar/Revista este:
SELECT IdTipZiar/Revista, TipZiar/Revista
FROM TIPURI_PRINC_INFO
ORDER BY TipZiar/Revista;
Instructiunea SQL pentru completarea valorilor cheii straine Tipografie este:
SELECT IdT, Tipografie
FROM TIPOGRAFII
ORDER BY Tipografie;
Instructiunea SQL pentru completarea valorilor cheii straine Periodicitate este:
SELECT IdPer, periodicitate
FROM PERIODICITATI
ORDER BY Periodicitate;
Datorita existentei relatiilor intre tabele (determinate de cheile lor straine), putem lega intre ele si instantele acestora, folosind coloana „+” a lor; de exemplu, facand clic pe aceasta coloana a instantei tabelei ZIARE/REVISTE
se va deschide urmatoarea fereastra ce permite alegerea unei tabele legate de aceasta:
Alegand TIPOGRAFII, vom putea vizualiza/actualiza simultan instanta celor doua tabele astfel:
Alegand TIPURI_PRINC_INFO, vom putea vizualiza/actualiza simultan instanta celor doua tabele astfel:
Similar, legand TIPURI_PRINC_INFO de ZIARE/REVISTE, se obtine (o ierarhie pe doua niveluri, caci TIPOGRAFI este deja legata la ZIARE/REVISTE):
Alegand PERIODICITATI, vom putea vizualiza/actualiza simultan instanta celor doua tabele astfel:
Alegand SPONSORIZARI, vom putea vizualiza/actualiza simultan instanta celor doua tabele astfel:
Alegand PERSOANE, vom putea vizualiza/actualiza simultan instanta celor doua tabele astfel:
Legand ZIARE/REVISTE la TIPOGRAFII, se obtine:
Similar,legand SPONSORIZARI la ZIARE/REVISTE se obtine (o ierarhie pe doua niveluri, caci ZIARE/REVISTE este deja legata la TIPOGRAFII):
Legand ZIARE/REVISTE la TIPURI_PRINC_INFO obtinem:
Legand TIPOGRAFII la ZIARE/REVISTE obtinem(ZIARE/REVISTE fiind deja legata la TIPURI_PRINC_INFO):
Legand PERIODICITATE la ZIARE/REVISTE obtinem(ZIARE/REVISTE fiind deja legata de TIPOGRAFII care era legata de TIPURI_PRINC_INFO):
Legand ZIARE/REVISTE la PERIODICITATE obtinem:
Legand TIPOGRAFII la ZIARE/REVISTE obtinem(ZIARE/REVISTE fiind deja legate la PERIODICITATI):
VI . Interogari
Se presupune ca, pe langa actualizarea datelor, utilizatorii sunt frecvent interesati de raspunsul la urmatoarele interogari:
Proiectarea si programarea interogarilor cerute este urmatoarea:
Se obtine astfel urmatoarea formalizare in modul proiectare (QBE):
Codul SQL echivalent este urmatorul:
SELECT Count([ZIARE/REVISTE].Nume) AS [NrZiare/Reviste],
PERSOANE.Nume, Sum(SPONSORIZARI.Suma) AS
TotalulSumaSponsorizarii
FROM [ZIARE/REVISTE] INNER JOIN (PERSOANE INNER JOIN SPONSORIZARI ON PERSOANE.[#P] = SPONSORIZARI.Persoana) ON [ZIARE/REVISTE].[#ZR] = SPONSORIZARI.[Ziar/RevistaSpons]
WHERE (((SPONSORIZARI.Suma)>=[Precizati suma dorita in Lei de sponsorizare a Ziarului/Revistei: ]))
GROUP BY PERSOANE.Nume
HAVING (((Count([ZIARE/REVISTE].Nume))>=[Precizati numarul minim dorit de ziare/reviste sponsorizate cu macar x lei: ]))
ORDER BY Count([ZIARE/REVISTE].Nume) DESC , PERSOANE.Nume;
Executand aceasta interogare, de exemplu, cu valorile x=4000 si n=1 asupra instantei curente a bd, se obtine urmatorul rezultat:
2.IntrebareComplexa Aflati numele ,tipografia,periodicitatea ziarului/revistei ,precum si numele persoanei care o sponsorizeaza,data la care este sponsorizata revista/ziarul , numarul de pagini ale acestuia sa fie >35, iar tipul ziarului sa fie orice inafara de sport,ordonatile crescator dupa nume, descrescator dupa tipografie si apoi dupa pers.care face sponsorizarea in ordine crescatoare.
Se obtine astfel urmatoarea formalizare in modul proiectare (QBE):
Codul SQL echivalent este urmatorul:
SELECT [ZIARE/REVISTE].Nume, TIPOGRAFII.Tipografie,
PERIODICITATI.Periodicitate, SPONSORIZARI.Persoana,
SPONSORIZARI.Data, [ZIARE/REVISTE].NrPag
FROM (TIPURI_PRINC_INFO INNER JOIN (TIPOGRAFII INNER JOIN (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) ON TIPOGRAFII.[#T] = [ZIARE/REVISTE].Tipografie) ON TIPURI_PRINC_INFO.[#TipZiar/Rezista] = [ZIARE/REVISTE].TipZiar) INNER JOIN SPONSORIZARI ON [ZIARE/REVISTE].[#ZR] = SPONSORIZARI.[Ziar/RevistaSpons]
WHERE (((TIPURI_PRINC_INFO.[TipZiar/Rezista])<>'sport'))
GROUP BY [ZIARE/REVISTE].Nume, TIPOGRAFII.Tipografie, PERIODICITATI.Periodicitate, SPONSORIZARI.Persoana, SPONSORIZARI.Data, [ZIARE/REVISTE].NrPag
HAVING ((([ZIARE/REVISTE].NrPag)>35))
ORDER BY [ZIARE/REVISTE].Nume, TIPOGRAFII.Tipografie DESC , SPONSORIZARI.Persoana;
Executand aceasta interogare, se obtine urmatorul rezultat:
3.Nume&Perioada:Aflati numele si periodicitatea ziarului/revistei in functie de numele si prenumele sponsorului, numele acestuia putand fi introdus de la tastatura si putand afla informatii legate de 2 sponsori.
Avem o interogare bazata pe UNION intre informatiile primului sponsor si cele legate de cel de-al doilea sponsor.
3.1 Nume&PerioadaPrimulSponsor:
SELECT [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume] AS [Nume Prenume]
FROM (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) INNER JOIN (PERSOANE INNER JOIN SPONSORIZARI ON PERSOANE.[#P] = SPONSORIZARI.Persoana) ON [ZIARE/REVISTE].[#ZR] = SPONSORIZARI.[Ziar/RevistaSpons]
GROUP BY [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume], PERSOANE.Nume
HAVING (((PERSOANE.Nume)=[Introduceti numele primului sponsorului dorit]));
Executand aceasta interogare, de exemplu, pentru numele primului sponsor=Barbu asupra instantei curente a bd, se obtine urmatorul rezultat:
3.2Nume&PerioadaAlDoileaSponsor
SELECT [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume] AS [Nume Prenume]
FROM (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) INNER JOIN (PERSOANE INNER JOIN SPONSORIZARI ON PERSOANE.[#P] = SPONSORIZARI.Persoana) ON [ZIARE/REVISTE].[#ZR] = SPONSORIZARI.[Ziar/RevistaSpons]
GROUP BY [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume], PERSOANE.Nume
HAVING (((PERSOANE.Nume)=[Introduceti numele celui de-al 2-lea sponsor dorit]));
Executand aceasta interogare, de exemplu, pentru numele primului sponsor=Vasile instantei curente a bd, se obtine urmatorul rezultat:
Codul SQL pentru INTEROGAREA CU UNION(leaga cele 2 interogari)
SELECT [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume] AS [Nume Prenume]
FROM (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) INNER JOIN (PERSOANE INNER JOIN SPONSORIZARI ON PERSOANE.[#P] = SPONSORIZARI.Persoana) ON [ZIARE/REVISTE].[#ZR] = SPONSORIZARI.[Ziar/RevistaSpons]
GROUP BY [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume], PERSOANE.Nume
HAVING (((PERSOANE.Nume)=[Introduceti numele primului sponsorului dorit]))
UNION
SELECT [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume] AS [Nume Prenume]
FROM PERSOANE INNER JOIN ((PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) INNER JOIN SPONSORIZARI ON [ZIARE/REVISTE].[#ZR] = SPONSORIZARI.[Ziar/RevistaSpons]) ON PERSOANE.[#P] = SPONSORIZARI.Persoana
GROUP BY [ZIARE/REVISTE].Nume, PERIODICITATI.Periodicitate, [PERSOANE].[Nume] & ' ' & [PERSOANE].[Prenume], PERSOANE.Nume
HAVING (((PERSOANE.Nume)=[Introduceti numele celui de-al 2-lea sponsor dorit]));
4.ZiarePeriod Care sunt ziarele/revistele de moda lunare si care sunt ziarele/revistele de sport zilnice.Ordonatile crescator dupa numele ziarului/revistei si descrescator dupa tipul ziarului/revistei.
Avem o interogare cu operatorul Union ce se bazeaza pe informatiile din interogarile:
4.1ZiarModaLunar
SELECT [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista], PERIODICITATI.Periodicitate
FROM TIPURI_PRINC_INFO INNER JOIN (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) ON TIPURI_PRINC_INFO.[#TipZiar/Rezista] = [ZIARE/REVISTE].TipZiar
WHERE (((TIPURI_PRINC_INFO.[TipZiar/Rezista])='moda'))
GROUP BY [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista], PERIODICITATI.Periodicitate, [ZIARE/REVISTE].Nume
HAVING (((PERIODICITATI.Periodicitate)='Lunar'))
ORDER BY [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista] DESC;
4.2ZiarSportZilnic
SELECT [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista], PERIODICITATI.Periodicitate
FROM TIPURI_PRINC_INFO INNER JOIN (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) ON TIPURI_PRINC_INFO.[#TipZiar/Rezista] = [ZIARE/REVISTE].TipZiar
WHERE (((TIPURI_PRINC_INFO.[TipZiar/Rezista])='sport'))
GROUP BY [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista], PERIODICITATI.Periodicitate, [ZIARE/REVISTE].Nume
HAVING (((PERIODICITATI.Periodicitate)='Zilnic'))
ORDER BY [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista] DESC;
Codul SQL pentru INTEROGAREA CU UNION(leaga cele 2 interogari)
SELECT [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista]
FROM TIPURI_PRINC_INFO INNER JOIN (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) ON TIPURI_PRINC_INFO.[#TipZiar/Rezista] = [ZIARE/REVISTE].TipZiar
WHERE (((TIPURI_PRINC_INFO.[TipZiar/Rezista])='moda'))
GROUP BY PERIODICITATI.Periodicitate, [ZIARE/REVISTE].Nume, [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista]
HAVING (((PERIODICITATI.Periodicitate)='Lunar'))
ORDER BY [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista] DESC
UNION
SELECT [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista]
FROM TIPURI_PRINC_INFO INNER JOIN (PERIODICITATI INNER JOIN [ZIARE/REVISTE] ON PERIODICITATI.[#Per] = [ZIARE/REVISTE].Periodicitate) ON TIPURI_PRINC_INFO.[#TipZiar/Rezista] = [ZIARE/REVISTE].TipZiar
WHERE (((TIPURI_PRINC_INFO.[TipZiar/Rezista])='sport'))
GROUP BY PERIODICITATI.Periodicitate, [ZIARE/REVISTE].Nume, [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista]
HAVING (((PERIODICITATI.Periodicitate)='Zilnic'))
ORDER BY [ZIARE/REVISTE].Nume, TIPURI_PRINC_INFO.[TipZiar/Rezista] DESC;
5.TotalSponsorizariPerZiare/Reviste:Sa se calculeze submultimea denumirilor ziarelor/revistelor care sunt sponsorizate de cel putin m persoane , iar suma totala de sponsorizare a fiecrarui ziar depaseste x (LEI), precum si numarul corespunzator de sponsori .
In primul pas, pentru a ne limita de la inceput numai la datele relevante, se calculeaza submultimea ziarelor/revistelor al caror total de sponsorizari este minim x sicare auminim m sponsori:
Instructiunea SQL echivalenta (salvata sub numele de TotalSponsorizariPerZiar/Revista )este urmatoarea:
SELECT SPONSORIZARI.[Ziar/RevistaSpons], Sum(SPONSORIZARI.Suma) AS TotalSponsorizari, Count(SPONSORIZARI.Persoana) AS NrSponsori
FROM SPONSORIZARI
GROUP BY SPONSORIZARI.[Ziar/RevistaSpons]
HAVING (((Sum(SPONSORIZARI.Suma))>=[Total sponsorizare minim dorit:]) And ((Count(SPONSORIZARI.Persoana))>=[Numar minim de sponsori dorit:]));
Executand aceasta interogare, de exemplu, cu valorile m = 1,x = 4000, se obtine urmatorul rezultat:
6. DateSponsor: Sa se introduca numele sponsorului dorit si sa se afiseze numele ziarului sau revistei,data sponsorizari si suma sponsorizarii.
SELECT PERSOANE.Nume AS NumePersoana, [ZIARE/REVISTE].Nume AS NumeZiarSauRevista, SPONSORIZARI.Data AS DataSponsorizari, SPONSORIZARI.Suma AS SumaSponsorizari
FROM [ZIARE/REVISTE] INNER JOIN (PERSOANE INNER JOIN SPONSORIZARI ON PERSOANE.[#P] = SPONSORIZARI.Persoana) ON [ZIARE/REVISTE].[#ZR] = SPONSORIZARI.[Ziar/RevistaSpons]
WHERE (((PERSOANE.Nume) Like '*' & [Introduceti Numele(sau o parte a numelui) Sponsorului dorit al caror informatii doriti] & '*'))
GROUP BY PERSOANE.Nume, [ZIARE/REVISTE].Nume, SPONSORIZARI.Data, SPONSORIZARI.Suma;
Ne reamintim ca se doreste previzualizarea si tiparirea (totala sau partiala) a urmatorului raport: pe primul nivel - denumirea ziarelor/revistelor (in ordine crescatoare), pe al doilea (indentat) – periodicitatea acestora ( in ordine descrescatoare),numarul sponsorilor(in ordine crescatoare),tipografiile in care sunt tiparite,tipul ziarului,numele ziarului/revistei care sunt sponsorizate si totalul cu care a fost sponsorizat ziarul/revista; pe fiecare nivel se cer totaluri (Summary pentru numele ziarului/revistei si calculam cu” Sum”totalul sponsorizarilor per tipul de ziar).
6.3.1Proiectarea raportului folosind magicianul de rapoarte Access
Folosim Create raport by using wizard :
ne va aparea o imagine de unde selectam tabelele de unde ne alegem ceea ce vrem sa afisam:
nume,periodicitate din tabela”ZIARE/REVISTE”;
NrSponsori din :query”TotalSponsorizariPerZiar/Revista”;
tipografie si tipziar(din ZIARE/REVISTE);
in final ziar/revistaspons si totalsponsorizari(din query).
precizam apoi faptul ca, in cadrul acestui grup, dorim listarea in ordinea crescatoare a NrSponsori;
in sfarsit, alegem formatul Stepped, listarea de-a latul paginilor (Landscape, caci sunt multe coloane de listat) si salvam raportul, care se va deschide automat in pre-vizualizare:
Se observa ca, din pacate, mai sunt inca multe lucruri de modificat manual in proiectul sau, astfel incat el sa corespunda exigentelor utilizatorilor:
Schimbare titlu;
Reasezare in pagina si marire dimensiune coloane (pentru ca datele sa nu mai fie trunchiate);
Dupa efectuarea acestor modificari, prima pagina a raportului arata astfel,ptr urmatoarele valori:
DesignView:
Ne reamintim ca se doreste previzualizarea si tiparirea (totala sau partiala) a urmatorului raport: pe primul nivel – totalul sumei sponsorizat(in ordine crescatoare), pe al doilea (indentat) – numele sponsorilor;iar,pe ultimul numarul de ziare/reviste sponsorizate.
6.4.1Proiectarea raportului folosind magicianul de rapoarte Access
Folosim Create raport by using wizard :
ne va aparea o imagine de unde selectam tabelele/queries de unde ne alegem ceea ce vrem sa afisam:
totalul sumei sponsorizarii;
numele sponsorului;
numarul de ziare/reviste sponsorizate.
Se observa ca, din pacate, mai sunt inca multe lucruri de modificat manual in proiectul sau, astfel incat el sa corespunda exigentelor utilizatorilor:
Schimbare titlu;
Reasezare in pagina si marire dimensiune coloane (pentru ca datele sa nu mai fie trunchiate);
Dupa efectuarea acestor modificari, prima pagina a raportului arata astfel,ptr urmatoarele valori:
DesignView:
Desigur ca aplicatia trebuie sa ofere utilizatorilor in primul rand posibilitatea de a actualiza datele din bd TiparituriPeriodice.mdb , precum si pe cea a executiei prietenoase interogarilor si a raportului. Ca atare, ea va fi dotata si cu un meniu arborescent de comenzi (folosind standardul Access al panourilor cu butoane).
Cum structura bd dicteaza pe nivelul frunzelor arhitectura claselor de obiecte, incepem proiectarea acesteia de jos in sus, construind intai pentru fiecare tabela (deci multime de obiecte modelata in MMED) cate o clasa.
Toate aceste clase fundamentale vor afisa datele din tabela respectiva exact ca si tabelele (in mod „foaie de date”) si vor contine cel putin metodele de sincronizare a datelor din listele derulante corespunzand cheilor straine, astfel incat utilizatorii sa poata lucra, la limita, cu toate aceste ferestre deschise simultan, iar propagarea oricaror modificari ale instantei oricarei tabele in intreaga bd sa fie automata si transparenta utilizatorului.
In plus, pentru ca utilizatorul sa nici macar nu vada cheile primare, vom seta pentru acestea proprietatea TabStop la False si vom salva formele dupa ce ascundem coloanele respective (cu ajutorul mouse-ului) prin reducerea dimensiunii lor la 0 (singura modalitate de a le face invizibile in formatul „foaie de date”). O buna practica este si aceea de a le salva dupa ce le-am ordonat crescator in ordinea celei mai naturale (pentru utilizatori) chei semantice.
Alte setari comune tuturor acestor forme care mai trebuie schimbate:
AllowFormView=No
AllowPivotTableView=No
AllowPivotChartView=No
De verificat intotdeauna (pentru a permite actualizari concurente in mod optim) si ca:
RecordLocks=EditedRecords
Pentru testare si ulterioare extensii cat mai usoare, cream aceste clase (cu ajutorul magicianului de forme) exact in ordinea in care au fost ele considerate in schema MMED.
1.TIPURI_PRINC_INFO
Fereastra corespunzatoare rezultata este urmatoarea:
Clasa contine metodele:
Private Sub Form_AfterUpdate()
On Error Resume Next
Forms!ZIAREREVISTE!TipZiar.Requery
End Sub
Private Sub Form_Delete(Cancel As Integer)
On Error GoTo err_point
If vbNo=MsgBox('Sigur doriti stergerea tipului ' & Me!TipZiar & '?', _
vbQuestion + vbYesNo + vbDefaultButton2, _
'Confirmati sau infirmati cererea Dvs') Then
Cancel = True
End If
exit_point: Exit Sub
err_point: MsgBox Err.Description
End Sub
Private Sub Form_BeforeDelConfirm(Cancel As Integer, _
Response As Integer)
Response = acDataErrContinue
End Su
2.PERIODICITATI
Fereastra corespunzatoare rezultata este urmatoarea:
Private Sub Form_AfterDelConfirm(Status As Integer)
If Status = acDeleteOK Then
On Error Resume Next
Forms!ZIAREREVISTE!Periodicitate.Requery
End If
End Sub
Private Sub Form_AfterUpdate()
On Error Resume Next
Forms!ZIAREREVISTE!Periodicitate.Requery
End Sub
Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer)
Response = acDataErrContinue
End Sub
Private Sub Form_Delete(Cancel As Integer)
On Error GoTo err_point
If vbNo = MsgBox('Sigur doriti stergerea tipului ' & Me!Periodicitate & '?', _
vbQuestion + vbYesNo + vbDefaultButton2, _
'Confirmati sau infirmati cererea Dvs') Then
Cancel = True
End If
exit_point: Exit Sub
err_point: MsgBox Err.Description
End Sub
3.TIPOGRAFII
Fereastra corespunzatoare rezultata este urmatoarea:
Private Sub Form_AfterDelConfirm(Status As Integer)
If Status = acDeleteOK Then
On Error Resume Next
Forms!ZIAREREVISTE!Tipografie.Requery
End If
End Sub
Private Sub Form_AfterUpdate()
On Error Resume Next
Forms!ZIAREREVISTE!Tipografie.Requery
End Sub
Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer)
Response = acDataErrContinue
End Sub
Private Sub Form_Delete(Cancel As Integer)
On Error GoTo err_point
If vbNo = MsgBox('Sigur doriti stergerea tipului ' & Me!Tipografie & '?', _
vbQuestion + vbYesNo + vbDefaultButton2, _
'Confirmati sau infirmati cererea Dvs') Then
Cancel = True
End If
exit_point: Exit Sub
err_point: MsgBox Err.Description
End Sub
4.PERSOANE
Fereastra corespunzatoare rezultata este urmatoarea:
Private Sub Form_AfterUpdate()
On Error Resume Next
Forms!SPONSORIZARI!Persoana.Requery
End Sub
Private Sub Form_Delete(Cancel As Integer)
On Error GoTo err_point
If vbNo = MsgBox('Sigur doriti stergerea persoanei ' & Me!Nume & ' ' & Me!Prenume & '?', vbQuestion + vbYesNo + vbDefaultButton2, 'Confirmati sau infirmati cererea Dvs') Then
Cancel = True
End If
exit_point: Exit Sub
err_point: MsgBox Err.Description
End Sub
Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer)
Response = acDataErrContinue
End Sub
Private Sub Form_AfterDelConfirm(Status As Integer)
If Status = acDeleteOK Then
On Error Resume Next
Forms!SPONSORIZARI!Persoana.Requery
End If
End Sub
5.SPONSORIZARI
Fereastra corespunzatoare rezultata este urmatoarea:
Private Sub Form_Delete(Cancel As Integer)
On Error GoTo err_point
If vbNo = MsgBox('Sigur doriti stergerea sponsorizarii ziarului/revistei ''' _
& DLookup('Nume', 'ZIARE/REVISTE', 'IdZR=' & Me!Ziar / RevistaSpons) _
& ''' de catre persoana ' _
& DLookup('Persoana', 'PERSOANE', 'IdP=' & Me!Persona) & '?', _
vbQuestion + vbYesNo + vbDefaultButton2, _
'Confirmati sau infirmati cererea Dvs') Then
Cancel = True
End If
exit_point: Exit Sub
err_point: MsgBox Err.Description
End Sub
Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer)
Response = acDataErrContinue
End Sub
Formele proiectate si implementate in subsectiunea anterioara permit utilizatorilor actualizarea corecta si completa a datelor din bd a aplicatiei. Totusi ea nu ar fi si prietenoasa. Pentru aceasta, proiectam si implementam in aceasta sectiune o forma centrala de actualizare a datelor, care incearca sa satisfaca si acest deziderat oferind in plus tab-uri cu subforme (pentru datele cele mai frecvent actualizate), butoane (pentru cele mai rar actualizate, dar si pentru raport si cele doua interogari frecvente, ca si pentru iesirea directa din aplicatie) si o lista derulanta pentru pozitionare rapida pe orice alta inregistrare dorita de utilizator.
Fiind multimea centrala in DE-A structurala, alegem ZIARE/REVISTE drept tabela pe care se bazeaza aceasta forma, ea va avea 2 tab-uri, fiecare din acestea oferind cate una din subformele SPONSORIZARI si extensii viitoare.
ZIARE/REVISTE poate fi pentru inceput proiectata cu ajutorul magicianului de forme, alegand formatul Columnar. Apoi ascundem controlul #ZR (stergandu-i eticheta si setand proprietatile Visible=No, iar TabStop= No), aranjam coloanele sale astfel incat sa ocupe cat mai putin spatiu din antetul formei si setam in mod standard proprietatile acestei forme ce va afisa emisiunile una cate una :
(AllowDatasheetView=No,AllowPivotTableView=No, AllowPivotChartView=No, RecordSelectors=No, DividingLines=No).
Pentru pozitionare rapida pe orice alt Ziar/revista, alegem din Toolbox optiunea Combobox si, cu ajutorul magicianului de liste derulante (caruia ii cerem a treia optiune: Find a record on my form based on a value I selected in my combobox, iar apoi, drept coloane, doar #ZR si Nume), plasam in coltul din dreapta sus al formei o lista derulanta numita AltZiar; pentru ca utilizatorul sa nu faca confuzie intre ea si controlul Nume, o coloram in albastru inchis si ii afisam datele italic si bold; apoi, redenumim controlul ( in AltZiar), dar si metoda automat generata pentru sincronizare (din Combon_AfterUpdate in AltZiar_AfterUpdate), precum si referirea la control in corpul ei; noua metoda rezultata este urmatoarea:
Private Sub AltZiar_AfterUpdate()
' Find the record that matches the control.
Dim rs As Object
Set rs = Me.Recordset.Clone
rs.FindFirst '[#ZR] = ' & Str(Nz(Me![AltZiare], 0))
If Not rs.EOF Then Me.Bookmark = rs.Bookmark
End Sub
In fine, modificam proprietatile sale pentru a afisa datele crescator si a mari numarul de linii al listei derulante (de la 8 la macar 32), iar in StatusBarText si ControlTipText salvam textul „Pozitionare rapida pe alt ziar”:
Revenind la modul de proiectare al formei, adaugam sub antet (tot din Toolbox), lasand o banda libera pentru butoane, un control de tip tab (caruia, la cele doua pagini automat generate, ii mai adaugam inca una); redenumim paginile, in ordine, SPONSORIZARI si Extensii viitoare si le marim dimensiunea pentru a ocupa cu ele intreg ecranul.
Selectand prima dintre ele si apoi iconita Subform/Subreport a meniului Toolbox, se activeaza magicianul de legare a formelor: alegem forma SPONSORIZARI si acceptam optiunea implicita de legare a datelor intre cele doua forme oferita de acesta si care corespunde legaturii intre cele doua tabele .
Similar, adaugam butoane pentru lansarea in executie a celor 2 interogari (carora le vom interzice posibilitatea actualizarii datelor, prin inlocuirea parametrului automat generat acEdit cu acReadOnly!) si a rapoartelor; clasa ZIARE/REVISTE se imbogateste astfel cu urmatoarele noi metode:
Private Sub SponsoriImportantiButton_Click()
On Error GoTo Err_SponsoriImportantiButton_Click
DoCmd.OpenQuery 'SponsoriImportantii', acNormal, acReadOnly
Exit_SponsoriImportantiButton_Click: Exit Sub
Err_SponsoriImportantiButton_Click: MsgBox Err.Description
End Sub
Private Sub TotalSponsPerZiarButton_Click()
On Error GoTo Err_TotalSponsPerZiarButton_Click
DoCmd.OpenQuery'TotalSponsorizariPerZiar/Revista',acNormal, acReadOnly
Exit_TotalSponsPerZiarButton_Click: Exit Sub
Err_TotalSponsPerZiarButton_Click: MsgBox Err.Description
End Sub
Private Sub SponsoriImportantiRaportButton_Click()
On Error GoTo Err_SponsoriImportantiRaportButton_Click
DoCmd.OpenReport 'SponsoriImportantii', acPreview
Exit_SponsoriImportantiRaportButton_Click: Exit Sub
Err_SponsoriImportantiRaportButton_Click: MsgBox Err.Description
End Sub
Private Sub TotalSponsorizariPerZiarRaportButton_Click()
On Error GoTo Err_TotalSponsorizariPerZiarRaportButton_Click
DoCmd.OpenReport 'TOTAL SPONSORIZARI per ZIARE/REVISTE', acPreview
Exit_TotalSponsorizariPerZiarRaportButton_Click: Exit Sub
Err_TotalSponsorizariPerZiarRaportButton_Click: MsgBox Err.Description
End Sub
Deoarece utilizatorii ar putea avea nevoie sa faca calcule aritmetice pentru sponsorizari (altele decat totalul per emisiune) si pentru a nu-i obliga sa paraseasca forma si sa caute calculatorul sistemului de operare, am adaugat si un buton care sa apeleze acest calculator:
Private Sub CalcButton_Click()
On Error GoTo Err_CalcButton_Click
Dim stAppName As String
stAppName = 'C:WINDOWSsystem32calc.exe'
Call Shell(stAppName, 1)
Exit_CalcButton_Click: Exit Sub
Err_CalcButton_Click: MsgBox Err.Description
End Sub
In fine, pentru a permite utilizatorilor sa si termine lucrul cu aplicatia direct din aceasta forma (fara a se mai intoarce in meniu), adaugam si un buton de stop si metoda sa corespunzatoare:
Private Sub StopButton_Click()
On Error GoTo Err_StopButton_Click
If vbYes = MsgBox('Sigur doriti terminarea lucrului cu aplicatia si ' _
& 'inchiderea ei?', vbQuestion + vbYesNo + vbDefaultButton2, _
'Confirmati sau infirmati comanda Dvs') Then
DoCmd.Quit
End If
Exit_StopButton_Click: Exit Sub
Err_StopButton_Click: MsgBox Err.Description
End Sub
Pe nivelul sau radacina, oferim utilizatorilor optiunile de actualizare date, executie interogari, previzualizari rapoarte si terminare a aplicatiei:
Pe nivelul actualizarii datelor, oferim formele Ziare sau Reviste, PERIODICITATI, SPONSORIZARI (pentru datele cel mai frecvent modificabile), precum si salt pe un nivel ierarhic inferior pentru posibilitatea actualizarii restului datelor:
Pe nivelul actualizarii datelor mai rar modificabile, oferim formele Ziare/Reviste, TIPURI ZIARE sau REVISTE si TIPOGRAFII:
Pe nivelul interogarilor, oferim, desigur, cele doua interogari (SponsoriImportanti si TotalSponsorizariPerZiar/Revista); pentru simplitate, construim pentru fiecare dintre ele (cu ajutorul magicianului de forme) cate o forma tabulara omonima; pentru a le oferi doar in citire si cat mai rapid cu putinta, trebuie ca fiecareia dintre ele sa-i setam corect urmatoarele proprietati (din tab-ul Properties/Form/Data):
Nivelul meniului dedicat interogarilor rezulta astfel:
Desigur, pe nivelul rapoartelor oferim cele doua rapoarte disponibile:
Am ales arbitrar subuniversul Tiparituri periodice in Bucuresti, pentru care am stabilit informal multimile de obiecte, proprietatile acestora, restrictiile ce le guverneaza (considerate a fi singurele de interes), precum si trei interogari si un raport (plauzibile si folositoare) pe care utilizatorii unei aplicatii de bd pentru asistenta gestionarii acestui subunivers le-ar dori.
Am analizat subuniversul ales si am proiectat bd conceptuala necesara pe trei niveluri de abstractizare: diagrame entitati-asociatii, matematic si relational. Am implementat schema relationala obtinuta in Access 2003, obtinand bd TiparituriPeriodice.mdb.mdb.
|