Sunteți pe pagina 1din 60

CAPITOLUL 5

SISTEME DE GESTIUNE A BAZELOR DE DATE. ACCESS

Sumar:

 Prezentare generală
 Crearea şi actualizarea bazelor de date
 Formulare
 Interogare
 Rapoarte
 Programe, aplicaţii şi meniuri
2 Instrumente software pentru afaceri

5.1 SGBD ACCESS – PREZENTARE GENERALĂ

ACCESS este un sistem de gestiune a bazelor de date integrat în pachetul MS Office destinat
pentru uzul personal, pentru munca în grup sau pentru mici afaceri. Fiind, probabil, cel mai utilizat
instrument software dedicat bazelor de date, ACCESS oferă următoarele facilităţi majore:
 dispune de o interfaţă uşor de folosit pentru introducerea datelor;
 „găseşte” rapid datele legate între ele;
 asigură afişarea pe ecran sau tipărirea la imprimantă a datelor într-un format uşor de înţeles;
 permite afişarea datelor sub formă de grafice sau ca pagini Web;
 are incluse mecanisme pentru exportul datelor în Excel şi /sau Word;
 asigură protejarea datelor de erori;
 automatizează operaţiile comune pentru a reduce timpul de dactilografiere.
ACCESS este conceput pentru scenarii multiutilizator, ceea ce înseamnă că mai mulţi
utilizatori pot accesa aceleaşi tipuri de date în acelaşi timp. Teoretic o bază de date ACCESS 2003 se
poate adapta pentru 255 de utilizatori simultan.

Deschiderea sesiunii de lucru ACCESS


Ca şi în cazul celorlalte componente MS Office, ACCESS se poate lansa în mai multe moduri:
 meniul Start (figura 5.1), selectând din meniul Programs opţiunea Microsoft Office ACCESS
2003,

Figura 5.1 Deschiderea sesiunii ACCESS din Figura 5. 2 Deschiderea sesiunii ACCESS din
meniul Start meniul rapid

 meniul rapid (figura 5.2), selectând comanda New şi apoi opţiunea Microsoft Office ACCESS
Application;

Figura 5. 3 Deschiderea sesiunii ACCESS prin schortcut-ul de pe Desktop


Sistemul de gestiune a bazelor de date ACCESS 3

 shortcut-ul de pe Desktop (figura 5.3), accesând pictograma de pe desktop, dacă a fost creată o
scurtătură ACCESS 2003.

Interfaţa ACCESS
Dialogul utilizator-sistem se realizează, prin intermediul interfeţei ACCESS constituită, în
principal, din linia instrumente Database, linia de meniuri şi panoul de activităţi.
Linia /Bara de instrumente Database, pe lângă butoanele prezente în liniile Standard ale
altor produse MS Office, are în componenţă o serie de butoane specifice:

OfficeLinks – permite fuzionarea (Merge) sau publicarea (Publish) datelor în Word


sau analiza (Analyze) datelor folosind Excel.

Analyze - lansează unul dintre utilitarele de analiză: Alayze Table, Analyze


Performance sau Documenter.

Relationships – reprezintă grafic relaţiile existente şi permite modificarea acestora sau


crearea altora noi.
Linia de meniuri organizează meniurile ferestrelor ACCESS. Comenzile meniurilor permit:
 manipularea fişierelor bazei de date ACCESS;
 crearea şi modificarea obiectelor bazei de date;
 partajarea datelor cu alte aplicaţii;
 personalizarea mediului ACCESS.
La deschiderea sesiunii este activat, în dreapta ecranului, panoul de activităţi Task Pane care
oferă o serie de legături, ce diferă în funcţie de operaţia în curs de derulare (figura 5.4):
 Connect to Microsoft Office online – conectarea online la pagina Microsoft Office;
 Search for... - căutarea în funcţie de anumite criterii;
 Open – deschiderea unuia dintre fişierele aflate în lista ultimelor fişiere cu care s-a lucrat, sau
a unui alt fişier, căutat cu ajutorul butonului More...care deschide o fereastră Open;
 Create a new file... – crearea unui nou fişier.
Afişarea sau ascunderea panoului de activităţi se realizează din meniul View, prin comanda
Task Pane.

Figura 5.4 Task Pane Figura 5.5 Task Pane – New File
4 Instrumente software pentru afaceri

Dacă se optează pentru crearea unui nou fişier, Task Pane oferă mai multe variante (figura
5.5):
 Blank database - crearea unei baze de date „goale” care nu conţine date sau orice alte obiecte
(opţiunea cea mai des utilizată);
 From Existing File – crearea unei baze de date noi folosind structura unei baze de date
existente;
 On my computer – construirea unei baze de date dintr-un fişier şablon;
 Project using existing data şi Project using new data - proiectele ACCESS combină
interfaţa prietenoasă cu utilizatorul a programului ACCESS cu puterea unui server de baze de
date performant, cum este Microsoft SQL Server.
Proiectele ACCESS permit dezvoltarea unor noi aplicaţii client-server în următoarele situaţii
mai complexe:
 datele sunt foarte importante; nu se acceptă nici un fel de pierderi de date şi nici o
indisponibilitate temporară a datelor;
 datele vor fi folosite simultan de mai multe persoane. ACCESS admite cel mult 255 de
utilizatori, dar performanţele pot fi mult diminuate dacă utilizatorii sunt deosebit de activi;
 baza de date va avea dimensiuni foarte mari.
Configurarea sesiunii de lucru în ACCESS
Ca şi alte produse software, ACCESS permite stabilirea unor parametrii de lucru pentru
sesiunea curentă şi, eventual, a sesiunilor următoare. În acest scop se activează din meniul Tools,
comanda Options. Fereastra acestei comenzi este structurată pe numeroase cadre de pagină: View,
General, Edit/Find, International etc.
Vizăm în continuare doar cadrul de pagină General care, printre altele, permite stabilirea unui
director implicit în care vor fi salvate fişierele. Pentru exemplificare, din raţiuni lesne de înţeles, în
zona Default database folder:, s-a declarat ca director curent D:\FEAA\Anul2005-
2006\Instrumente software pentru afaceri\ISA_ZI\Capitolul 5 (figura 5.6).

Figura 5.6 Declararea unui director implicit

Închiderea sesiunii ACCESS

O sesiune de lucru ACCESS se poate închide folosind:


 Butonul Close (X) al ferestrei ACCESS;
Sistemul de gestiune a bazelor de date ACCESS 5

 Comanda Exit, din meniul File.


În ambele variante este asigurată şi închiderea şi salvarea bazei de date deschisă în acel
moment.
Tipuri de obiecte în proiectele ACCESS
Un proiect ACCESS se organizează în jurul unei baze de date şi poate conţine următoarele
tipuri de obiecte:
 Tabele (Tables) – reprezintă locul în care sunt stocate datele brute ale unei baze de date;
 Interogări (Queries) – tabele care conţin răspunsuri la anumite „întrebări” despre date;
 Formulare (Forms) – componente care oferă o interfaţă de introducere şi afişare a
datelor;
 Rapoarte (Reports) – facilităţi care oferă diferite modalităţi de afişare /tipărire a datelor
conţinute în tabele;
 Pagini (Pages) – sunt asemănătoare formularelor, în plus ele pot fi afişate într-un browser
Web. Astfel, ACCESS este prima bază de date care permite transferul datelor pe un site
Web;
 Macro-uri (Macros) - sunt liste de comenzi pe care ACCESS le poate salva şi executa;
 Module (Modules) – sunt obiecte care conţin coduri de program, scrise în VBA.
Modulele oferă utilizatorilor avansaţi posibilitatea de a personaliza bazele de date şi
conţinutul acestora.
Deoarece un proiect poate conţine până la mii de astfel de obiecte, pentru a le referi uşor
ACCESS oferă două modalităţi:
 gruparea obiectelor prin crearea de subseturi ale obiectelor şi
 utilizarea scurtăturilor pentru lansarea ACCESS-ului şi deschiderea unui obiect
particular (formular, raport) direct de pe desktop.

5.2 CREAREA ŞI ACTUALIZAREA BAZELOR DE DATE ACCESS


Orice proiect de lucru cu o bază de date demarează cu crearea tabelelor din bază şi definirea
restricţiilor. Crearea tabelelor presupune declararea numelui, tipului, lungimii şi altor proprietăţi
pentru fiecare atribut.

5.2.1 Tipuri de date


În tabelele ACCESS pot fi organizate diverse tipuri de date. Pentru fiecare câmp dintr-o tabelă
trebuie stabilit un tip de dată prin care se controlează natura şi cantitatea de date ce poate fi introdusă.
Sunt disponibile următoarele tipuri de date:
 Text – este folosit pentru stocarea şirurilor de cel mult 255 de caractere alfanumerice
(litere, numere, simboluri etc.);
 Memo – este indicat pentru a stoca şiruri care depăşesc 255 de caractere, nu sunt
structurate şi /sau au un anumit caracter de confidenţialitate; conţinutul câmpurilor memo
nu este vizualizat atunci când se afişează conţinutul tabelelor;
 Number – acceptă doar date numerice (întregi sau cu zecimale), cu un număr suficient de
poziţii, pentru aproape toate datele economice. La rândul lor datele numerice pot fi
reprezentate în diferite formate: Byte, Long Integer, Single, Double, Replication ID,
Decimal;
6 Instrumente software pentru afaceri

 Date /Time General Date – este tipul de date folosit pentru a stoca data calendaristică
şi/sau timpul şi are mai multe formate: Long Date, Medium Date, Short Date, Long Time,
Medium Time, Short Time;
 Currency – este asemănător datelor numerice, cu deosebirea că acceptă doar patru digiţi
pentru partea zecimală. Este conceput pentru a evita erorile de rotunjire, astfel încât
calculele cu bani să fie precise. Şi datele de acest tip pot avea mai multe formate: General
Number, Format Euro, Currency, Fexed, Standard, Percent, Scientific;
 AutoNumber – este o variantă specială a datelor Number. Este recomandat în procedura
de stabilire a cheii primare, atunci când din structura tabelei este dificil de ales un câmp
reprezentativ. Formatele pentru AutoNumber sunt: Long Integer, Replication ID;
 Yes /No - este conceput pentru a păstra înregistrări simple On /off. Formatele pot fi: True
/False, On/Off;
 Ole Object – permite stocarea informaţiilor într-un format accesibil altor programe
(documente Word, foi de calcul Excel, imagini, fişiere cu muzică etc.)
 Hyperlink – este un tip de date text special conceput pentru a stoca hyperlink-uri către
site-uri Web sau alte resurse Internet;
 Lookup Wizard – câmp special de căutare.
Remarcăm disponibilitatea datelor de tip Lookup Wizard care sunt folosite pentru a declara
câmpuri de căutare. Majoritatea bazelor de date organizează două tipuri de tabele: cele care includ
date primare şi cele care conţin liste de valori folosite în tabele. Aceste tabele auxiliare se numesc
tabele de căutare (lookup tables) şi prezintă două avantaje: pun la dispoziţia utilizatorului opţiuni
consecvente şi simplu de utilizat şi permit validarea datelor, acceptând numai datele din tabel. Dacă
lista intrărilor posibile pentru un câmp este redusă şi are o perioadă mare de valabilitate se poate crea
un tabel de căutare bazat pe o lista de valori introduse, nu pe tabel (de exemplu, pentru câmpul stare
civilă, se poate introduce o listă de valori Căsătorit şi Necăsătorit). Dacă se optează pentru utilizarea
unui câmp cu valori posibile, este necesară crearea unui tabel de căutare înainte de a putea folosi
tabelul pentru a crea un câmp de căutare într-un alt tabel.
Fiecare tip de date poate fi personalizat prin intermediul proprietăţilor. Aceste proprietăţi se
stabilesc prin fereastra proiectantului de tabele Design View.

Observaţie: În expresii constantele de tip text sunt incluse între ghilimele (de exemplu, „FEAA”),
iar datele calendaristice sunt încadrate de semnul # (de exemplu, #12/18/2005#).

O noutate deosebită în ACCESS 2003 o reprezintă etichetele inteligente (Smart Tags) care
pot fi aplicate câmpurilor. Această facilitate este preluată din Excel care foloseşte etichete inteligente
pentru a semnaliza erorile din foile de calcul şi pentru a oferi soluţii posibile. Prin etichete inteligente
se pot accesa informaţii de pe Internet sau îndeplini anumite sarcini. În principal, aceste etichete sunt
oferite de Microsoft şi cele mai multe dintre ele sunt gratuite.

5.2.2 Crearea /construirea tabelelor


Tabelele, fiind obiecte componente ale bazelor de date, presupun, ca primă etapă, obţinerea
bazei de date din care vor face parte. Dacă se optează pentru Blank database trebuie precizate
Sistemul de gestiune a bazelor de date ACCESS 7

locaţia, numele şi tipul unui astfel de fişier. Implicit, ACCESS atribuie numele md<n> şi extensia
.mdb (figura 5.7). Este recomandat ca numele fişierului să sugereze conţinutul informaţional sau
apartenenţa de o aplicaţie sau un utilizator. Exemplificările din acest capitol au ca suport baza de date
vinzări.mdb.

Locaţia în care va fi
salvată BD

Numele BD
Extensia implicită
a BD

Figura 5.7 Fereastra File New Database

Pentru crearea unui tabel ACCESS oferă trei posibilităţi (figura 5.8):

Opţiuni pentru crearea


tabelelor unei BD

Obiectele unei BD

Figura 5.8 Opţiuni pentru creare tabelelor unei Baze de date

 Create table in Design view - folosind modul de proiectare a tabelului; este cea mai
puternică şi mai flexibilă modalitate fiind specificate detaliile fiecărui câmp;
 Create table using wizard - apelând asistentul Table Wizard care precizează paşii care
trebuie urmaţi pentru construirea unor tabele obişnuite;
 Create table by entering date – introducând datele în câmpurile create de ACCESS;
această metodă este apropiată de modul de lucru în Excel.
Crearea tabelelor prin introducerea datelor
Cea mai „confortabilă” pentru începători este crearea tabelelor prin introducerea datelor. Dacă
se alege aceasta opţiune, în etapa imediat următoare se cere confirmarea salvării tabelului şi, implicit,
precizarea numelui acestuia într-o fereastră Save As. Pentru exemplificare, în baza de date Vinzări se
creează tabela Clienti (figura 5.9).
8 Instrumente software pentru afaceri

Figura 5.9 Ferastra Save As pentru tabela Clienti

În continuare, se deschide o fereastră în care coloanele, reprezentând câmpurile, au nume


predefinite de tipul Field<n>. Pe rândurile tabelului se introduc înregistrările /articolele (figura 5.10).

Figura 5.10 Fereastra Create table by entering date pentru tabela Clienţi

Figura 5.11 Comanda Rename Column

Pentru stabili nume de atribue care sugerează conţinutul este necesară redenumirea. Se
foloseşte comanda Rename Column apelată fie din meniul rapid (activat de pe antetul /header-ul
câmpului /coloanei), fie din meniul Format (figura 5.11). Intrarea în modul de editare este posibil şi
prin dublu click de mouse de pe antetul câmpului al cărui nume urmează a fi schimbat.
Crearea tabelelor folosind Table Wizard
Table Wizard este un instrument care permite crearea tabelelor prin parcurgerea unor paşi
prestabiliţi. Pentru exemplificare s-a dorit crearea tabelei CodPost_loc. Într-un prim pas sunt stabilite
câmpurile care vor constitui structura noii tabele. ACCESS oferă variate şabloane atât pentru domeniul
afacerilor (Business) cât şi cu caracter personal, după uzanţele americane. Folosind butonul Rename
Sistemul de gestiune a bazelor de date ACCESS 9

Field se pot personaliza machetele pentru articole, în sensul că structurile pot fi adaptate la specificul
aplicaţiei ce se proiectează (figura 5.12).

Tipuri de şabloane
Structuri de articole

Redenumirea unui
câmp

Figura 5.12 Stabilirea câmpurilor într-o tabelă creată cu Table wizard

După stabilirea câmpurilor, în pasul următor se precizează numele sub care va fi salvată tabela
şi modalitatea în care va fi stabilită cheia primară (vezi paragraful 4.3.4), de către utilizator sau,
implicit, de către ACCESS (figurile 5.13 şi 5.14).
Numele tabelei

Stabilirea cheii primare


de către Access prin
câmpul AutoNumber

Stabilirea cheii primare


de către utilizator

Figura 5.13 Precizarea numelui şi a opţiunii pentru stabilirea cheii primare


10 Instrumente software pentru afaceri

Cheia primară stabilită


de Access

Cheia primară stabilită de


utilizator

Figura 5.14 Stabilirea cheii primare

După precizarea cheii primare se alege modul în care se va continua după crearea tabelei, fiind
disponibile opţiunile (figura 5.15):
 modificarea în Table Design;
 introducerea datelor direct în tabelă; aceasta este varianta pentru care am optat în
exemplificarea de mai jos;
 introducerea datelor în tabelă folosind un formular creat de un asistent /wizard ACCESS.
4

Opţiuni prin care se


stabileşte maniera de
lucru cu tabela, după
creare

Figura 5.15 Opţiunea de introducere a datelor direct în tabelă

Introducerea datelor în
tabelă

Figura 5.16 Introducerea datelor în tabelă


Sistemul de gestiune a bazelor de date ACCESS 11

După parcurgerea acestor paşi are loc introducerea datelor în tabelă (figura 5.16).

Crearea tabelelor folosind Design View


Cea mai complexă modalitatea de obţinere a tabelelor unei baze de date o oferă Design View
în a cărui fereastră pot fi stabilite: numele câmpurilor, tipul datelor şi proprietăţile acestora, cheia
primară etc. Exemplificăm obţinerea celei de a treia tabele din baza de date vinzari.mdb.

Stabilirea cheii
primare

Figura 5.17 Stabilirea cheii primare

Primul câmp, numărul facturii, este de tip numeric şi este reprezentat în formatul Long
Integer. Acest format a fost ales ca proprietate din lista General. În plus, acest câmp a fost desemnat

cheie primară. Stabilirea acestei chei se poate realiza fie activând pictograma Primary Key din
linia cu instrumente Database, fie selectând comanda Primary Key din meniul rapid activat de pe
numele câmpului (figura 5.17). Din lista General se stabilesc proprietăţile şi pentru celelalte câmpuri
(figurile 5.18 şi 5.19).

Stabilirea formatului pentru


data calendaristică

Figura 5.18 Stabilirea formatului pentru data calendaristică


12 Instrumente software pentru afaceri

Figura 5.19 Stabilirea formatului pentru o dată numerică

După crearea tuturor tabelelor şi popularea acestora cu articole fereastra Database, pentru
baza de date vinzari este prezentată în figura 5.20. Pictogramele din linia cu instrumentele Database
permit realizarea unor operaţii specifice.

Figura 5.20 Fereastra Database pentru vinzari.mbd

Figura 5.21. Comenzi pentru adăugarea unui nou câmp


Sistemul de gestiune a bazelor de date ACCESS 13

Este posibilă modificarea structurii unei tabele în sensul că pot fi adăugate şi /sau şterse
câmpuri sau pot fi modificate atributele acestora. Adăugarea unui câmp se realizează fie din meniul
Insert, fie din cel rapid, ambele selectate când prompterul este poziţionat pe câmpul la stânga căruia
se va insera unul nou (figura 5.21).
Ştergerea unuia sau mai multor câmpuri presupune selectarea şi apoi activarea comenzii
Delete fie din meniul Edit, fie din cel rapid (figura 5.22).

Figura 5.22 Comenzi pentru ştergerea unui atribut

5.2.3 Declararea restricţiilor


Paragraful 4.3 a fost consacrat tipologiei restricţiilor într-o bază de date relaţională, restricţii
care cresc gradul de încredere în baza de date prin prevenirea a o serie de erori ce pot interveni la
inserarea, modificarea sau ştergerea de linii într-o tabelă. Pentru acomodare, ilustrarea practică a o
serie de restricţii a fost făcută pe exemplul ACCESS-ului. Aşa încât sarcina noastră din acest paragraf
este destul de uşoară. Faţă de ceea ce discutam în capitolul 4, ar mai fi de adăugat că este
recomandabil ca declararea resticţiilor să fie făcută odată cu crearea tabelelor sau imediat după, în
orice caz, înaintea de preluarea vreunei înregistrări în bază. Aceasta asigură preluarea corectă a tuturor
informaţiilor în tabele.

Figura 5.23. Trei click – uri


14 Instrumente software pentru afaceri

Ca şi crearea tabelelor, declararea şi modificarea ulterioară a restricţiilor decurge cât se poate


de natural în ACCESS. După deschiderea bazei de date, sunt suficiente trei click-uri mari şi late pentru
a (re)intra în proiectantul tabelei CLIENŢI – vezi figura 5.23.
În figura 4.7 am ilustrat modul în care, setând opţiunea Required a proiectantului de tabele
pentru oricare atribut pe valoarea Yes, acelui atribut i se vor interzice valorile nule. Ca o mică
ciudăţenie a ACCESS-ului, atributele de tip cheie primară apar în macheta proiectantului de tabele ca
având proprietatea Required pe No – vezi partea stângă a figurii 4.8 – în timp ce, de fapt, nici un
atribut de tip cheie primară nu poate avea valori nule.
Legat de restricţiile de unicitate, pe lângă cele discutate în paragraful 4.3.4 şi 5.2.2 (figurile
5.13, 5.14 şi 5.17) să mai adăugăm că în ACCESS cheia primară poate fi: naturală - când valorile
atributelor care o compune se introduc de utilizator - şi artificială - când se foloseşte un câmp de tip
AutoNumber, în acest din urmă caz ACCESS introducând automat o valoare consecutivă la inserarea
unei înregistrări (1 pentru prima înregistrare, 2 pentru a doua înregistrare s.a.m.d.). ACCESS-ul crează
indecşi pentru fiecare tip de cheie primară sau alternativă, acesta fiind motivul pentru care la aceste
tipuri de atribute proprietatea Indexed este setată pe Yes (No Duplicates). Dacă o cheie primară este
compusă, pentru fiecare atribut component se alege simbolul cheii primare din linia de instrumente.
În privinţa restricţiei referenţiale, se cuvin câteva detalii faţă de ceea ce a fost discutat în
paragraful 4.3.5. Figura 4.12 ilustrează modul în care se stabilesc relaţiile (legăturile) referenţiale între

tabele (vizualizare realizată prin folosirea opţiunii Relationship din linia de instrumente). De
fapt, ceea ce afişează figura reprezintă aşa numitele legăturile permanente dintre tabele. Regulile
pentru păstrarea integrităţii referenţiale se stabilesc în fereastra Edit Relationships (figura 5.24)
activată prin dublu click de pe oricare legătură permanentă din fereastra Relationships (figura 4.12).

Opţiuni pentru
Integritatea
referenţială

Figura 5.24 Fereastra Edit Relationships

Practic, restricţia de integritate referenţială se instituie abia la marcarea opţiunii Enforce


Referential Integrity, ACCESS-ul restricţionând adăugarea, modificarea şi /sau ştergerea în tabelele
părinte şi copil astfel:
 nu se permite modificarea valorii cheii primare din tabela părinte dacă există în tabela copil
măcar o înregistrare cu care este în legătură;
 nu poate fi introdusă nici o valoare a unei chei străine dacă respectiva valoare nu există deja ca
şi cheie primară în tabela părinte.
Dacă se alege opţiunea Cascade Update Related Fields orice modificare a unei chei primare în
tabela părinte va atrage modificarea în cascadă a tuturor cheilor străine în înregistrările copil, iar
Sistemul de gestiune a bazelor de date ACCESS 15

bifând opţiunea Cascade Delete Related Records la ştergerea unei înregistrări din tabela părinte se
vor elimina automat toate înregistrările copil.
Din fereastra Database pot fi realizate diverse operaţii cu tabelele şi înregistrările încărcate în
acestea. Pentru a vizualiza conţinutul unei tabele este suficient un dublu click de mouse de pe numele
tabelei. La afişare unele tabele au în stânga o coloană în care apare semnul plus (+) sau spaţiu. Semnul
plus în dreptul unei înregistrări semnifică faptul că aceasta este legată prin chei străine de înregistrări
aflate în alte tabele. Click pe semnul plus determină schimbarea în semnul minus (-) şi afişarea
înregistrărilor „înrudite” (copil) într-o subfoaie de date (figura 5.25).

Semnul +
înregistrarea are cel
puţin o înregistrare
“înrudită” într-o altă
tabelă

Semnul - sunt afişate


înregistrările
“înrudite”

Figura 5.25 Afişarea înregistrărilor din tabela copil

Pentru a vedea toate înregistrările subordonate articolelor dintr-o tabelă părinte se poate lansa
comanda Subdatasheet din meniul Format (figura 5.26).

Figura 5.26 Expandarea articolelor subordonate

La capitolul (de fapt, paragraful) restricţii utilizator de tipul regulilor la nivel de atribut (figura
4.10) am rămas datori cu expresia de la Validation Rule a atributului NumeClient din tabela CLIENŢI:
StrComp(UCase([NumeClient]),[NumeClient],0)=0. Exotismul expresiei ţine nu atât de folosirea
funcţiei UCase care converteşte toate literele din valoarea argumentului (atributul NumeClient, în cazul
nostru) în majuscule, cât de funcţia StrComp, prin care, în formatul prezentat se compară două şiruri
16 Instrumente software pentru afaceri

de caractere, dintre care unul (cel din dreapta) este valoarea atributului, iar celălalt aceeaşi valoare, dar
scrisă cu majuscule. Dacă cele două şiruri diferă câtuşi de puţin, rezultatul evaluării expresiei este
False, iar modificarea atributului (sau inserarea liniei) este respinsă. Practic, regula acceptă numai
valori în care literele sunt exclusiv majuscule.
Bănuind că explicaţia n-a fost suficientă, vă supunem atenţiei regula de validare a atributului
Adresa prin care prima literă din valoarea oricărei adrese va fi majusculă, restul valorii fiind lăsat la
latitudinea utilizatorului: StrComp(Left(UCase([Adresa]),1),Left([Adresa],1),0)=0. Funcţia LEFT
extrage primele n caractere de la stânga valorii argumentului.
Orice regulă la nivel de înregistrare, aşa cum a fost cea pentru tabela FACTURI prezentată în
figura 4.11, se poate introduce în proiectantul de tabelă apelând opţiunea Properties din linia de
instrumente (simbolul acestei opţiuni în linia de instrumente este chiar cel al ferestrei Table Properties
din figură).

5.2.4 Inserări, modificări şi ştergeri de înregistrări


Dacă în alte SGBD-uri am putea cheltui zeci de pagini explicând de zor ce butoane, comenzi,
opţiuni trebuie apelate pentru inserări, poziţionarea pe înregistrări, modificări, ştergeri, în Access
putem să expediem subiectul în câteva propoziţii, bazându-ne pe experienţa din... Excel. Afişarea
înregistrărilor unei tabele existente în baza de date se face de manieră similară modificării structurii,
numai că în loc de opţiunea Design se alege Open – vezi partea stânga sus a figurii 5.27. Pentru
inserarea unei înregistrări din meniul Insert se alege chiar prima comandă, New Record (vezi stânga
jos a figurii), iar pentru ştergere, în maniera din Excel se selectează linia sau liniile de şters (click pe
“antetul” liniei, iar apoi din meniul Edit se alege Delete Record. Modificarea valorilor se face direct,
prin poziţionarea în linia şi coloana dorită şi operarea modificărilor dorite.

Figura 5.27 Editarea datelor dintr-o tabelă


Sistemul de gestiune a bazelor de date ACCESS 17

Atunci când numărul de linii dintr-o tabelă este imens, iar datele trebuie modificate după
criterii riguroase, este necesară recurgerea la interogări pe care le vom discuta în paragraful 5.4 şi
capitolul 6.

5.3 FORMULARE ACCESS

Un formular reprezintă un instrument pus la dispoziţia utilizatorului în scopul uşurării


operaţiilor de accesare şi actualizare a datelor stocate în tabelele unei bazei de date. Trebuie reţinut
faptul că un formular este legat la o structură de date de tip tabelă sau cursor (query) obţinut în urma
unei interogări. Prin intermediul formularului se asigură o vedere organizată şi formatată asupra unei
părţi sau asupra tuturor câmpurilor din una sau mai multe tabele.
În cadrul unui formular deosebim cinci secţiuni de lucru, şi anume:
1. Antetul de formular (Form Header);
2. Antetul de pagină (Page Header);
3. Zona de detalii (Detail);
4. Subsolul de pagină (Page Footer);
5. Subsolul de formular (Form Footer).
Din cele cinci secţiuni este obligatorie doar zona de detalii, deoarece prin intermediul ei se
atinge scopul pentru care a fost conceput un asemenea instrument. Antetele de formular şi de pagină,
precum şi subsolurile aferente, sunt „aduse” pe ecran prin opţiunile Form Header /Footer şi Page
Header/Footer din meniul View.
În ACCESS, formularele pot fi construite în trei moduri:
 Crearea rapidă a unui formular prin utilizarea facilităţii AutoForm (Columnar, Tabular,
Datasheet, PivotTable sau PivotChart). De obicei se utilizează varianta organizării
datelor sub forma unei coloane. Dacă se alege Tabular, formularul va cuprinde un număr
mai mare de înregistrări în zona de detaliu, ceea ce va semăna cu o tabelă.
 Apelarea la asistent/vrăjitor (Form Wizard). Utilizatorul va construi formularul, pas cu
pas, sub îndrumarea asistentului, singura sarcină a acestuia fiind să răspundă la întrebări
prin selecţia unei variante din mai multe posibile;
 Utilizarea ferestrei de proiectare (Design View). În acest mod de lucru, formularul este
creat de către utilizatori avansaţi.
În prima etapă, pentru oricare variantă am opta din cele trei, trebuie să selectăm din proiectantul
bazei de date, de sub Object opţiunea Forms, după care să activăm butonul New, ca în figura 5.28.
18 Instrumente software pentru afaceri

1 2

Figura 5.28. Lansarea în execuţie a generatorului de formulare

Urmare a acţiunii 2 din figura precedentă se va activa fereastra New Form (figura 5.29), în
care va trebui să selectăm varianta de lucru pentru organizarea câmpurilor (1) şi tabela de legătură (2)
aşa cum se prezintă în figura 5.29.

Figura 5.29. Fereastră de selecţie a modului de organizare a datelor şi a tabelei de lucru

Vom parcurge în cele ce urmează variantele de lucru cu asistentul /vrăjitorul şi cea cu


AutoForm Columnar.
1. Utilizarea facilităţii AutoForm în generarea de formulare
Ne propunem pentru tabela CLIENTI să generăm formularul cu acelaşi nume. În acest sens,
vom da click pe AutoForm: Columnar (1), după care vom da click pe săgeata rubricii (Combo Box)
din dreptul Choose the table … (2) de unde vom selecta tabela CLIENTI (3).
După selecţia tabelei CLIENTI vom activa butonul Ok moment în care se va genera automat
formularul corespunzător tabelei noastre (figura 5.30).
Sistemul de gestiune a bazelor de date ACCESS 19

6
5
4
2 3

Figura 5.30. Formularul generat automat pentru tabela CLIENTI

Din figura precedentă observăm:


1. Titlul ferestrei este clienti, ca şi numele tabelei;
2. Suntem poziţionaţi pe prima înregistrare din tabela CLIENTI;
3. Pe ultimul rând dispunem de un set de butoane de navigare de la o înregistrare la alta;
4. Cheia primară a tabelei este marcată prin săgeata în dreptul codului client;
5. Putem modifica foarte uşor, chiar prea uşor, valorile oricărui câmp cu respectarea
restricţiilor de integritate referenţială declarate deja;
6. Putem realiza operaţii de sortare, filtrare, căutare, ştergere ( ) şi adăugare ( ) din
butoanele din linia de instrumente. Adăugarea este posibilă şi din butoanele de navigare cu
acelaşi buton .
După crearea formularului de mai sus este necesar să-l salvăm cu un nume, în cazul nostru îi
vom da numele Clienti. Acest lucru se realizează prin activarea opţiunii Save din meniul File sau
direct click pe discheta. Rezultatul va fi apariţia ferestrei de salvare a formularului cu un nume
recomandat de ACCESS, în cazul nostru clienti. Dacă dorim să păstrăm numele, nu ne rămâne decât
să dăm click pe butonul Ok. În caz că dorim să schimbăm numele, vom introduce numele nou şi vom
da Ok (figura 5.31).

Figura 5.31 Salvarea formularului

În urma operaţiei de salvare va apare în proiectantul bazei de date pentru formulare noul
formular creat, cu numele clienti.
2. Utilizarea asistentului în generarea de formulare
Continuăm crearea unui formular pentru tabela CODPOST_LOC, dar prin apelarea
asistentului în generarea de formulare. În figura 5.32. avem marcate etapele necesare lansării
asistentului.
20 Instrumente software pentru afaceri

3
2
1

Figura 5.32 Lansarea generatorului de formulare prin asistentul specializat

După activarea butonului Ok (5) vom intra în fereastra din figura de mai jos, din care va
trebui să selectăm câmpurile care să fie trimise în formular. În cazul nostru vom trimite toate
câmpurile, ceea ce înseamnă că vom da click pe butonul >>, apoi Next.

Figura 5.33. Fereastra de selectare a câmpurilor din tabela CODPOST_LOC

După activarea butonului Next vom intra în fereastra de organizare a datelor, din care vom
selecta butonul radio Columnar şi Next, ceea ce va face trecerea în fereastra de stabilire a stilului, din
care vom selecta Standard şi Next (figura 5.34).

Figura 5.34 Selecţia modului de organizare a datelor şi a stilului


Sistemul de gestiune a bazelor de date ACCESS 21

După selectarea stilului se va solicita ataşarea unui nume pentru formular. În cazul nostru îi vom
da numele Coduri şi vom activa butonul Finish (figura 5.35).

Figura 5.35 Salvarea şi afişarea formularului

Utilizarea unui formular se realizează direct din proiectantul bazei de date prin dublu click pe
numele acestuia sau cu selectare Form, selectare nume formular şi activarea butonului Open. Dacă ne
propunem să utilizăm formularul Coduri, astfel (figura 3.36):
a. selectăm Form;
b. selectăm Coduri;
c. activăm butonul Open.

Figura 5.36 Lansarea în execuţie a unui formular

În cazul în care se doreşte adăugarea unei înregistrări se activează butonul din zona
butoanelor de defilare sau din liniile de instrumente, ceea ce va determina golirea formularului, cu
posibilitatea completării datelor despre altă localitate (figura 5.37).

Figura 5.37 Adăugarea unei înregistrări


22 Instrumente software pentru afaceri

Modificarea unei înregistrări cu ajutorul formularului Coduri se realizează în două etape:


a. căutarea articolului de modificat;
b. efectuarea modificării direct în formular.
În mod similar modificării se realizează şi ştergerea unei înregistrări cu ajutorul formularului,
cu precizarea că se dă click pe butonul :
a. căutarea articolului de modificat;
b. efectuarea ştergerii direct în formular.

5.4 OBŢINEREA DE INFORMAŢII DIN BAZA DE DATE ÎN ACCESS

ACCESS-ul a fost, încă din tinereţea sa, un reper în materie de facilităţi de obţinere a
informaţiilor dintr-o bază de date relaţională, printr-un mecanism simplu de creare a interogărilor.
Vis-a-vis de terminologie, în engleză, verbul care desemnează explorarea bazei de date pentru a obţine
informaţiile necesare este to query pe care-l traducem prin a interoga. Chiar dacă la noi interogatoriul
ne duce cu gândul mai degrabă la beciurile securităţii şi bătăile crunte aplicate duşmanilor poporului,
sensul interogării unei baze de date este de a o investiga pentru a “stoarce” informaţii. Astfel încât, în
cele ce urmează ne vom transforma în storcători de informaţii, este drept, fără bastoane de cauciuc,
reflectoare în ochi şi pumni la ficat.

Figura 5.38 Proiectantul de interogări

Într-un proiect ACCESS, la loc de cinste între obiecte, imediat după tabele (Tables) apar
interogările (Queries). Selectarea acestora, click-ul de rigoare pe butonul New şi apoi a opţiunii Design
Sistemul de gestiune a bazelor de date ACCESS 23

View determină afişarea pe ecran a “proiectantului” de interogări, un cadru foarte versatil prin care
putem formula o cerinţă informaţională (figura 5.38).
Partea de sus a ecranului (în spatele ferestrei de alegere a tabelelor) serveşte la afişarea
tabelelor implicate în interogare, precum şi a legăturilor (restricţiilor referenţiale) dintre ele. În cadrul
propriu zis, fiecare coloană corespunde unei coloane din lista ce se doreşte a fi obţinută, informaţiile
specificate fiind: numele atributului (Field), tabela în care se află acesta (Table), dacă valorile
atributului vor fi ordonate crescător sau descrescător (Sort) în listă, dacă respectiva coloană va fi
afişată în listă sau serveşte doar la precizarea filtrului de selecţie a înregistrărilor (Show) şi condiţiile
pe care trebuie să le îndeplinească înregistrările (liniile) pentru a fi incluse în raport, altfel spus,
condiţia a filtrate a liniilor în rezultat (Criteria).
Ar mai trebui spus că putem include în rezultat nu numai atribute din tabele, ci şi expresii de
atribute, după cum vom vedea imediat.

5.4.1 Informaţii obţinute dintr-o singură tabelă


Ne propunem să obţinem din tabela FACTURI o listă (situaţie) de genul celei din figura 5.39.
Comparând cu liniile tabelei FACTURI din finalul capitolului 4 observăm că în rezultat sunt incluse
numai facturile emise după 20 iunie 2005, iar situaţia obţinută prezintă o coloană inexistentă în tabela
FACTURI, şi anume ValoareFărăTVA.

Figura 5.39 Facturile (inclusiv valoarea fără TVA) emise după 20 iunie 2005

Pornind de la ceea ce dorim să obţinem, să vedem cum se construieşte macheta interogării.


Figura 5.40 încearcă (fără succes) să lămurească lucrurile. În partea de sus tronează singura tabelă
necesară obţinerii rezultatului – FACTURI. Partea interesantă este însă în partea de jos a figurii.
24 Instrumente software pentru afaceri

Figura 5.40 Macheta interogării pentru obţinerea listei din figura 5.39

Mai întâi, în linia Criteria a coloanei Data este formulat criteriu de filtrare a liniilor din
rezultat: > #6/20/2005#. Este modalitatea de a indica faptul că valorile de pe coloana Data trebuie să
fie mai mari decât 20 iunie 2005. Dar cel mai captivant este ceea ce se petrece pe a treia coloană a
machetei. În prima fază pe linia Field se introduce expresia ValoareTotala – TVAColectata. Apoi se
face un click discret pe butonul Properties (pasul 2) şi se obţine pe ecran modesta fereastră Field
Properties. Aici vom indica formatul de afişare – fix (Format...Fixed) cu două zecimale (Decimal
Places...2), precum şi numele coloanei calculate (Caption...ValoareFaraTVA). Simplu, nu ? (vă
aşteptăm cu drag la restanţe !).
Se salvează macheta (celebra pictogramă a dischetei din figura de mai sus) sub numele
Facturi_dupa_20iunie2005, o imagine izbitor de asemănătoare figurii 5.39 fiind obţinută după click-ul
de rigoare pe butonul View din stânga-sus-ul ferestrei interogării.

5.4.2 Informaţii obţinute din două sau mai multe tabele


Prinzând un pic de curaj după încercarea din paragraful precedent, ne apropiem simţitor de
majoritatea situaţiilor reale, în care informaţiile necesare, precum şi condiţiile pe care trebuie să le
îndeplinească acestea, se găsesc nu într-o singură tabelă, ci în două sau chiar mai multe. Interogarea
din figura 5.41 – botezată Fac_dupa20iunie2005v2 (adică versiunea a doua a facturilor emise după 20
iunie 2005) – beneficiază de serviciile tuturor celor trei tabele. Întrucât în primele paragrafe ale
capitolului au fost declarate restricţiile referenţiale, pe măsura adăugării tabelelor în interogare,
ACCESS-ul indică şi legăturile dintre ele.
Sistemul de gestiune a bazelor de date ACCESS 25

Figura 5.41. Interogare ce foloseşte trei tabele, două condiţii de filtrare şi ordonare

Spre deosebire de interogarea precedentă, între coloanele Data şi ValoareFărăTVA au fost


introduse două coloane, NumeClient (corespunzător atributului cu acelaşi nume din tabela CLIENŢI) şi
Localitate (ce conţine valorile atributului corespunzător din tabela CODPOST_LOC). Condiţia de
filtrare a liniilor din rezultat priveşte două atribute. În afara datei, ce trebuie să fie, în continuare, după
20 iunie 2005, facturile trebuie să fi fost emise unor clienţi din localitatea Iaşi. Pentru aceasta, pe linia
Criteria, în dreptul coloanei Localitate este specificat “Iasi”.
În plus, s-a dorit şi ordonarea crescătoare a liniilor din rezultat după valorile atributului
NumeClient. Vă lăsăm pe dvs. să vizualizaţi rezultatul acestei interogări.

5.4.3 Prelucrări /grupări /sintetizări


Partea cea mai interesantă a interogărilor, în ACCESS sau orice alt SGBD, ţine de prelucrarea
datelor numerice. Astfel, cei de la compartimentul Vânzări (de obicei, acum i se spune Marketing,
deoarece sună mult mai bine) pot fi cât se poate de interesaţi să afle valorile vânzărilor pe zile
calendaristice, pe un interval la alegere. Probabil dialogul ar putea suna aşa: “Aş fi interesat(ă) de
evoluţia zilnică a vânzărilor în perioada 18-24 iunie 2005”, iar după un timp situaţia cerută ar fi
similară, numai că s-ar referi la intervalul 25-30 iunie 2005.
În tabela FACTURI fiecare linie se referă la o factură, aşa încât, pentru onorarea solicitării
colegilor de la compartimentul Marketing este necesară gruparea pe zile a facturilor şi însumarea,
pentru fiecare zi, a celor trei mărimi: valoarea fără TVA, TVA colectată şi valoarea totală a facturilor
din ziua respectivă. Iată cum rezolvăm problema – vezi figura 5.42.
26 Instrumente software pentru afaceri

Figura 5.42. Filtru generalizat, plus o grupare după dată

Pentru declararea modalităţii de grupare trebuie mai întâi folosit simbolul de însumare din
linia de instrumente a interogării. Ca urmare, în machetă, între liniile Table şi Sort apare linia Total.
Pe această linie, pentru coloanele TVAColectată şi ValoareTotală este suficientă selectarea opţiunii
Sum, în timp ce pentru valoarea fără TVA trebuie selectată opţiunea Expression, deoarece valoarea sa
se determină prin diferenţa dintre celelalte două (vezi în linia Fields expresia ValFaraTVA:
SUM(ValoareTotala – TVAColectata)).
Un alt artificiu care face o impresie bună este noul criteriu prin care utilizatorul poate indica în
momentul vizualizării rezultatelor interogării intervalul de vizualizare, adică data iniţială şi data finală
a acestuia: BETWEEN [Data Initiala:] AND [Data finala:]. La vizualizare (click pe simbolul View
din stânga liniei de instrumente a interogării) pe ecran apare o fereastră minusculă, ca în figura 5.43,
urmată de o alta, le fel de minusculă, în care se solicită data finală şi numai după aceea se afişează
rezultatul cu liniile ce desemnează zilele din intervalul specificat în care există măcar o factură.

Figura 5.43. Solicitarea valorii primului parametru de intrare (data iniţială a intervalului)

Cam atât deocamdată. Ne revedem cu interogările în capitolul 6.

5.5 CONSTRUIREA ŞI UTILIZAREA RAPOARTELOR


Informaţiile din domeniul economic sunt prezentate, cel mai adesea, prin intermediul
rapoartelor. Raportul reprezintă un ansamblu de informaţii conforme cu cerinţele utilizatorilor,
construit pe baza datelor din tabele. Rapoartele pot fi afişate pe ecran sau tipărite la imprimantă,
majoritatea lor având formă tabelară.
Sistemul de gestiune a bazelor de date ACCESS 27

La proiectarea şi construirea rapoartelor în format tabelar se vor lua în considerare cinci secţiuni
principale, la care mai pot fi adăugate altele două, dacă se doreşte gruparea datelor. Aceste secţiuni,
prezentate în structura raportului din figura 5.48, sunt (redăm şi denumirea lor în limba engleză, pentru
o mai bună recunoaştere a lor în generatoarele de rapoarte):
 Antetul şi sfârşitul (subsolul) raportului (Report Header şi Report Footer). Antetul raportului
conţine elementele care vor apare o singură dată, la începutul raportului. Aici se includ, de obicei,
titlul raportului, data obţinerii şi numele destinatarului. În secţiunea de sfârşit (subsol) se prevăd
elementele care vor apare o singură dată în raport, la sfârşitul acestuia. Aici se pot include totalurile
generale pentru câmpurile numerice şi numele persoanelor care au generat şi certificat raportul
respectiv.
 Antetul şi sfârşitul paginii (Page Header şi Page Footer). În aceste secţiuni vor fi incluse acele
elemente ale raportului care vor apare o singură dată pe fiecare pagină, la începutul sau la sfârşitul
ei. De regulă, numele coloanelor sunt prevăzute în antetul paginii astfel încât ele să fie afişate la
începutul fiecărei pagini. Totalurile la nivel de pagină, dacă sunt necesare, trebuie incluse în
secţiunea de sfârşit (subsol) a paginii. Numărul paginii poate apare în oricare din cele două
secţiuni.
 Secţiunea de detaliu (Detail). Este secţiunea principală a oricărui raport şi conţine valorile
câmpurilor din baza de date şi a expresiilor calculate ce vor forma o linie cu date. Pentru fiecare
înregistrare prelucrată din baza de date se va crea câte o linie în raport.
 Antetul şi sfârşitul grupului (Group Header şi Group Footer). Aceste două secţiuni apar în
rapoarte numai atunci când se doreşte gruparea datelor. În exemplul din figura 5.48, vânzările sunt
grupate pe clienţi, iar codul clientului reprezintă câmpul de control, adică acela după valorile căruia
se va face gruparea. Elementele incluse în aceste secţiuni vor apare o singură dată pentru fiecare
grup de date, deasupra primei linii cu date din grup, respectiv sub ultima linie. În antetul grupului
se includ, de regulă, datele de identificare ale grupului adică, în exemplul nostru, codul şi numele
clientului. În secţiunea de sfârşit se pot afişa totaluri sau rezultatele altor operaţiuni de agregare la
nivelul grupului, precum numărul elementelor, valoarea medie, valoarea minimă şi valoarea
maximă pentru câmpurile numerice.
În ACCESS, rapoartele pot fi construite în trei moduri:
 Crearea rapidă a unui raport pe baza unei singure tabele sau interogări, prin utilizarea facilităţii
AutoReport (Columnar sau Tabular). Utilizatorul trebuie doar să specifice tabela din care se vor
extrage datele, iar raportul va fi generat şi afişat pe ecran imediat. Dacă se optează pentru
Columnar, raportul obţinut va fi de tip coloană, adică datele unei linii din tabelă vor fi aranjate pe
o singură coloană. Dacă se alege Tabular, raportul generat va fi de tip tabel, rezervându-se câte o
coloană pentru fiecare câmp din tabelă.
 Apelarea la vrăjitor (Report Wizard). Utilizatorul va construi raportul, pas cu pas, sub
îndrumarea vrăjitorului, rolul său constând în furnizarea de răspunsuri la anumite întrebări, care
privesc sursa datelor (tabelele şi/sau interogările), câmpurile de date care vor fi reţinute în raport,
modul de grupare şi ordonare a datelor, formatul şi titlul raportului. Spre deosebire de cazul
anterior, acum pot fi create rapoarte pe baza mai multor tabele şi/sau interogări.
 Utilizarea ferestrei de proiectare (Design View). În acest mod de lucru, rapoartele vor fi create
fără ajutorul vrăjitorului. În schimb, utilizatorul va avea posibilitatea să creeze rapoarte mai
28 Instrumente software pentru afaceri

complexe, pe care să le personalizeze conform cerinţelor sale. Ca şi în primul caz, raportul poate
conţine date dintr-o singură tabelă sau interogare.
Pentru crearea unui raport, indiferent de modalitatea dorită, se selectează opţiunea Reports din
fereastra bazei de date şi apoi butonul New din linia de instrumente, situată în partea superioară a
ecranului. În urma acestei acţiuni se afişează fereastra de dialog din figura 5.44.

Figura 5.44 Fereastra de dialog pentru alegerea modalităţii de realizare a unui raport

În continuare vom descrie numai ultimul mod de lucru, întrucât acesta ne permite realizarea de
rapoarte complexe şi personalizate.
Ne propunem să construim un raport privind situaţia vânzărilor după 20 iunie 2005, pe
categorii de clienţi. Cerinţele raportului sunt următoarele:
 vor fi incluse următoarele informaţii: codul şi numele clientului, numărul şi data facturii,
valoarea totală şi valoarea TVA;
 datele vor fi grupate pe clienţi (după codul clientului), iar pentru fiecare client se va calcula
şi afişa valoarea totală a facturilor şi valoare totală TVA;
 datele vor fi ordonate după numărul facturii;
 se vor include totaluri pentru coloanele valoare totală şi valoare TVA, atât pentru fiecare
client, cât şi la sfârşitul raportului.
Etapele de creare a raportului sunt următoarele:
1. Crearea interogării pentru extragerea datelor necesare raportului din tabele. Aşa cum
spuneam anterior, în fereastra de proiectare pot fi construite rapoarte pe baza unei singure tabele sau
interogări. Întrucât raportul solicită date din două tabele, CLIENTI şi FACTURI, va trebui să creăm o
interogare care să extragă datele din cele două tabele. La construirea raportului se vor folosi datele
extrase prin interogarea FAC_DUPA20IUNIE2005V2, creată anterior, în paragraful destinat
interogării bazei de date.
2. Deschiderea ferestrei pentru construirea raportului. În acest sens, se activează fereastra
de dialog New Report, prezentată anterior în figura 5.44. Se selectează opţiunea Design View după
care, din căsuţa combinată (combo box) situată mai jos se alege interogarea
FAC_DUPA20IUNIE2005V2. După apăsarea butonului OK, se deschide fereastra pentru construire a
rapoartelor, prezentată în fig. 5.45.
Sistemul de gestiune a bazelor de date ACCESS 29

Figura 5.45 Fereastra pentru construirea rapoartelor

În cadrul ferestrei se poate observa pagina raportului care, pentru început, este goală, linia de
instrumente şi o mică fereastră ce conţine lista câmpurilor tabelei sau interogării selectate anterior. Se
observă că pagina conţine numai trei din cele cinci secţiuni ale unui raport. Pentru adăugarea celorlalte
două, Report Header şi Report Footer, se va accesa meniul View şi se va selecta opţiunea Report
Header/Footer.
3. Adăugarea obiectelor în cele cinci secţiuni ale raportului. Pentru includerea obiectelor în
raport se utilizează de instrumente, în aceeaşi manieră ca la construirea formularelor. În acest sens, vor
fi utilizate următoarele butoane:
 etichetă , pentru specificarea de constante, respectiv pentru specificarea titlului
raportului, denumirii coloanelor sau a altor texte cu rol explicativ;
 căsuţă de text , pentru specificarea de variabile, respectiv pentru adăugarea câmpurilor
de date şi a expresiilor de calcul ale căror valori vor fi afişate la vizualizarea /tipărirea
raportului.
 linie şi dreptunghi , pentru trasarea liniilor şi chenarelor necesare pentru
înfrumuseţarea raportului;
 săgeată , atunci când dorim selectarea unui obiect din raport.
Pentru adăugarea unui text, se selectează butonul etichetă, se poziţionează mouse-ul în poziţia
din care dorim să înceapă textul şi se dă clic, după care se introduce textul. Pentru a continua textul pe
linia următoare, dar în aceeaşi căsuţă, se foloseşte combinaţia de taste CTRL+ENTER.
Mai întâi se completează antetul raportului (Report header), în care se include data afişării sau
tipăririi, şi antetul paginii (Page header). Pentru includerea datei curente se adaugă o căsuţă de text
care va avea ca expresie de calcul funcţia DATE(). Specificarea expresiei de calcul se face astfel: se
selectează căsuţa, se apasă butonul dreapta al mouse-ului şi se alege opţiunea Properties din meniul
afişat. Efectul acestei acţiuni constă în afişarea ferestrei cu proprietăţi, prezentată în figura 5.46.a). În
această fereastră se alege proprietatea Control Source şi se apasă butonul „trei puncte”, din dreapta,
pentru deschiderea ferestrei Expression Builder (construirea expresiilor de calcul). În figura 5.46.b) se
30 Instrumente software pentru afaceri

poate vedea conţinutul acestei ferestre şi modul în care a fost introdusă expresia DATE(). Expresia de
calcul poate fi introdusă şi de la tastatură, direct în căsuţa de editare. Se revine în pagina raportului
prin apăsarea butonului OK şi închiderea ferestrei cu proprietăţi.

a) Fereastra cu proprietăţi b) Fereastra pentru introducerea expresiilor de calcul


Figura 5.46 Ferestrele pentru introducerea expresiilor de calcul

Pasul următor vizează introducerea câmpurilor număr factură, data factură, valoare totală şi
valoare TVA în secţiunea de detaliu (Detail). În acest sens, din lista câmpurilor se trag, pe rând, cele
patru câmpuri în locul dorit. Eticheta adăugată automat pentru fiecare câmp introdus în raport poate fi
ştearsă deoarece rolul explicativ îl îndeplineşte numele coloanei în care acesta este plasat. Dedesubtul
celor patru câmpuri se trasează o linie pentru a delimita rândurile cu date în momentul vizualizării
/tipăririi raportului.
În subsolul paginii (Page Footer) se vor introduce numărul paginii curente şi numărul total de
pagini din raport. Se va adăuga o căsuţă de text, urmându-se paşii descrişi anterior pentru data curentă,
a cărei expresie va avea forma:
= „Pagina” & [Page] & „ din ” & [Pages].
Variabila [Page] livrează numărul paginii curente, iar variabila [Pages] numărul total de
pagini. Operatorul & este utilizat pentru adunarea şirurilor de caractere.
În subsolul raportului (secţiunea Report Footer) se adaugă o linie pentru totalul general, în
care vor fi însumate valoarea facturilor şi valoarea TVA. Cele două formule de calcul se introduc tot
prin intermediul căsuţelor de text şi vor avea forma:
= SUM ([ValoareTotală])
= SUM ([TVAColectata])
ValoareTotala şi TVAColectata sunt câmpurile din rezultatul interogării pentru valoarea totală a
unei facturi şi valoarea TVA aferentă.
4. Gruparea şi ordonarea datelor. Liniile din raport pot fi ordonate sau grupate în funcţie de
mai multe criterii, iar pentru fiecare grup de date se pot introduce în raport alte două secţiuni: antetul şi
subsolul grupului. Cele două operaţiuni sunt realizate din fereastra Sorting and Grouping. Deschiderea
ei se face prin selectarea opţiunii Sorting and Grouping din meniul View sau prin apăsarea butonului
din linia cu instrumente, situată deasupra ferestrei de construire a raportului.
Fereastra (prezentată în figura 5.47) conţine un grid (tabel), format din două coloane, Field
/Expression şi Sort Order, şi un grup de proprietăţi pentru definirea grupurilor de date, în partea sa
Sistemul de gestiune a bazelor de date ACCESS 31

inferioară. Coloana Field /Expression este utilizată pentru specificarea câmpurilor sau expresiilor după
care se face gruparea şi /sau ordonarea datelor în raport. În raportul nostru datele trebuie grupate după
codul clientului şi ordonate după numărul facturii. De aceea, vom selecta în prima linie câmpul
CodClient, iar în cea de-a doua Nrfact. Această coloană poate conţine cel mult zece nume de câmpuri şi
/sau expresii, adică pot fi utilizate cel mult zece criterii de grupare şi sortare.

Figura 5.47 Fereastra Sorting and Grouping

Coloana Sort Order permite alegerea ordinii crescătoare (Ascending) sau descrescătoare
(Descending) pentru câmpul sau expresia din linia respectivă. În momentul completării coloanei
Field/Expression, în coloana Sort Order va fi atribuită implicit valoarea Ascending. Dacă se doreşte
modificarea ordinii de sortare pentru un anumit câmp sau expresie, atunci se selectează printr-un clic
elementul respectiv, după care în coloana Sort Order se alege valoarea Descending.
În cazul în care pentru un câmp sau o expresie se doreşte nu doar sortarea datelor, ci şi
gruparea lor, atunci se selectează elementul respectiv şi se vor configura proprietăţile din jumătatea
inferioară a ferestrei Sorting and Grouping. Aceste proprietăţi au următoarele semnificaţii:
 Group Header prezintă două valori posibile Yes /No. Dacă se alege valoarea Yes, atunci pentru
câmpul sau expresia selectată din coloana Field /Expression se adaugă în raport o secţiune nouă
pentru antetul grupului. Valoarea implicită este No, adică nu se creează automat o secţiune pentru
antetul grupului.
 Group Footer este asemănătoare cu proprietatea anterioară, numai că se referă la secţiunea de
sfârşit (subsol) a grupului respectiv. Pentru includerea ei în raport se va alege valoarea Yes.
 Group On stabileşte modul de grupare a valorilor câmpului selectat. Valorile posibile depind de
tipul câmpului sau expresiei de grupare (text, numeric sau dată calendaristică). De exemplu, dacă
s-a ales data facturii drept câmp de grupare, atunci prin această proprietate se va stabili dacă datele
vor fi grupate pe fiecare valoare distinctă (se alege valoarea Each Value), pe fiecare an (Year),
lună (Month), săptămână (Week) s.a.m.d.
 Group Interval specifică un interval sau un număr de caractere pe care se bazează gruparea
liniilor din raport. În cazul unui câmp de grupare de tip Date/Time, stabilirea valorii 12 semnifică
gruparea liniilor care aparţin aceleiaşi jumătăţi de zi, dacă pentru proprietatea Group On a fost
stabilită valoarea Hour.
 Keep together se referă la modul de tipărire a liniilor raportului care fac parte din acelaşi grup.
Pentru această proprietate există trei valori posibile: No – permite tipărirea liniilor dintr-un grup şi
pe pagina următoare, dacă s-a ajuns la sfârşitul paginii; Whole group (Grupul întreg) – are ca efect
32 Instrumente software pentru afaceri

tipărirea tuturor secţiunilor grupului (antetul, detaliile şi subsolul) pe o singură pagină, dacă este
posibil; With First Detail (Cu prima linie de detaliu) – antetul grupului va fi tipărit pe aceeaşi
pagină cu prima linie a secţiunii de detaliu.
După adăugarea tuturor câmpurilor şi expresiilor de ordonare şi grupare şi configurarea
proprietăţilor de grupare, se închide fereastra Sorting and Grouping şi se trece la completarea
secţiunilor nou introduse în pagina raportului. Cerinţele raportului ales de noi ca exemplu impun
crearea unui grup de date, în funcţie de codul clientului. În secţiunea de antet se introduc codul şi
numele clientului, iar în cea de subsol se adaugă sumele calculate pentru valoarea facturilor şi valoarea
TVA, în maniera descrisă pentru secţiunea Report Footer.

Figura 5.48 Fereastra pentru construirea raportului exemplificat

Forma finală a raportului privind vânzările pe clienţi, cu toate obiectele incluse, este
prezentată în figura 5.48. Acum se salvează raportul (este recomandabil să salvaţi mai des, fără a
aştepta să finalizaţi construirea raportului), după care se face vizualizarea acestuia, prin selectarea
opţiunii Print Preview din meniul View sau prin apăsarea butonului din linia cu instrumente. În
continuare se poate configura pagina (dimensiune, orientare, margini etc.), folosind opţiunea Page
Setup din meniul File. De asemenea, se poate tipări raportul prin comanda Print din acelaşi meniu
File.
La vizualizare raportul va arăta ca în figura 5.49.
Odată salvat, raportul poate fi ulterior modificat. În acest sens, se alege obiectul Report din
fereastra bazei de date, apoi se alege raportul dorit din fereastra din dreapta, ce conţine rapoartele
create deja, şi se apasă butonul din linia cu instrumente. Efectul acestei comenzi va consta
în deschiderea ferestrei de proiectare a raportului (figura 5.48), în care vor fi regăsite toate obiectele
raportului şi care pot fi modificate în conformitate cu noile cerinţe.
Sistemul de gestiune a bazelor de date ACCESS 33

Figura 5.49 Forma raportului exemplificat la vizualizare

5.6 APLICAŢII, PROGRAME, PROCEDURI VBA ÎN ACCESS

Ca orice aplicaţie din pachetul MS Office pentru scrierea de proceduri se foloseşte Visual
Basic for Application. Programele VBA sunt numite proceduri şi sunt grupate în:
Subrutine, care se referă la instrucţiuni VBA cuprinse între Sub … End Sub şi care nu
returnează o valoare;
Sub nume_proc()

End sub

Funcţii procedurale care se referă la instrucţiuni VBA cuprinse între Function … End
Function şi care returnează o valoare.
Function nume_funct(param)

End Function

Orice procedură cuprinde un set de instrucţiuni care îndeplinesc o anumită sarcină. În scrierea
unei proceduri se folosesc cuvinte cheie, adică acele cuvinte de culoare albastră, care reprezintă
cuvinte rezervate ale mediului VBA. Celelalte cuvinte de culoare neagră sunt cuvinte utilizator de
natura variabilelor sau valorilor.
La rândul lor, procedurile şi modulele se regrupează în module, care pot fi: clase de module şi
module standard.
34 Instrumente software pentru afaceri

Toate aceste proceduri se scriu în VBA şi devin parte a componentei Modules din proiectantul
de bază de date (vezi figura 5.50). Tot ca proceduri şi funcţii se scriu şi interogările aplicate asupra
bazei de date. Pentru a vizualiza conţinutul unui modul este necesar să se dea dublu click pe numele
acestuia şi astfel se va intra în VBA.

Dublu
click

Figura 5.50 Componenta Modules din BD Vinzari şi vizualizarea conţinutului pentru Meniu în VBA

În mod similar se vizualizează conţinutul celorlalte module şi a interogărilor (ramura Query).


Lansarea în execuţie a unei proceduri în VBA se face direct din meniul Run cu opţiunea Run
Sub/User Form sau simplu cu F5. Acelaşi lucru se poate realiza dacă se dă click pe butonul din
linia de instrumente (de obicei se găseşte sub Run). Dacă în urma unei execuţii se intră în modul Break
(adică se blochează execuţia în VBA prin colorarea în galben a unei linii cu instrucţiuni), va trebui să
se reseteze din meniul Run opţiunea Reset sau simplu click pe butonul din linia de instrumente.
Lansarea în execuţie în cadrul procedurilor de interogare şi a celor din module se realizează cu
următoarele instrucţiuni:
Run (“Auto_Open”) ‘ se executa procedura Auto_Open
Sau
Call Auto_Open ‘ se apelează procedura Auto_Open

Pentru apelarea unei interogări (query), a unui formular sau raport într-o procedură VBA se
foloseşte instrucţiunea DoCmd, astfel:

DoCmd.OpenQuery ("interog") ‘ apeleaza interogarea cu numele interog


DoCmd.OpenReport ("Situatia vanzarilor"), acPreview ‘ apeleaza raportul Situaţia vanzarilor
DoCmd.OpenForm ("Coduri")

5.7 CREAREA DE MENIURI ÎN ACCESS


Pentru creare de meniuri într-o aplicaţie sub MSO ACCESS este posibil să se procedeze fie la
scrierea de macro-uri (componentă a proiectantului de bază de date), fie la scrierea de proceduri sub
VBA ca element component din Modules.
Sistemul de gestiune a bazelor de date ACCESS 35

Pentru baza de date Vinzari am apelat varianta a doua în sensul că am scris o procedură sub
VBA, cu numele Auto_Open, prin care am dezactivat meniul standard al ACCESS-ului şi am creat
propriul nostru meniu cu opţiunile din figura 5.51.

Figura 5.51 Meniul aplicaţiei pentru BD Vinzari

Pentru a renunţa la meniul ACCESS şi a obţine opţiunile din meniul aplicaţiei Vinzari avem
următoarea procedură în modulul Meniu:

Sub Auto_Open()
'* setari fereastra
Dim oComandBar As Object
Set oComandBar = Application.CommandBars("Menu Bar")

'Set oComandBar = Application.CommandBars("Worksheet Menu Bar")


oComandBar.Controls("File").Delete
oComandBar.Controls("Edit").Delete
oComandBar.Controls("View").Delete
oComandBar.Controls("Insert").Delete
oComandBar.Controls("Tools").Delete
oComandBar.Controls("Window").Delete
oComandBar.Controls("Help").Delete
' adaugam optiunile noastre
Dim oPopUp As Object
Dim oButton As Object

' Optiunea Fisiere


Set oPopUp = oComandBar.Controls.Add(10)
oPopUp.Caption = "Fisiere"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Pregatire"
oButton.OnAction = "Pregatire"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Sterge Tabele Vanzari"
oButton.OnAction = "StergeTabele_4"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Creare Tabele Vanzari"
oButton.OnAction = "CreareTabele_4"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "________________"
oButton.Enabled = False
36 Instrumente software pentru afaceri

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "Salvare ca .."
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "________________"
oButton.Enabled = False
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Iesire"
oButton.OnAction = "Reset"

' Optiunea Reguli


Set oPopUp = oComandBar.Controls.Add(10)
oPopUp.Caption = "Reguli"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Valori Implicite"
oButton.OnAction = "ValoriImplicite"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "La nivel de atribut"
oButton.OnAction = "ReguliLaNivelDeATRIBUT"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "La nivel de inregistrare"
oButton.OnAction = "ReguliLaNivelDeINREGISTRARE"

' Optiunea Actualizare


Set oPopUp = oComandBar.Controls.Add(10)
oPopUp.Caption = "Actualizare"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Populare Vinzari"
oButton.OnAction = "PopulareVinzari_4"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Clienti"
oButton.OnAction = "Clienti"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Coduri"
oButton.OnAction = "Coduri"

' Optiunea Interogare


Set oPopUp = oComandBar.Controls.Add(10)
oPopUp.Caption = "Interogari"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Modificare"
oButton.OnAction = "Updateuri"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "Between"
oButton.OnAction = "InterogareBetween"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "Like1"
oButton.OnAction = "InterogareLike1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "Like2"
oButton.OnAction = "InterogareLike2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "IN1"
oButton.OnAction = "InterogareIN1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "IN2"
Sistemul de gestiune a bazelor de date ACCESS 37

oButton.OnAction = "InterogareIN2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "ISNULL"
oButton.OnAction = "InterogareISNULL"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "DISTINCT1"
oButton.OnAction = "InterogareDISTINCT1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "DISTINCT2"
oButton.OnAction = "InterogareDISTINCT2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "ORDER BY"
oButton.OnAction = "InterogareORDERBY"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "JONCTIUNE1"
oButton.OnAction = "InterogareJONCTIUNE1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "AUTOJONCTIUNE1"
oButton.OnAction = "InterogareAUTOJONCTIUNE1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "AUTOJONCTIUNE2"
oButton.OnAction = "InterogareAUTOJONCTIUNE2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "COUNT1"
oButton.OnAction = "InterogareCOUNT1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "COUNT2"
oButton.OnAction = "InterogareCOUNT2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "SUM1"
oButton.OnAction = "InterogareSUM1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "SUM2"
oButton.OnAction = "InterogareSUM2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "MINMAX1"
oButton.OnAction = "InterogareMINMAX1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "SUBCONSULTARI1"
oButton.OnAction = "InterogareSUBCONSULTARI1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "SUBCONSULTARI2"
oButton.OnAction = "InterogareSUBCONSULTARI2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "SUBCONSULTARI3"
38 Instrumente software pentru afaceri

oButton.OnAction = "InterogareSUBCONSULTARI3"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "SUBCONSULTARI4"
oButton.OnAction = "InterogareSUBCONSULTARI4"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "REUNIUNE1"
oButton.OnAction = "InterogareREUNIUNE1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "REUNIUNE2"
oButton.OnAction = "InterogareREUNIUNE2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "GRUPARE_PAS1"
oButton.OnAction = "InterogareGRUPARE_PAS1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "GRUPARE_PAS3"
oButton.OnAction = "InterogareGRUPARE_PAS3"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "HAVING1"
oButton.OnAction = "InterogareHAVING1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "HAVING_SUBCONSULTARE1"
oButton.OnAction = "InterogareHAVING_SUBCONSULTARE1"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "HAVING_SUBCONSULTARE2"
oButton.OnAction = "InterogareHAVING_SUBCONSULTARE2"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "HAVING_SUBCONSULTARE3"
oButton.OnAction = "InterogareHAVING_SUBCONSULTARE3_Final"

' Optiunea Rapoarte


Set oPopUp = oComandBar.Controls.Add(10)
oPopUp.Caption = "Rapoarte"

Set oButton = oPopUp.Controls.Add(1)


oButton.Caption = "Raport 1"
oButton.OnAction = "Rap1"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Raport 2"
oButton.OnAction = "Rap2"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Situatia vanzarilor"
oButton.OnAction = "Sit_vanz"

' Optiunea Ajutor


Set oPopUp = oComandBar.Controls.Add(10)
oPopUp.Caption = "Ajutor"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Ajutor"
oButton.Enabled = False
Sistemul de gestiune a bazelor de date ACCESS 39

' Optiunea Iesire


Set oPopUp = oComandBar.Controls.Add(10)
oPopUp.Caption = "Iesire"
Set oButton = oPopUp.Controls.Add(1)
oButton.Caption = "Iesire"
oButton.OnAction = "Reset"

End Sub

Figura 5.52 Componente ale meniului aplicaţiei Vinzari

Spre exemplu:
- pentru a apela opţiunea Clienti din meniul Actualizare avem procedura Clienti din modulul
Capitolul_5, care conţine instrucţiunea de apelare a formularului Clienti;
Sub Clienti()
DoCmd.OpenForm "Clienti"
End Sub

- pentru a apela opţiunea Between din meniul Interogari avem procedura ”InterogareBetween” din
modulul Capitolul_6;

Sub interogareBETWEEN()
Dim consultare As QueryDef
Set consultare = CurrentDb.QueryDefs("interog")
consultare.SQL = "SELECT * FROM facturi WHERE nrfact BETWEEN 111120 AND 111124 ; "
DoCmd.OpenQuery ("interog")
End Sub

- pentru a apela opţiunea Situatia vanzarilor din meniul Rapoarte avem procedura ”Sit_vanz” din
modulul Capitolul_5;
Sub Sit_vanz()
DoCmd.OpenReport "Situatia vanzarilor", acPreview
End Sub

Observaţie:
Este important ca după lansarea procedurii Auto_Open() să se apeleze opţiunea Iesire din
Fisiere sau Iesire, pentru a se reseta parametrii meniului ACCESS. În caz contrar aceste opţiuni vor fi
prezente la următorul utilizator. Deci nu trebuie părăsită sesiune de lucru ACCESS cu butonul !
Capitolul 6

INTEROGAREA BAZELOR DE DATE. LIMBAJUL SQL

Sumar

 Prezentarea generală a limbajului SQL


 Crearea tabelelor şi declararea restricţiilor
 Comenzi de actualizare a tabelelor
 Structura de bază a frazei select
 Joncţiuni
 Funcţii-agregat: COUNT, SUM, AVG, MAX, MIN
 Sub-consultări. operatorul IN
 Reuniune, intersecţie, diferenţă
 Gruparea tuplurilor. Clauzele GROUP BY şi HAVING
2 Instrumente software pentru afaceri

6.1 PREZENTAREA GENERALĂ A LIMBAJULUI SQL


După două capitole de luptă surdă cu bazele de date, a devenit aproape evident că folosim
bazele de date pentru că avem memoria prea scurtă. Deoarece suntem o lume aşezată pe un morman de
hârtii & hârţoage, ne este cu neputinţă să reconstituim ceea ce am făcut adineori, dară-mi-te ieri,
săptămâna trecută sau acum un an sau cinci. Necazul e că, de cele mai multe ori, trebuie să ştim nu
numai ce-am făcut noi, dar ce-au făcut şi colegii şi partenerii de afaceri. Dacă la oameni mai putem
trece cu vederea, în cazul bazelor de date încrederea este elementul cheie (primară, străină...). Aşa
încât şi în capitolul 4 şi în capitolul 5 am fost foarte interesaţi să aflăm cum definim cât mai multe
restricţii, astfel să diminuăm riscul preluării în baza de date a unor informaţii eronate. Apoi am văzut
cum inserăm, modificăm şi ştergem date într-o bază. Tangenţial am abordat şi câteva modalităţi de a
obţine informaţii de o manieră asistată, grafică.
Chiar dacă am încercat să păstrăm discuţia la un nivel general, exemplificările au fost făcute
pe calapodul ACCESS-ului. Cei care au experienţă în ACCESS şi vor să treacă, forţaţi de împrejurări,
pe un SGBD mai performant, gen PostgreSQL, Oracle etc. (trecere care echivalează cu trecerea de la
amatori la semi sau chiar profesionişti de-a binelea) vor fi bruscaţi de diferenţele de interfaţă, opţiuni
etc.
Pentru atenuarea şocurilor trecerilor de la un SGBD la altul, specialiştii bazelor de date s-au
gândit la un limbaj universal dedicat creării tabelelor, definirii restricţiilor, creării utilizatorilor şi
grupurilor de utilizatori, definirii drepturilor fiecărui utilizator/grup la obiecte din bază, actualizării
înregistrărilor din tabele (inserare, modificare, ştergere) şi, mai ales, extragerii şi prelucrării datelor din
bază. Acest limbaj a fost standardizat încă din 1986 (în SUA) şi 1989 (la nivel mondial – ISO) şi se
numeşte SQL.
Haideţi să revenim la interogarea FACTURI_DUPA_20IUNIE2005 din figura 5.40 (a cărei
execuţie produce rezultatul din figura 5.39). Dacă din modul proiectare (Design) alegem opţiunea
SQL View, o să ne trezim cu o fereastră în care apare din senin o comandă cel puţin ciudată:

Figura 6. 1. O interogare SQL de-a gata


Limbajul SQL 3

SELECT facturi.NrFact, facturi.Data, [ValoareTotala]-[TVAColectata] AS Expr1,


facturi.TVAColectata, facturi.ValoareTotala
FROM facturi
WHERE (((facturi.Data)>#6/20/2005#));
Ei bine, acest SELECT este chiar o comandă SQL. Dar s-o luăm la pas temeinic. Un mobil
determinant al succesului bazelor de date relaţionale l-a constituit, fără nici o îndoială, SQL. De la
începuturile bazelor de date, s-a pus problema elaborării unui limbaj universal special dedicat bazelor
de date, limbaj care să permită, în egală măsură, definirea relaţiilor (tabelelor), declararea restricţiilor,
modificarea datelor din tabele, precum şi extragerea informaţiilor din cele mai diverse din datele
existente în bază. În 1970, E.F.Codd sugera "adoptarea unui model relaţional pentru organizarea
datelor [...] care să permită punerea la punct a unui sub-limbaj universal pentru gestiunea acestora,
sub-limbaj care să fie, în fapt, o formă aplicată de calcul asupra predicatelor".
De atunci până în prezent au fost propuse numeroase limbaje pentru lucrul cu bazele de date,
denumite, în general, limbaje de interogare. Dintre cele teoretice, cele mai cunoscute sunt algebra
relaţională şi calculul relaţional, iar dintre cele practice (comerciale) Quel, QBE şi SQL. De departe,
cel mai important este SQL, fundamentat de algebra relaţională.
După mulţi autori, momentul decisiv în naşterea SQL ca limbaj îl constituie lansarea
proiectului System /R de către firma IBM, eveniment ce a avut loc în 1974. Tot în 1974 Chamberlin şi
Boyce au publicat o lucrare în care este prezentată forma unui limbaj structurat de interogare,
"botezat" SEQUEL (Structured English as QUEry Language). În 1975 Chamberlin, Boyce, King şi
Hammer publică un articol în care prezintă sub-limbajul SQUARE, asemănător SEQUEL-ului, dar
care utiliza expresii matematice şi nu cuvinte din limba engleză. Autorii celor două studii au
demonstrat că limbajele SEQUEL şi SQUARE sunt complete din punct de vedere relaţional.
Un colectiv de autori, condus de Chamberlin, elaborează în 1976 o nouă lucrare în care se face
referire la SEQUEL 2, acesta fiind "preluat" ca limbaj de interogare al SGBD-ului System /R al firmei
IBM. În 1980 Chamberlin schimbă denumirea SEQUEL în SQL - Structured Query Language (Limbaj
Structurat de Interogare), dar şi astăzi mulţi specialişti pronunţă SQL ca pe predecesorul său. Anii
următori au înregistrat apariţia a o serie întreagă de lucrări care l-au perfecţionat, ultimul deceniu
consacrându-l ca pe cel mai răspândit limbaj de interogare a BDR, fiind prezent în numeroase
"dialecte" specifice tuturor SGBDR-urilor actuale, de la DB2 la Microsoft SQL Server, de la Oracle la
FoxPro şi ACCESS.
American National Standard Institute publică în 1986 standardul SQL ANSI X3.136-1986.
Este un standard care se bazează, într-o mare măsură, pe "dialectul" SQL al produsului DB2 de la
IBM. În 1989 are loc revizuirea extinderea acestui standard, "născându-se" SQL-89, care mai este
denumit şi SQL1. Deşi recunoscut ca bază a multor SGBDR-uri comerciale, SQL1 şi-a atras
numeroase critici. În plus, variantele comercializate de diferiţii producători, deşi asemănătoare în
esenţă, erau (şi sunt) incompatibile la nivel de detaliu. Pentru a umple golurile SQL1, ANSI a elaborat
în 1992 "versiunea" SQL2, specificaţiile fiind prezentate la un nivel mult mai detaliat (dacă SQL1 se
întindea pe numai 100 de pagini, SQL2 a fost publicat în aproape 600). IBM a avut un aport
incontestabil la apariţia şi maturizarea SQL, fiind un producător cu mare influenţă în "lumea" SGBD-
urilor, iar produsul său, DB2, este unul din standardele de facto ale SQL.
Standardul SQL:1999 a fost amânat de câteva ori până la publicarea sa, iar cea mai recentă
versiune este SQL:2003. Actualmente, principalele orientări ale SQL vizează transformarea acestuia
4 Instrumente software pentru afaceri

într-un limbaj complet, în vederea definirii şi gestionării obiectelor complexe şi persistente. Aceasta
include: generalizare şi specializare, moşteniri multiple, polimorfism, încapsulare, tipuri de date
definite de utilizator, triggere (declanşatoare) şi proceduri stocate, suport pentru sisteme bazate pe
gestiunea cunoştinţelor, expresii privind interogări recursive şi instrumente adecvate de administrare a
datelor.
La momentul actual, SQL reprezintă cel mai important limbaj în domeniul bazelor de date,
atât prin gama comenzilor şi opţiunilor de care dispune, dar mai ales datorită faptului că s-a reuşit
standardizarea sa şi portarea pe toate Sistemele de Gestiune a Bazelor de date semnificative. Cu atât
mai mult, cu cât, spre deosebire de majoritatea covârşitoare a altor limbaje, poate fi deprins relativ
uşor de neinformaticieni şi utilizat pentru chestiuni de mare fineţe de către profesionişti. Acest capitol
se doreşte a fi o prezentare a elementelor esenţiale prin care, dată fiind structura unei baze de date
relaţionale, pot fi formulate interogări (fraze SELECT) prin care se obţin răspunsuri la gamă eterogenă
de întrebări. În plus, sunt evocate pe scurt comenzile pentru actualizarea unei tabele (INSERT,
UPDATE, DELETE), precum şi cele de declarare a structurii bazei de date (CREATE TABLE).
Din punctul de vedere al utilizatorului final, obiectivul principal al SQL constă în a oferi
utilizatorului mijloacele necesare formulării unei consultări numai prin descrierea rezultatului dorit, cu
ajutorul unei aserţiuni (expresie logică), fără a fi necesară şi explicitarea modului efectiv în care se
face căutarea în BD. Altfel spus, utilizatorul califică (specifică) rezultatul iar sistemul se ocupă de
procedura de căutare.
Deşi este referit, în primul rând, ca un limbaj de interogare, SQL este mult mai mult decât un
instrument de consultare a bazelor de date, deoarece permite, în egală măsură:
 Definirea datelor
 Consultarea BD
 Manipularea datelor din bază
 Controlul accesului
 Partajarea bazei între mai mulţi utilizatori ai acesteia
 Menţinerea integrităţii BD.

Deşi toate clasificările îl încadrează la limbaje de generaţia a IV-a, SQL nu este, totuşi, un
limbaj de programare propriu-zis, prin comparaţie cu Basic, Pascal, C, COBOL etc. SQL nu conţine
(până la SQL3) instrucţiuni/comenzi pentru codificarea structurilor alternative şi repetitive, cu atât mai
puţin facilităţi de lucru cu obiecte vizuale, specifice formularelor de preluare a datelor (căsuţe-text,
butoane radio, liste, butoane de comandă etc.). Din acest punct de vedere, poate fi referit ca sub-limbaj
orientat pe lucrul cu bazele de date. Comenzile sale pot fi, însă, inserate în programe redactate în
limbaje de programare "clasice".
Principalele atuuri ale SQL sunt:
1. Independenţa de producător, nefiind o tehnologie "proprietară".
2. Portabilitate între diferite sisteme de operare.
3. Standardizare.
4. "Filosofia" sa se bazează pe modelul relaţional de organizare a datelor.
5. Este un limbaj de nivel înalt, cu structură ce apropie de limba engleză.
6. Furnizează răspunsuri la numeroase interogări simple, ad-hoc, neprevăzute iniţial.
7. Constituie suportul programatic pentru accesul la BD.
8. Permite multiple imagini asupra datelor bazei.
9. Este un limbaj relaţional complet.
Limbajul SQL 5

10. Permite definirea dinamică a datelor, în sensul modificării structurii bazei chiar în timp ce o parte
din utilizatori sunt conectaţi la BD.
11. Constituie un excelent suport pentru implementarea arhitecturilor client-server.
Principalele comenzi ale SQL, care se regăsesc, într-o formă sau alta, în multe dintre SGBDR-
urile actuale sunt prezentate în tabelul 6.1.

Tabel 6.1. Clase de comenzi SQL

Comandă Scop

Pentru manipularea datelor


SELECT Extragerea datelor din BD
INSERT Adăugarea de noi linii într-o tabelă
DELETE Ştergerea de linii dintr-o tabelă
UPDATE Modificarea valorilor unor atribute
Pentru definirea bazei de date
CREATE TABLE Adăugarea unei noi tabele în BD
DROP TABLE Ştergerea unei tabele din bază
ALTER TABLE Modificarea structurii unei tabele
CREATE VIEW Crearea unei tabele virtuale
DROP VIEW Ştergerea unei tabele virtuale
Pentru controlul accesului la BD
GRANT Acordarea unor drepturi pentru utilizatori
REVOKE Revocarea unor drepturi pentru utilizatori
Pentru controlul tranzacţiilor
COMMIT Marchează sfârşitul unei tranzacţii
ROLLBACK Abandonează tranzacţia în curs

6.2 CREAREA TABELELOR ŞI DECLARAREA RESTRICŢIILOR


Limbajul SQL prezintă o serie întreagă de opţiuni care permit crearea tabelelor şi modificarea
valorilor unor atribute pentru tuplurile unei relaţii. Mai mult, standardul SQL dispune de opţiuni clare
privind specificarea unor restricţii legate de cheile primare, cheile străine etc. Baza de date pe care o
vom lua în discuţie pe parcursul acestui capitol este cea prezentată în capitolul 4. Pentru crearea unei
tabele comanda SQL este, natural, CREATE TABLE prin care se declară numele tabelei, numele, tipul
şi lungimea fiecărui atribut, precum şi restricţiile. Astfel, primele două tabele din baza de date,
CODPOST_LOC şi CLIENŢI pot fi create astfel:
CREATE TABLE codPost_loc (
CodPostal CHAR(6) CONSTRAINT pk_cp PRIMARY KEY,
Localitate CHAR (35) NOT NULL,
Judet CHAR(25) NOT NULL ) ;
CREATE TABLE clienti (
CodClient INTEGER CONSTRAINT pk_cp PRIMARY KEY,
NumeClient CHAR (30) NOT NULL CONSTRAINT un_numeclient UNIQUE,
Adresa CHAR(60),
CodPostal CHAR(6) NOT NULL CONSTRAINT ref_cl_codpost
REFERENCES codpost_loc (CodPostal) ) ;
Se pot observa cu uşurinţă clauzele PRIMARY KEY folosite pentru declararea cheilor
primare, UNIQUE pentru cheile alternative, NOT NULL pentru interzicerea valorilor nule, precum şi
6 Instrumente software pentru afaceri

REFERENCES pentru declararea cheii străine. În plus, opţiunea CONSTRAINT ne ajutăm să


“botezăm” fiecare restricţie după cum dorim.
Spre deosebire de alte SGBD-uri, în ACCESS comenzile nu pot fi introduse direct, ci incluse
în module de program. Iată modulul CREARETABELE():
Sub CreareTabele()
Dim dbs As Database
'Set dbs = OpenDatabase("Z:\ISA_2006_ZI\BD\vinzari.mdb")
Set dbs = CurrentDb
dbs.Execute "CREATE TABLE codPost_loc " _
& "(CodPostal CHAR(6) CONSTRAINT pk_cp PRIMARY KEY, " _
& " Localitate CHAR (35) NOT NULL, " _
& " Judet CHAR(25) NOT NULL) ; "
dbs.Execute "CREATE TABLE clienti " _
& "(CodClient INTEGER CONSTRAINT pk_cp PRIMARY KEY, " _
& " NumeClient CHAR (30) NOT NULL CONSTRAINT un_numeclient UNIQUE, " _
& " Adresa CHAR(60), " _
& " CodPostal CHAR(6) NOT NULL CONSTRAINT ref_cl_codpost REFERENCES codpost_loc (CodPostal) ) ;"
dbs.Execute "CREATE TABLE facturi " _
& "(NrFact INTEGER CONSTRAINT pk_facturi PRIMARY KEY, " _
& " CodClient INTEGER NOT NULL CONSTRAINT ref_fact_cl REFERENCES clienti (CodClient), " _
& " Data DATETIME NOT NULL, " _
& " ValoareTotala NUMERIC NOT NULL, " _
& " TVAColectata NUMERIC NOT NULL) ;"
End Sub
Deşi în capitolul 4 spuneam că structura unei baze de date este constantă, există situaţii în care
trebuie să:
- adăugăm un atribut;
- eliminăm un atribut;
- schimbăm tipul unui atribut;
- modificăm lungimea unui atribut;
- să declarăm o nouă restricţie
- să anulăm o restricţie în vigoare.
Deoarece baza de date este în uz, nu ne putem permite să ştergem şi apoi să recreăm tabelele,
pentru că aceasta echivalează cu pierderea iremediabilă a înregistrărilor existente. Aşa că este necesară
folosirea comenzii ALTER TABLE. Dacă în tabela CLIENŢI se doreşte păstrarea şi a codului fiscal al
fiecărui furnizor, este necesară adăugarea atributului CodFiscal, care este un şir de caractere (un număr
precedat de litera R, dacă clientul respectiv este plătitor de TVA) de lungime 10 caractere. Comanda
utilizată este:
ALTER TABLE CLIENŢI ADD CodFiscal CHAR(10)
În SQL ştergerea unei tabele din baza de date este realizabilă cu ajutorul comenzii DROP
TABLE. Iată cum ar putea lansate comenzile de ştergere ale celor trei tabele pe care abia le-am creat
acum jumătate de pagină:
Sub StergeTabele()
Dim dbs As Database
Set dbs = OpenDatabase("Z:\ ISA_2006_ZI\BD\vinzari.mdb")
dbs.Execute "DROP TABLE facturi ;"
dbs.Execute "DROP TABLE clienti ;"
dbs.Execute "DROP TABLE codpost_loc ;"
End Sub
Am trecut în revistă până în acest moment principalele clauze ale comenzii CREATE TABLE
(şi ALTER TABLE) pentru declararea cheilor primare, alternative şi străine, şi valorilor nenule.
Limbajul SQL 7

Nemeritat, a fost omisă clauza CHECK prin care putem defini restricţii utilizator sub forma regulilor
de validare la nivel de atribut sau înregistrare. Astfel, în tabela CLIENŢI valorile atributului CodClient
trebuie să înceapă de la 1001, iar numele clientului se doreşte a fi scris cu majuscule întotdeauna.
Aceste două reguli de validare pot fi definite în SQL atât în momentul creării:
CREATE TABLE clienti (
CodClient INTEGER CONSTRAINT pk_cp PRIMARY KEY
CONSTRAINT ck_codclient CHECK (CocClient > 1000),
NumeClient CHAR (30) NOT NULL CONSTRAINT un_numeclient UNIQUE
CONSTRAINT ck_numeclient CHECK (NumeClient = UPPER(NumeClient)),
Adresa CHAR(60),
CodPostal CHAR(6) NOT NULL CONSTRAINT ref_cl_codpost
REFERENCES codpost_loc (CodPostal) ) ;
cât şi ulterior prin ALTER TABLE. Din păcate, ACCESSul nu este prea îngăduitor în această privinţă,
clauza CHECK fiind interzisă. Singura modalitate de declarare a regulilor este cea procedurală:
Sub Reguli_Atribute()
Dim dbs As Database, tdf As TableDef, fld As Field
Set dbs = CurrentDb
' CLIENTI.CodClient > 1000
Set tdf = dbs.TableDefs("clienti")
Set fld = tdf.Fields("CodClient")
fld.ValidationRule = "[CodClient] > 1000"
fld.ValidationText = "Cel mai mic cod de client acceptat este 1001 !"
' CLIENTI.NumeClient se scrie numai cu majuscule
Set tdf = dbs.TableDefs("clienti")
Set fld = tdf.Fields("NumeClient")
fld.ValidationRule = "StrComp(UCase([NumeClient]), [NumeClient], 0) = 0"
fld.ValidationText = "Literele din numele clientului sunt obligatoriu majuscule !"
' Prima litera din CLIENTI.Adresa este majuscula. Restul, la alegere !
Set tdf = dbs.TableDefs("clienti")
Set fld = tdf.Fields("Adresa")
fld.ValidationRule = "StrComp(LEFT(UCase([Adresa]),1), LEFT([Adresa],1), 0) = 0"
fld.ValidationText = "Prima litera din adresa clientului trebuie sa fie majuscula !"
'Data facturii
Set tdf = dbs.TableDefs("facturi")
Set fld = tdf.Fields("Data")
fld.ValidationRule = "[Data] BETWEEN #1-1-2005# AND #12-31-2010# "
fld.ValidationText = "Data facturii trebuie sa se incadreze in intervalul 1 ian.2005 - 31 dec.2010 !"
End Sub
Despre reguli la nivel de înregistrare, ce să mai vorbim... Astfel, dacă în tabela FACTURI s-ar
dori instituirea regulii după care TVA-ul poate fi cel mult egal cu 0,19/1,19 din valoarea totală a
fiecărei facturi (prietenii ştiu de ce !), restricţia ar putea fi definită la creare astfel:
CREATE TABLE facturi (
NrFact INTEGER CONSTRAINT pk_facturi PRIMARY KEY,
CodClient INTEGER NOT NULL CONSTRAINT ref_fact_cl REFERENCES clienti (CodClient),
Data DATE NOT NULL,
ValoareTotala NUMERIC NOT NULL,
TVAColectata NUMERIC NOT NULL),
CONSTRAINT ck_tva_valtot CHECK (TVAColectata <= ValoareTotala * 0.19 / 1.19) );
ACCESS-ul este, după cum vă imaginaţi, impasibil la graţiile (de tip CHECK) ale SQL-ului,
aşa că singura soluţie e tot cea procedurală:
Sub Regula_inregistrare()
8 Instrumente software pentru afaceri

Dim dbs As Database, tdf As TableDef


Set dbs = CurrentDb
Set tdf = dbs.TableDefs("facturi")
tdf.ValidationRule = "[TVAColectata] <= [ValoareTotala] * 0.19 / 1.19"
tdf.ValidationText = "TVA poate fi maxim 0,19/1,19 din valoarea totala a facturii !"
End Sub

6.3 COMENZI DE ACTUALIZARE A TABELELOR


SQL prezintă comenzi specifice pentru modificarea conţinutului unei tabele, înţelegând prin
aceasta trei acţiuni prin care se actualizează baza: a) adăugarea de noi linii la cele existente într-o
tabelă; b) ştergerea unor linii, c) modificarea valorii unui atribut.

6.3.1 Adăugare
Să presupunem că, la un moment dat, întreprinderea vinde produse şi firmei RODEX SRL
care are sediul pe strada Sapienţei, nr.44 bis, în localitatea Iaşi. Acest nou client trebuie "introdus" în
baza de date, operaţiune care în SQL, se realizează prin comanda:
INSERT INTO clienti VALUES (1009, ‘RODEX SRL’, ‘Sapienţei, 44 bis’, ‘706600’)
Fraza INSERT de mai sus poate fi scrisă şi sub forma:
INSERT INTO clienti (CodClient, NumeClient, Adresa, CodPostal)
VALUES (5009, ‘RODEX SRL’, ‘Sapienţei 44 bis’, 706600)
După cum se observă, după numele tabelei (CLIENŢI) au fost enumerate toate atributele
pentru care se introduc valori prin clauza VALUES. Dacă nu s-ar fi cunoscut adresa clientului RODEX,
atunci fraza INSERT ar fi avut una din formele:
INSERT INTO clienti (CodClient, NumeClient, Adresa, CodPostal)
VALUES (5009, "RODEX SRL", NULL, ‘6600’) sau
INSERT INTO clienti (CodClient, NumeClient, CodPostal) VALUES (5009, ‘RODEX SRL’, ‘6600’)
În noua linie a tabelei CLIENŢI valoarea atributului Adresa va fi NULL.
Conţinutul celor trei tabele din finalul capitolului 4 a fost realizat în ACCESS prin modulul
următor în care comanda INSERT este argumentul unei comenzi DoCmd.RunSQL:
Sub Inserturi()
' CODPOST_LOC
DoCmd.RunSQL ("INSERT INTO codPost_loc VALUES ('706600', 'Iasi', 'Iasi') ;")
DoCmd.RunSQL ("INSERT INTO codPost_loc VALUES ('706610', 'Iasi', 'Iasi') ;")
DoCmd.RunSQL ("INSERT INTO codPost_loc VALUES ('705300', 'Focsani', 'Vrancea') ;")
DoCmd.RunSQL ("INSERT INTO codPost_loc VALUES ('705725', 'Pascani', 'Iasi') ;")
DoCmd.RunSQL ("INSERT INTO codPost_loc VALUES ('706750', 'Tg.Frumos', 'Iasi') ;")
' CLIENTI
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1001, 'TEXTILA SA', 'Bld. Copou, 87', '706600' );")
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1002, 'MODERN SRL', 'Bld. Gãrii, 22', '705300' ) ;")
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1003, 'OCCO SRL', NULL, '706610') ;")
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1004, 'FILATURA SA', 'Bld. Unirii, 145', '705300' ) ;")
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1005, 'INTEGRATA SA', 'I.V.Viteazu, 115', '705725' ) ;")
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1006, 'AMI SRL', 'Galaþiului, 72', '706750' );")
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1007, 'AXON SRL', 'Silvestru, 2', '706610' ) ;")
DoCmd.RunSQL ("INSERT INTO clienti VALUES (1008, 'ALFA SRL', 'Prosperitãþii, 15', '705725' ) ;")
'FACTURI
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111111, 1003, #6-17-2005#, 17000, 0) ;")
Limbajul SQL 9

DoCmd.RunSQL ("INSERT INTO facturi VALUES (111112, 1001, #6-17-2005#, 2850, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111113, 1004, #6-18-2005#, 5850, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111114, 1003, #6-18-2005#, 2850, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111115, 1008, #6-18-2005#, 35700, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111116, 1008, #6-19-2005#, 8700, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111117, 1006, #6-20-2005#, 1100, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111118, 1007, #6-23-2005#, 15000, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111119, 1005, #6-24-2005#, 4720, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111120, 1003, #6-24-2005#, 3000, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111121, 1001, #6-24-2005#, 4250, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111122, 1007, #6-24-2005#, 8750, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111123, 1006, #6-25-2005#, 66000, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111124, 1004, #6-25-2005#, 38600, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111125, 1003, #6-30-2005#, 1280, 0);")
DoCmd.RunSQL ("INSERT INTO facturi VALUES (111126, 1002, #6-01-2005#, 54250, 0);")
End Sub
După cum se observă, deliberat TVA colectată este declarată zero la toate liniile inserate în
FACTURI. Aceasta pentru a avea motiv de modificare (UPDATE) – vezi paragraful pe peste linia
curentă.

6.3.2 Modificarea valorilor unor atribute


Pentru modificarea valorilor unuia sau multor atribute dintr-o tabelă, comanda utilizată este
UPDATE care are formatul general: UPDATE tabelă SET atribut = expresie WHERE predicat
Ca rezultat, vor fi modificate valorile atributului specificat, noile valori ale acestuia fiind cele
care rezultă în urma evaluării expresiei; modificarea se va produce pe toate liniile tabelei care
îndeplinesc condiţia specificată în predicat. Astfel comanda:
UPDATE facturi SET TVAColectata = INT(ValoareTotala * 19 / 1.19) / 100
va stabili valoarea TVA colectată pentru toate facturile (lipseşte clauza WHERE, deci vor fi afectate
toate liniile din tabela FACTURI) pe 0.19/1.19 din valoarea totală a fiecărei facturi. Funcţia INT
extrage doar partea întreagă dintr-un număr real (se elimină, deci, partea fracţionară), iar prin
împărţirea rezultatului la 100 ne asigurăm că TVA va avea două poziţii la partea fracţionară.
În ACCESS această actualizare se poate face în două moduri. Grafic, putem crea o interogare
de tip pe calapodul clasic al construirii machetelor (prezentat în paragraful 5.4), după “aducerea”
tabelei FACTURI în machetă, selectând din meniul Query Type a opţiunii Update Query – vezi
partea stângă a figurii 6.2. Partea dreaptă a figurii prezinta noua formă a machetei, în care apare linia
Update To şi dispar Sort şi Show. La rubrica Update To se introduce expresia de calcul a valorilor
atributului TVAColectată. Cea de-a două modalitate este cea procedurală, comanda prin care se
lansează UPDATE-rile fiind, ca şi in cazul inserării, DoCmd.RunSQL.
Sub Updateuri()
DoCmd.RunSQL ("UPDATE facturi SET TVAColectata = INT(ValoareTotala * 19 / 1.19) / 100 ;")
DoCmd.RunSQL ("UPDATE facturi SET TVAColectata = 0 WHERE NrFact = 111117 ;")
DoCmd.RunSQL ("UPDATE facturi SET TVAColectata = INT(ValoareTotala * 9 / 1.09) / 100 " & _
" WHERE NrFact IN (111118, 111122) ;")
End Sub
10 Instrumente software pentru afaceri

Figura 6.2. Interogare de modificare

Modulul de mai sus, specific ACCESSului conţine, pe lângă comanda UPDATE explicată,
alte două, prin care facturii 111117 îi este declarat procentul zero de TVA, iar a doua indică faptul că
toate produsele/serviciile din facturile 111118 şi 111122 au procentul de TVA de 9%. Deşi cei mai
mulţi utilizatori ar opta pentru varianta grafică, va asigurăm că varianta procedurală este mai
productivă atunci când sunt necesare actualizări repetate, aşa cum este cazul de mai sus.

6.3.3 Ştergeri
Operaţiunea de eliminarea a una sau mai multe linii dintr-o tabelă, pe baza unui predicat, se
realizează în SQL prin comanda DELETE care are sintaxa: DELETE FROM nume-tabelă WHERE predicat
Dacă am dori să eliminăm din tabela CLIENŢI linia aferentă clientului MODERN SRL (cod
1002), comanda ar fi:
DELETE FROM clienti WHERE CodClient = 1002
În ACCESS, similar interogărilor pentru modificare pot fi create şi interogări pentru ştergere,
în care se specifică criteriul pe care trebuie să-l satisfacă liniile pentru a fi şterse din tabela indicată
(fiind în criză de spaţiu, nu vom mai prezenta nici o figură în acest scop). Prin program, dacă am dori
eliminarea tuturor înregistrărilor din tabelele bazei, apoi re-adăugarea şi re-modificarea lor, ne-am
putea servi de blocul următor:
Sub Stergeri()
DoCmd.RunSQL ("DELETE FROM facturi ;")
DoCmd.RunSQL ("DELETE FROM clienti ;")
DoCmd.RunSQL ("DELETE FROM codPost_loc ;")
Call Inserturi
Call Updateuri
End Sub

6.4 STRUCTURA DE BAZĂ A FRAZEI SELECT


Fără îndoială, cea mai gustată parte din SQL este cea legată de interogarea bazei, adică de
obţinerea de informaţii din cele mai diverse, prin prelucrări, grupări etc. Ceea ce a fost prezentat în
Limbajul SQL 11

paragraful 5.4 este doar o părticică din ceea ce poate fi “stors” dintr-o bază de date. Aşadar, în SQL o
interogare se formulează printr-o frază SELECT. Aceasta prezintă trei clauze principale: SELECT,
FROM şi WHERE.
 SELECT este utilizată pentru desemnarea listei de atribute (coloanele) din rezultat;
 FROM este cea care permite enumerarea relaţiilor din care vor fi extrase informaţiile aferente
consultării;
 prin WHERE se desemnează condiţia (predicatul), simplă sau complexă, pe care trebuie să le
îndeplinească liniile tabelelor (enumerate în clauza FROM) pentru a fi extrase în rezultat.
La modul general (şi simplist) o consultare simplă în SQL poate fi prezentată astfel: SELECT
C1, C2, ..., Cn FROM R1, R2, ..., Rm WHERE P.
Execuţia unei fraze SELECT se concretizează în obţinerea unui rezultat de forma unei tabele
(relaţii). Când clauza WHERE este omisă, se consideră implicit că predicatul P are valoarea logică
"adevărat". Dacă în locul coloanelor C1, C2, ... Cn apare simbolul "*", în tabela-rezultat vor fi incluse
toate coloanele (atributele) din toate relaţiile specificate în clauza FROM. De asemenea, în tabela-
rezultat, nu este obligatoriu ca atributele să prezinte nume identic cu cel din tabela enumerată în clauza
FROM. Schimbarea numelui se realizează prin opţiunea AS.
Uneori, rezultatul interogării "încalcă" poruncile modelului relaţional. Conform restricţiei de
entitate, într-o relaţie nu pot exista două linii identice. Or, în SQL, rezultatul unei consultări poate
conţine două sau mai multe tupluri identice. Pentru eliminarea liniilor identice este necesară utilizarea
opţiunii DISTINCT: SELECT DISTINCT C1, C2, ..., Cn FROM R1, R2, ..., Rm WHERE P
Am început acest capitol prin a arăta fraza SELECT care se ascunde în spatele unei consultări
“grafice” ACCESS. Fraza:
SELECT facturi.NrFact, facturi.Data, [ValoareTotala]-[TVAColectata] AS ValFaraTVA,
facturi.TVAColectata, facturi.ValoareTotala
FROM facturi WHERE (((facturi.Data)>#6/20/2005#));
conţine şi un câmp calculat – ValFărăTVA, al cărui nume se specifică prin clauza AS, şi ale cărui valori
se determină prin relaţia ValoareTotală – TVAColectată. Predicatul de selecţie (clauza WHERE) asigură
extragerea în rezultat doar a facturilor emise după 20 iunie 2005.

Cum se poate introduce o interogare în ACCESS fără a o “desena” cu proiectantul de machete


pentru interogări prezentat în paragraful 5.4 ? Mai întâi creăm o interogare foarte simplă – să-i zicem –
INTEROG. După modelul indicat în stânga figurii 6.3 îi vizualizăm definiţia folosind opţiunea SQL
View, iar apoi în fereastra care apare înlocuim fraza SELECT cu cea care ne interesează (frază care nu
are, probabil, nici o legătură cu definiţia actuală a interogării), după care se apasă butonul Run
(semnul mirării).
Iar dacă vrem să facem acelaşi lucru prin program, folosim modulul următor:
Sub interogareBETWEEN()
Dim consultare As QueryDef
Set consultare = CurrentDb.QueryDefs("interog")
consultare.SQL = "SELECT * FROM facturi WHERE nrfact BETWEEN 111120 AND 111124 ; "
DoCmd.OpenQuery ("interog")
End Sub
Modulul interogareBETWEEN() declară (prin Dim) obiectul consultare ca fiind definiţia unei
interogări (QueryDef), preia (prin comanda Set) în consultare fraza SELECT care constituie definiţia
12 Instrumente software pentru afaceri

interogării create anterior – interog –, modifică definiţia acestea prin linia consultare.SQL = “SELECT
…” şi, în final, execută noua variantă a interogării, rezultatul fiind similar variantei din figura 6.3.

Figura 6.3. Schimbarea definiţiei unei interogări şi re-execuţia sa

Fireşte, noile definiţii pot fi salvate sau se poate renunţa la ele, mai ales atunci lucrăm cu
module ce pot apelate ori de câte ori este nevoie.

Operatorul BETWEEN
Fraza SELECT de mai sus conţine operatorul BETWEEN care va extrage din tabelă numai
facturile cu numerele cuprinse între 111120 şi 111124. Fără BETWEEN predicatul ar trebuit scris
WHERE nrfact >= 111120 AND nrfact <= 111124.

Operatorul LIKE
Operatorul LIKE se foloseşte pentru a compara un atribut de tip şir de caractere (ex.
NumeClient, Adresa, Localitate) cu un literal (constantă de tip şir de caractere). Astfel, dacă se doreşte
obţinerea unei tabele-rezultat care să conţină numai clienţii ai căror nume începe cu litera M, putem
scrie predicatul din clauza WHERE sub forma: NumeClient LIKE "M%". Deoarece după litera M apare
semnul "%" (sau “*”), se vor extrage din tabela CLIENŢI toate tuplurile pentru care valoarea
atributului NumeClient începe cu litera M, indiferent de lungimea acestuia (ex. MELCRET, MIGAS,
MITA, MATSUSHITA etc.). Despre semnul "%" (sau “*”) se spune că este un specificator multiplu,
joker sau mască. Un alt specificator multiplu utilizat în multe versiuni SQL este liniuţa-de-subliniere
("_") sau semnul de întrebare (“?”). Spre deosebire de "%", "_" substituie un singur caracter. Diferenţa
dintre cei doi specificatori multipli este pusă în evidenţă în continuare. Astfel, dacă interesează care
sunt clienţii ai căror nume începe cu litera A şi sunt societăţi cu răspundere limitată (SRL-uri), fraza
SELECT care furnizează răspunsul este:
SELECT * FROM CLIENŢI WHERE NumeClient LIKE "A__ SRL%"
(vezi partea stângă a figurii 6.4). Dacă s-ar fi utilizat simbolul "%" de maniera următoare:
SELECT * FROM CLIENŢI WHERE NumeClient LIKE "A%SRL%"
rezultatul ar fi fost cel din partea dreaptă a figurii.
Limbajul SQL 13

Figura 6.4. Folosirea specificatorilor multipli

În concluzie, "_" sau “?” înlocuiesc (substituie) un singur caracter, în timp ce "%" sau “*”
înlocuiesc un şir de caractere de lungime variabilă (între 0 şi n caractere). Cei doi specificatori multipli
pot fi utilizaţi împreună.

Operatorul IN
Un alt operator util este IN cu formatul general: expresie1 IN (expresie2, expresie3, ...).
Rezultatul evaluării unui predicat ce conţine acest operator va fi "adevărat" dacă valoarea expresiei1
este egală cu (cel puţin) una din valorile: expresie2, expresie3, ...
Spre exemplu, pentru a afla care sunt clienţii din localităţile din judeţele Iaşi şi Vaslui, fără
utilizarea operatorului IN se scrie:
SELECT * FROM codpost_loc WHERE Judet = 'Iasi' OR Judet = 'Vaslui'
Iar utilizând IN:
SELECT * FROM codpost_loc WHERE Judet IN ("Iasi", "Vaslui")

Operatorul IS NULL
O valoare nulă este o valoare nedefinită. Este posibil ca la adăugarea unei linii într-o tabelă,
valorile unor atribute să fie necunoscute. În aceste cazuri valoarea atributului pentru tuplul respectiv
este nulă. Reamintim că, prin definiţie, nu se admit valori nule pentru grupul atributelor care constituie
cheia primară a relaţiei. Pentru aflarea clienţilor pentru care nu s-a introdus adresa, se poate scrie:
SELECT * FROM clienti WHERE Adresa IS NULL
Cum în baza noastră de date, numai clientului OCCO SRL nu-i cunoaştem adresa, rezultatul
interogării este cel din figura 6.5 (în ACCESS valorile NULL se afişează ca şi cum ar conţine spaţii).

Figura 6.5. Extragerea valorilor NULLe

Observaţii
 Valoarea NULL nu se confundă cu valoarea zero (pentru atributele numerice) sau cu valoarea
"spaţiu" (pentru atributele de tip şir de caractere)
 Operatorul NULL se utilizează cu IS şi nu cu semnul "=". Dacă s-ar utiliza expresia = NULL şi nu
expresia IS NULL, rezultatul evaluării va fi întotdeauna fals, chiar dacă expresia nu este nulă !

Opţiunile DISTINCT şi ORDER BY


Dorim să aflăm judeţele în care firma are clienţi. Este necesară parcurgerea relaţiei
CODPOST_LOC, singurul atribut care interesează fiind Judeţ:
SELECT DISTINCT Judet FROM codpost_loc
După cum se observă în partea stângă a figurii 6.6, SQL nu elimină dublurile automat, iar dacă
se doreşte ca în tabela-rezultat o localitate să figureze o singură dată, se utilizează opţiunea DISTINCT
(rezultatul în dreapta figurii 6.6):
14 Instrumente software pentru afaceri

SELECT DISTINCT Judet FROM codpost_loc

Figura 6.6. Fără şi cu DISTINCT

În continuare vrem să obţinem denumirea fiecărei localităţi şi judeţul în care se află, dar liniile
rezultatului trebuie ordonate în funcţie de judeţ şi, în cadrul aceluiaşi judeţ, în ordinea inversă a
localităţii (de la Z la A), fraza SELECT se formulează după cum urmează, rezultatul fiind prezentat în
figura 6.7.
SELECT DISTINCT Localitate, Judet FROM codpost_loc
ORDER BY Judet ASC, Localitate DESC

Figura 6.7. Clauza ORDER BY

Opţiunile ASCENDING (crescător) şi DESCENDING (descrescător) indică deci modul în care se


face ordonarea tuplurilor tabelei-rezultat al interogării. Prioritatea de ordonare este stabilită prin
ordinea atributelor specificate în ORDER BY: ordonarea "principală" se face în funcţie de valorile
primului atribut specificat; în cadrul grupelor de tupluri pentru care valoarea primului atribut este
identică, ordinea se stabileşte după valoarea celui de-al doilea atribut specificat s.a.m.d. Dacă în
ORDER BY lipsesc opţiunile ASCENDING/DESCENDING, ordonarea se face crescător.

6.5 JONCŢIUNI
După cum afirmam şi în paragraful 5.4 majoritatea informaţiilor obţinute dintr-o bază de date
necesită “răsfoirea” simultană a două sau mai multe tabele. Interogarea Fac_dupa20iunie2005v2 din
figura 5.41 foloseşte trei tabele. Folosind opţiunea SQLView obţinem o frază SELECT cu totul
remarcabilă:
SELECT facturi.NrFact, facturi.Data, clienti.NumeClient, codPost_loc.Localitate,
[ValoareTotala]-[TVAColectata] AS Expr1, facturi.TVAColectata, facturi.ValoareTotala, *
FROM (codPost_loc INNER JOIN clienti ON codPost_loc.CodPostal = clienti.CodPostal)
INNER JOIN facturi ON clienti.CodClient = facturi.CodClient
WHERE (((facturi.NrFact)>#6/20/2005#) AND ((codPost_loc.Localitate)="Iasi"));
Clauza FROM vine acum în centrul atenţiei prin apariţia clauzei INNER JOIN. Iată cum stau
lucrurile: deoarece în lista pe care vrem să obţinem se găsesc atribute plasate în cele trei tabele, în
clauza FROM trebuie enumerate cele trei tabele; în fapt, după cum am văzut în capitolul 4, cele trei
tabele sunt legate prin restricţii referenţiale, atributele de legătura fiind cheile străine – cheile primare.
Astfel, legătura dintre FACTURI şi CLIENŢI se poate realiza prin intermediul atributului CodClient
care este cheie primară în CLIENŢI (tabela părinte) şi cheie străină în FACTURI (tabela copil).
Limbajul SQL 15

Legătura dintre aceste două tabele care prezintă un câmp comun se numeşte joncţiune şi se
simbolizează în SQL prin INNER JOIN:
SELECT *
FROM facturi INNER JOIN clienti ON facturi.CodClient=clienti.CodClient
Fără a intra în prea multe detalii teoretice, reţinem că, ori de câte ori informaţiile necesare şi
condiţiile pe care trebuie să le îndeplinească acele informaţii privesc atribute aflate în tabele diferite,
trebuie făcută joncţiunea acestor tabele. Când tabele nu pot fi joncţionate direct, trebuie aduse “cu
forţa” în clauza FROM şi tabelele care să completeze “lanţul”.
Ne interesează, spre exemplu, numărul şi data facturilor emise clienţilor din judeţul Iaşi.
Numărul şi data facturilor se găsesc în tabela FACTURI (atributele NrFact şi Data), însă pentru
denumirea judeţului există un atribut (Judet) în tabela CODPOST_LOC. Cele două tabele nu pot fi
joncţionate direct, aşa încât atragem în interogare şi cea de-a treia tabelă – CLIENŢI:
SELECT NrFact, Data
FROM (facturi INNER JOIN clienti ON facturi.codclient=clienti.codclient)
INNER JOIN codpost_loc ON codpost_loc.codpostal=clienti.codpostal
WHERE judet=’Iasi’
ORDER BY NrFact
Scrisă sub formă de modul ACCESS – InterogareJONCTIUNE1() – şi lansată prin “apăsarea
butonului Run, fraza SELECT obţine rezultatul din figura 6.8.

Figura 6.8. Un modul ACCESS cu frază SELECT ce joncţiunează cele trei tabele (plus rezultatul)

Lăsam să se înţeleagă, la un moment dat, că în SQL pot fi formulate interogări mult mai
complexe decât se poate realiza cu ajutorul machetei din paragraful 5.4. Haideţi să luăm o asemenea
problemă, ce-i drept nu atât de complicată precum ameninţam: Care sunt facturile emise în aceeaşi zi
ca şi factura 111113 ? Dificultatea ţine de faptul că cerinţa este formulată indirect, adică vrem să
aflăm facturile emise într-o zi (Data), dar noi nu ştim data etalon, ci factura-etalon.
Problema propusă poate fi rezolvată relativ uşor folosind o subconsultare, după cum va fi
prezentat într-un paragraf viitor. Până una-alta, soluţia pe care o avem în acest moment la îndemână se
bazează pe autojoncţiune. Autojoncţiunea înseamnă joncţiunea unei tabele (FACTURI) cu ea-însăşi,
practic, joncţiunea a două instanţe ale unei aceleaşi tabele. Pentru a joncţiune cele două instanţe
trebuie să aibă pseudonime (aliasuri) diferite, în cazul nostru F1 şi F2. Întrucât ne interesează facturi
emise în aceeaşi zi cu 111113, autojoncţiunea se face după atributul Data:
SELECT *
16 Instrumente software pentru afaceri

FROM facturi F1 INNER JOIN facturi F2 ON F1.data=F2.data


WHERE F2.NrFact = 111113
Iată rezultatul – vezi figura 6.9. Rezultatul conţine 10 coloane, cinci din prima instanţă a
tabelei FACTURI (F1) şi cinci din a doua instanţă (F2). ACCESSul e destul de inspirat să scrie
înaintea fiecărui atribut din ce instanţă provine.

Figura 6.9. Facturile emise în aceeaşi zi ca şi 111113

Toate liniile rezultatului respectă condiţia de joncţiune - F1.data=F2.data. Jumătatea din dreapta
a coloanelor se referă strict la factura etalon – 111113, iar cea din stânga la facturile din aceeaşi zi cu
111113, inclusiv factura-etalon. Pentru a răspunde punctual la problemă, precizăm atributele
(coloanele) care ne interesează şi eliminăm din rezultat factura 111113:
SELECT F1.NrFact, F1.Data
FROM facturi F1 INNER JOIN facturi F2 ON F1.data=F2.data
WHERE F2.NrFact = 111113 AND F1.NrFact <> 111113

6.6 FUNCŢII-AGREGAT: COUNT, SUM, AVG, MAX, MIN


Cu funcţiile agregat facem un prim pas spre analiza datelor din bază. Li se spune funcţii
agregat deoarece, în absenţa grupării (clauza GROUP BY – vezi ultimul paragraf din acest capitol)
rezultatul unei asemenea funcţii are forma unei tabele cu o singură linie.

Funcţia COUNT
Contorizează valorile unei coloane, altfel spus, numără, într-o relaţie, câte valori diferite de
NULL are coloana specificată. Dacă în locul unui atribut apare semnul asterisc (*) se numără liniile
rezultatului. Astfel, dacă vrem să aflăm câţi clienţi are firma vom folosi interogarea (rezultatul său se
află in stânga figurii 6.10).
SELECT COUNT (CodClient) AS Nr_Clienti1, COUNT (*) AS Nr_Clienti2 FROM clienti

Figura 6.10. Nişte COUNT-uri

Teoretic, în tabela CLIENŢI pot apărea şi clienţi cărora încă nu li s-a trimis încă nici o factură.
Dacă vrem să aflăm răspunsul la întrebarea: La câţi clienţi s-au trimis facturi ?, am fi tentaţi să
folosim interogarea:
SELECT COUNT () AS NrClienti1, COUNT(CodClient) AS NrClienti2
FROM clienti INNER JOIN facturi ON clienti.CodClient=facturi.CodClient
care, însă, ne va furniza un răspuns eronat (vezi partea dreaptă a figurii 6.10). În produsele care
respectă recomandările standardelor SQL, rezultatul corect poate fi însă obţinut prin utilizarea clauzei
DISTINCT astfel:
SELECT COUNT (DISTINCT CodClient) FROM facturi
Limbajul SQL 17

În ACCESS această opţiune nu este acceptată, aşa încât mai aşteptăm până la paragraful
dedicat subconsultărilor.

Funcţia SUM
Funcţia SUM calculează suma valorilor unei coloane. Pentru a afla suma valorilor totale ale
facturilor, soluţia este cât se poate de simplă:
SELECT SUM (ValoareTotala) AS Total_ValoriFacturi FROM facturi
iar totalul valorilor pentru facturile trimise clientului AXON SRL este obţinut astfel:
SELECT SUM (ValoareTotala) AS Total_Fact_AXON
FROM facturi INNER JOIN clienti ON facturi.CodClient = clienti.CodClient
WHERE NumeClient = ‘AXON SRL’
Funcţiile MAX şi MIN
Determină valorile maxime, respectiv minime ale unei coloane în cadrul unei tabele. Valorile
cea mai mică şi cea mai mare ale unei facturi se află astfel:
SELECT MIN(ValoareTotala), MAX(ValoareTotala) FROM facturi
Atenţie ! La întrebarea Care este factura emisă cu cea mai mare valoare ? nu putem răspunde
deocamdată. Varianta următoare nu este corectă: SELECT NrFactura, MAX(ValoareTotala ) FROM facturi
La execuţia acestei interogări se afişează un mesaj de eroare, soluţia problemei fiind posibilă
ceva mai pe finalul capitolului.

6.7 SUB-CONSULTĂRI. OPERATORUL IN


O altă facilitate deosebit de importantă a limbajului SQL o constituie posibilitatea includerii
(imbricării) a două sau mai multe fraze SELECT, astfel încât pot fi formulate interogări cu mare grad
de complexitate. Operatorul cel mai des întrebuinţat este IN. Astfel, revenind la o problemă anterioară -
Care sunt facturile emise în aceeaşi zi în care a fost întocmită factura 111113 ? – în locul epuizantei
auto-joncţiuni putem recurge la subconsultare:
SELECT * FROM facturi WHERE NrFact <> 111113 AND Data IN
(SELECT Data FROM facturi WHERE NrFact=111113)
Sub-consultarea SELECT Data FROM facturi WHERE NrFact = 111113 are ca rezultat o tabelă
alcătuită dintr-o singură coloană (Data) şi o singură linie ce conţine valoarea atributului Data pentru
factura 111113, ca în stânga figurii 6.11. Clauza WHERE Data IN determină căutarea în tabela
FACTURI a tuturor tuplurilor (liniilor) care au valoarea atributului Data egală cu una din valorile
tuplurilor (în cazul nostru, egală cu valoarea tuplului) din tabela obţinută prin "sub-consultare" (în
cazul nostru, tabela din stânga figurii). Cu alte cuvinte, în acest caz WHERE Data IN va selecta toate
facturile pentru care data emiterii este 18/06/2005 – partea dreaptă a figurii 6.11.

Figura 6.11 Rezultatul sub-consultării (stânga) şi al interogării

Dacă s-ar schimba condiţia de selecţie, în sensul că ne-ar interesa facturile emise în alte zile
decât cea în care a fost întocmită factura 111113 operatorul de sub-consultare va fi NOT IN:
18 Instrumente software pentru afaceri

SELECT * FROM facturi WHERE Data NOT IN


(SELECT Data FROM facturi WHERE NrFact = 111113)
Ca să încheiem paragraful cu o interogare mai prezentabilă, ne interesează clienţii cărora li
s-au trimis facturi întocmite în aceeaşi zi cu factura 111113:
SELECT DISTINCT NumeClient FROM clienti WHERE CodClient IN
(SELECT CodClient FROM facturi WHERE Data IN
(SELECT Data FROM facturi WHERE NrFact = 111113))
Am ilustrat modul în care pot fi imbricate (înlănţuite, incluse) trei fraze SELECT.

6.8 REUNIUNE, INTERSECŢIE, DIFERENŢĂ


Operatorul pentru reuniune este deci UNION. De remarcat că, la reuniune, SQL elimină
automat dublurile, deci nu este necesară utilizarea clauzei DISTINCT. Operatorul UNION este prezent în
toate SGBD-urile importante. Dacă două relaţii, R1 şi R2 sunt uni-compatibile, adică au acelaşi număr
de atribute care corespund sintactic (adică primul atribut din R1 este de acelaşi tip cu primul atribut
din R2), se poate scrie SELECT * FROM R1 UNION SELECT * FROM R2.
În ceea ce ne priveşte, vrem să aflăm cum se numesc clienţii cărora le-am emis facturi pe 23
sau pe 24 iunie 2005, avem la dispoziţie două variante, una bazată pe operatorul logic OR:
SELECT DISTINCT NumeClient FROM clienti WHERE CodClient IN
(SELECT DISTINCT CodClient FROM facturi
WHERE Data = #6/23/2005# OR Data = #6/24/2005#)
şi o altă bazată pe reuniune:
SELECT DISTINCT NumeClient FROM clienti WHERE CodClient IN
(SELECT DISTINCT CodClient FROM facturi WHERE Data = #6/23/2005# )
UNION
SELECT DISTINCT NumeClient FROM clienti WHERE CodClient IN
(SELECT DISTINCT CodClient FROM facturi WHERE Data = #6/24/2005#)
Pentru realizarea intersecţiei a două tabele unicompatibile, R1 şi R2, în standardele SQL a fost
introdus operatorul INTERSECT: SELECT * FROM R1 INTERSECT SELECT * FROM R2. Dacă în
produsele profesionale, precum DB2 (IBM) sau Oracle operatorul este prezent, în schimb multe din
cele din categoria “uşoară”, precum Visual Fox Pro şi ACCESS INTERSECT rămâne un deziderat,
funcţionalitatea sa realizându-se prin subconsultări (operatorul IN) sau, uneori, prin joncţiune. Astfel,
dacă dorim să aflăm cum se numesc clienţii cărora le-am emis facturi şi pe 23 şi pe 24 iunie 2005,
soluţia cea mai la îndemână în ACCESS este:
SELECT DISTINCT NumeClient FROM clienti WHERE CodClient IN
(SELECT DISTINCT CodClient FROM facturi WHERE Data = #6/23/2005# )
AND CodClient IN
(SELECT DISTINCT CodClient FROM facturi WHERE Data = #6/24/2005#)
Diferenţa dintre tabelele R1 şi R2 (unicompatibile) se realizează utilizând operatorul MINUS
sau EXCEPT, însă implementările sunt similare operatorului INTERSECT. Astfel, pentru a obţine
clienţii cărora le-am emis facturi şi pe 24, dar nu şi pe 24 iunie 2005, soluţia ACCESS este:
SELECT DISTINCT NumeClient FROM clienti WHERE CodClient IN
(SELECT DISTINCT CodClient FROM facturi WHERE Data = #6/24/2005# )
AND CodClient NOT IN
(SELECT DISTINCT CodClient FROM facturi WHERE Data = #6/23/2005#)
Limbajul SQL 19

6.9 GRUPAREA TUPLURILOR. CLAUZELE GROUP BY ŞI HAVING


În paragraful 5.4 făceam cunoştinţă cu o primă interogare în care era necesară gruparea
liniilor. Ne interesa valoarea zilnică a vânzărilor într-o anumită perioadă, iar cadrul construirii
interogării (VinzariPeZile_interval_la_alegere) lua forma din figura 5.42. Folosind din nou opţiunea
SQL View să vedem fraza SELECT ce se ascunde în spatele machetei:
SELECT facturi.Data, Sum(facturi.TVAColectata) AS SumOfTVAColectata,
Sum(facturi.ValoareTotala) AS SumOfValoareTotala,
Sum([ValoareTotala]-[TVAColectata]) AS ValFaraTVA
FROM facturi
GROUP BY facturi.Data
HAVING (((facturi.Data) Between [Data initiala:] And [Data finala:]))
ORDER BY facturi.Data;
SQL permite utilizarea clauzei GROUP BY pentru a forma grupe (grupuri) de tupluri ale unei
relaţii, pe baza valorilor comune ale unei coloane. În frazele SELECT formulate până în acest paragraf,
prin intermediul clauzei WHERE au fost selectate tupluri din diferite tabele. Prin asocierea unei clauze
HAVING la o clauză GROUP BY este posibilă selectarea anumitor grupe de tupluri ce îndeplinesc un
criteriu.

Clauza GROUP BY
Rezultatul unei fraze SELECT ce conţine această clauză este o tabelă care va fi obţinută prin
regruparea tuturor liniilor din tabelele enumerate în FROM, care prezintă o aceeaşi valoare pentru o
coloană sau un grup de coloane. Formatul general este:
SELECT coloană 1, coloană 2, ...., coloană m FROM tabelă GROUP BY coloană-de-regrupare
Simplificăm problema, dorind o listă cu totalul zilnic al valorii facturilor emise. Fraza este
ceva mai simplă:
SELECT Data, SUM (ValoareTotala) AS Total_Zilnic FROM facturi GROUP BY Data
Tabela-rezultat va avea un număr de linii egal cu numărul de date calendaristice distincte din
tabela FACTURI. Pentru toate facturile aferente unei zile se va calcula suma valorilor, datorită
utilizării funcţiei SUM(ValoareTotala). Succesiunea paşilor este următoarea:
1. Se ordonează liniile tabelei FACTURI în funcţie de valoarea atributului Data - figura 6.12.

Figura 6.12. Pasul 1 al grupării

2. Se formează câte un grup pentru fiecare valoare distinctă a atributului Data - vezi figura 6.13.
20 Instrumente software pentru afaceri

Figura 6.13. Al doilea pas al grupării

3. Pentru fiecare din cele nouă grupuri se calculează suma valorilor atributului ValoareTotala. Tabela
rezultat va avea nouă linii, ca în figura 6.14.

Figura 6.14. Rezultatul final al grupării

Dacă interesează numărul facturilor emise pentru fiecare client, răspunsul poate fi obţinut prin
interogarea:
SELECT NumeClient, COUNT(NrFact) AS NrFacturi_pe_Client
FROM facturi INNER JOIN clienti ON facturi.CodClient = clienti.CodClient
GROUP BY NumeClient
Până la standardul SQL:1999 şi publicarea Amendamentului OLAP la acest standard, în SQL
nu puteau fi calculate, prin GROUP BY, subtotaluri pe mai multe niveluri. Pentru aceasta este necesară
scrierea de programe în SGBD-ul respectiv.

Clauza HAVING
Clauza HAVING permite introducerea unor restricţii care sunt aplicate grupurilor de tupluri,
deci nu tuplurilor "individuale", aşa cum "face" clauza WHERE. Din tabela rezultat sunt eliminate
toate grupurile care nu satisfac condiţia specificată. Clauza HAVING "lucrează" împreună cu o clauză
GROUP BY, fiind practic o clauză WHERE aplicată acesteia. Formatul general este:
SELECT coloană 1, coloană 2, .... , coloană m FROM tabelă
GROUP BY coloană-de-regrupare HAVING caracteristică-de-grup
Pentru facturile emise interesează valoarea zilnică a acestora (în funcţie de data la care au fost
întocmite), dar numai dacă aceasta (valoarea zilnică) este de mai mare de 40000 lei noi (RON).
SELECT Data, SUM(ValoareTotala) AS Vinzari_Zilnice
FROM facturi GROUP BY Data HAVING SUM(ValoareTotala) > 40000
Limbajul SQL 21

La execuţia acestei fraze, se parcurg cei trei paşi descrişi la începutul acestui paragraf, apoi,
dintre cele nouă tupluri obţinute prin grupare, sunt extrase numai cele care îndeplinesc condiţia
SUM(ValoareTotala) > 40000. Rezultatul final este cel din figura 6.15.

Figura 6.15. Zilele cu vânzări mai mari de 40000 RON

Şi acum, o interogare cu adevărat interesantă: Să se afişeze ziua în care s-au întocmit cele mai
multe facturi ! Iată soluţia:
SELECT Data, COUNT(*) AS nr_facturilor FROM facturi
GROUP BY Data HAVING COUNT(*) >= ALL
(SELECT COUNT(*) FROM facturi GROUP BY Data)
Avem de-a face cu o subconsultare al cărei rezultat (stânga figurii 6.16) serveşte drept termen
de comparaţie al predicatului (condiţiei) formulat în clauza HAVING.

Figura 6.16. Clauza HAVING cu folosirea unei subconsultări

Cam atât pentru acest capitol, disciplină, semestru (“informatic”) şi an (tot “informatic”) ! Vă
mulţumim pentru răbdare, şi vă asigurăm că cine a ajuns cu cititul (şi înţelesul) până în acest punct, are
toate şansele unui examen încununat de succes.

S-ar putea să vă placă și