Atestat FoxPro
Atestat FoxPro
ÎN VIZUAL FOXPRO
7
Nivelul conceptual (sau global) este nivelul imediat superior celui fizic, datele fiind privite prin
prisma semanticii lor, punându-se accent pe conţinutul lor efectiv şi pe relaţiile care le leagă de alte date.
Întreaga bază de date este descrisă prin intermediul unui număr restrâns de structuri care, deşi relativ simple,
prin transpunerea la nivel fizic devin extrem de complexe. Toţi utilizatorii îşi exprimă cerinţele de date la
nivel conceptual, prezentându-le administratorului bazei de date, acesta fiind cel care are o viziune globală
asupra organizării bazei concretizată printr-o schemă conceptuală aferentă.
Nivelul extern este ultimul nivel de abstractizare la care poate fi descrisă o bază de date. El este dat de
viziunea programatorului de aplicaţii, care realizează programele de aplicaţii pentru manipularea datelor şi
structura logică (subschema) corespunzătoare descrierii datelor aplicaţiei. Dacă la nivel conceptual baza de
date era abordată în ansamblul ei, în practică, un utilizator sau un grup de utilizatori lucrează numai cu o
porţiune specifică a bazei de date, în funcţie de departamentul în care îşi desfăşoară activitatea şi atribuţiile
sale (lor). Pentru a simplifica interacţiunea utilizator-bază de date se recurge la nivelul extern, în care baza de
date se prezintă sub diferite machete, sub-scheme sau scheme externe specifice necesităţilor fiecăriu
utilizator sau grup de utilizatori.
Sistemul de gestiune al bazei de date reprezintă software-ul propriu-zis al acesteia asigurând
realizarea următoarelor activităţi:
• definirea structurii bazei de date;
• încărcarea datelor în baza de date;
• accesul la date (consultare, interogare);
• întreţinerea bazei de date (colectarea şi refolosirea spaţiilor goale, refacerea bazei de date în
cazul unui incident);
• reorganizarea bazei de date (restructurarea şi modificarea strategiei de acces);
• securitatea datelor.
Aşadar, sistemul de gestiune al bazei de date apare ca un sistem complex de programe care asigură
interfaţa între o bază de date şi utilizatorii acestuia. În acest context, sistemului de gestiune al bazei de date îi
revin o serie de obiective:
• asigurarea independenţei datelor: independenţa datelor trebuie privită din două puncte de
vedere: independenţa fizică a datelor ce face ca memorarea datelor precum şi tehnicile fizice de
memorare să poată fi modificate fără a determina rescrierea programelor de aplicaţie, iar
independenţa logică a datelor ce se referă la posibilitatea adăugării de noi articole de date sau
extinderea structuri conceptuale (globale), fără ca aceasta să impună rescrierea programelor
existente;
• asigurarea unei redundanţe minime şi controlate a datelor din baza de date: memorarea
datelor, în cazul bazelor de date, se face astfel încât fiecare dată să apară o singură dată; totuşi,
nu sunt excluse nici cazurile în care, pentru a realiza performanţe sporite, referitoare la timpul de
acces la date şi răspuns la solicitările uilizatorilor, să se accepte o anumită redundanţă a datelor,
în acest caz însă instituidu-se un control automat în vederea asigurării coerenţei datelor din bază;
• asigurarea unor facilităţi sporite de utilizare a datelor: aceasta presupune:
– folosirea datelor de către mai mulţi utilizatori în diferite scopuri;
– accesul cât mai simplu al utilizatorului la date;
– existenţa unor limbaje performante de regăsire a datelor;
– posibilitatea unui acces multicriterial, fără sortări suplimentare;
– utilizarea unui limbaj cât mai apropiat de limbajul natural, cu posibilitatea exploatării
în mod facil a bazei de date şi de către utilizatorii neinformaticieni;
• sporirea gradului de securitate a datelor împotriva accesului neautorizat la ele;
• asigurarea integrităţii datelor împotriva unor ştergeri intenţionate sau neintenţionate, prin
intermediul unor proceduri de validare, a unor protocoale de control concurent şi a unor
proceduri de refacere a bazei de date după incidente;
• asigurarea partajabilităţii datelor: partajabilitatea datelor trebuie înţeleasă nu numai sub
aspectul asigurării accesului mai multor utilizatori la aceleaşi date, ci şi acela al posibilitătii
dezvoltării unor aplicaţii fără a se modifica structura bazei de date.
Pentru realizarea obiectivelor enumerate mai sus, sistemele de gestiune a bazelor de date dispun de
o serie de componente ce permit efectuarea numeroaselor operaţii. Se pot astfel deduce câteva funcţii cu
caracter de generalitate pentru toate sistemele de gestiune a bazelor de date, şi anume:
• funcţia de descriere a datelor: permite definirea structurii bazei de date cu ajutorul limbajului
de definire; definirea datelor poate fi realizată la nivel logic, conceptual şi fizic; la nivelul acestei
funcţii se descriu multitudinea atributelor (câmpurilor) din cadrul structurii bazei de date,
legăturile dintre entităţile de date sau dintre atributele aceleaşi entităţi, se definesc eventualele
criterii de validare a datelor, metodele de acces la date, aspectele referitoare la asigurarea
integrităţii şi confidenţialităţii datelor, etc; rezultatul acestei funcţii va fi schema bazei de date,
memorate în cod intern;
• funcţia de manipulare a datelor este cea mai complexă funcţie şi realizează următoarele
activităţi:
– crearea (încărcarea) bazei de date;
– adăugarea de noi înregistrări (tupluri);
– suprimarea unor înregistrări;
– modificarea valorilor corespunzătoare unor câmpuri;
– căutarea, sortarea şi editarea parţială şi totală a unei înregistrări virtuale etc.; funcţia de
manipulare a datelor se realizează prin intermediul limbajului de manipulare a datelor;
• funcţia de utilizare asigură mulţimea interfeţelor necesare pentru comunicarea tuturor
utilizatorilor cu baza de date; în cadrul realizării acestei funcţii, apar mai multe categorii de
utilizatori:
– utilizatori conversaţionali: aceştia reprezintă categoria beneficiarilor de informaţii care
utilizează limbajele de interogare a bazei de date într-o formă simplistă;
– utilizatori programatori, care utilizează limbajele de manipulare, realizând proceduri
complexe de exploatare a bazei de date;
– administratorul bazei de date apare ca un utilizator special şi are rolul hotărâtor în ceea
ce priveşte funcţionarea optimă a întregului ansamblu;
• funcţia de administrare a bazei de date apare ca o funcţie complexă şi este de competenţa
administratorului acesteia.
8
entităţii. Putem avea o dependenţă funcţională între identificatorii a două entităţi. O corespondenţă sau
asociere sau relaţie reprezintă o legătură logică între două sau mai multe realizări de entităţii. Rolul unei
entităţi este un nume care desemnează modul de participare al entităţii la o asociere. Identificarea asocierilor
se realizează prin rolurile entităţilor participante deci, concret, cu ajutorul identificatorilor entităţilor
respective. Mulţimea entităţilor care participă la o asociere formează colecţia acesteia, numărul acestora
reprezentând gradul sau dimensiunea asocierii. O corespondenţă între realizări diferite ale aceleeaşi
entităţi se numeşte asociere reflexivă, caz care se recomandă precizarea rolurilor fiecărei entităţi în cadrul
asocierii. O entitate poate participa la mai multe corespondenţe; în acelaşi timp, pot exista mai multe asocieri
între aceleaşi entităţi. Un subansamblu de entităţi ale aceluiaşi tip de entitate formează un subtip al entităţii
respective cu proprietăţi specifice.
În cadrul modelului EA de abstractizare a unui ansamblu de date trebuie să se ţină cont de
următoarele reguli:
• o asociere (relaţie) nu poate exista decât o singură dată între aceleaşi entităţi;
• numele entităţilor, corespondenţele (relaţiilor), rolurilor, atributelor trebuie să fie unice în cadrul
modelului conceptual, iar apoi în baza de date definită.
Atunci când inserăm tupluri într-o relaţie, de multe ori un atribut este necunoscut sau neaplicabil.
Pentru a reprezenta acest atribut a fost introdusă o valoare convenţională în relaţie, şi anume valoarea null.
În ceea ce priveşte un tabel de tip view (vizualizare, filtru, relaţie virtuală) acesta reprezintă o filtrare a
tabelului iniţial necesară unei anumite abordări, unei anumite aplicaţii. Spunem că un tabel de tip view
reprezintă o relaţie virtuală, deoarece datele pe care le conţine nu sunt în realitate memorate, fiind stocată
numai definiţia vizualizării. Utilizarea vizualizărilor este, în anumite situaţii, avantajoasă, asigurând
securitatea tabelului iniţial, care este astfel protejat de ştergeri, modificări, etc., dar prezintă şi limitări în
prelucrarea datelor.
Operatorii modelului relaţional definesc operaţiile care se pot efectua asupra relaţiilor, în scopul
realizării funcţiilor de prelucrare asupra bazei de date. Modelul relaţional oferă două mulţimi de operatori pe
relaţii şi anume: algebra relaţională şi calculul relaţional. Operatorii algebrei relaţionale sunt fie operatori
tradiţionali pe mulţimi (UNION, INTERSECT, PRODUCT, DIFFERENCE), fie operatori relaţionali
speciali (PROJECT, SELECT, JOIN, DIVISION). Calculul relaţional este de două tipuri : orientat pe tupluri
sau orientat pe domenii, reprezentând o adaptare a calculului predicatelor la domeniul bazelor de date. Pe
baza unor predicate iniţiale, prin aplicarea unor operatori ai calculului cu predicate (conjuncţia, disfuncţia,
10
negaţia, cuantificatorul existenţial şi cel universal) se pot defini noi predicate, noi relaţii. Conform
echivalenţei dintre algebra relaţională şi calculul relaţional demonstrate de Ullmann, orice relaţie posibil de
definit în algebra relaţională poate fi definită şi în cadrul calculului relaţional, şi reciproc.
10
Regulile de integritate sunt aserţiuni pe care datele conţinute în baza de date trebuie să le satisfacă.
Trebuie făcută distincţia între regulile structurale care sunt inerente modelării datelor şi regulile de
funcţionare (comportament) care sunt specifice unei aplicaţii particulare. Există trei tipuri de constângeri
structurale (de cheie, de referinţă, de entitate) ce constituie mulţimea minimală de reguli de integritate pe
care trebuie să le respecte un SGBD relaţional şi care sunt definite în raport cu noţiunea de cheie a unei
relaţii. O mulţime minimală de atribute ale căror valori identifică un tuplu unic într-o relaţie reprezintă o
cheie pentru relaţia respectivă. Fiecare relaţie are cel puţin o cheie de identificare. Dacă există mai multe
chei de identificare, atunci acestea se numesc chei candidat. Una dintre cheile candidat va fi aleasă de către
administratorul bazei de date pentru a identifica efectiv tupluri şi ea va primi numele de cheie primară, iar
celelalte chei candidat vor purta numele de chei alternative sau alternate. Modelul relaţional serveşte la
reprezentarea entităţilor din lumea reală şi a asocierilor dintre acestea. Modelarea asocierilor dintre entităţi
impune recurgerea la conceptul de cheie externă. Aceasta reprezintă un atribut/grup de atribute dintr-o
relaţie R1 ale cărui/căror valori sunt definite pe acelaşi domeniu/aceleaşi domenii ca şi cheia primară a unei
alte relaţii R2 şi care are rolul de a modela asocierea dintre entităţile reprezentate prin relaţiile R1 şi R2. În
acest context, R1 este denumită relaţie care referă, iar R2 poartă numele de relaţie referită.
Cu aceste considerente, cele trei reguli de integritate structurală se referă la :
• unicitatea cheii: cheia primară trebuie să fie unică şi minimală;
• integritatea entităţii: atributele cheii primare trebuie să fie diferite de valoarea null;
• integritatea referirii: o cheie externă trebuie ori să fie null în întregime, ori să corespundă la o
valoare a cheii primare asociate.
Pe lângă aceste caracteristici, pentru tabele incluse într-o bază de date se pot efectua şi următoarele
precizări pentru câmpurile din structura lor:
• pentru fiecare câmp se poate stabili un format implicit de afişare a datelor (Display → Format);
• pentru fiecare câmp în parte se poate stabili o machetă pentru introducerea datelor (Display →
Input Mask);
• se poate stabili un titlu nou pentru fiecare câmp; acesta va apare în antetul vizualizării
conţinutului tabelei (Display → Caption);
• o valoare iniţială implicită pentru fiecare câmp; la adăugării unei noi înregistrări, câmpurile
acesteia vor fi iniţializate cu aceste valori implicite (Field Validation → Default value);
• pentru fiecare câmp se poate impune o regulă de validare a valorilor (Field Validation → Rule)
şi eventual un mesaj care să fie afişat pe ecran în cazul nerespectării condiţiei de validare impuse
(Field Validation → Message); regula de validare la nivel de câmp constă dintr-o expresie
logică, ce va fi evaluată la orice modificare a valorii câmpului respectiv; dacă valoarea rezultată
în urma evaluării expresiei de validare este false, atunci noua valoare a câmpului nu va fi
acceptată şi se va afişa un mesaj de eroare standard sau unul specificat de utilizator.
La nivelul tabelei în ansamblu (figura 1.3), pot fi precizate: o regulă de validare la nivel de
înregistrare (la modificarea unei înregistrări) şi, eventual, un mesaj de eroare, în cazul nerespectării acestei
reguli, precum şi secvenţe de cod care să fie executate la inserarea unei noi înregistrări, la actualizarea
(modificarea) sau la ştergerea uneia existente. Validarea la nivel de înregistrare (Record Validation → Rule)
se declanşează după cea la nivel de câmp, dar înaintea secvenţelor de cod asociate evenimentelor de
manipulare a tabelei.
Legarea tabelelor între ele în cadrul modelului relaţional a impus alte două tipuri de indecşi,
cel candidat şi cel cheie:
• indexul candidat în cadrul unei tabele pot exista mai multe câmpuri (sau mai precis mai multe
criterii) care să asigure identificarea unică a înregistrărilor tabelei şi care vor sta la baza definirii
indexilor de acest tip; spre deosebire de indexul unic, cel candidat va împiedeca încărcarea într-o
înregistrare a unor valori care, după evaluarea cheii de indexare, conduc la valori existente în
tabelă;
• indexul de tip cheie primară: se va alege dintre potenţialii indecsi de tip candidat şi va juca un
rol important în legarea tabelelor.
Tipurile de indecşi prezentate (normali, unici, candidaţi şi de tip cheie primară) impun anumite
restricţii de acces, în funcţie de valorile cheii de indexare. Accesul la înregistrările tabelei este din ce în ce
mai restrictiv, în ordinea: indecşi normali, unici, candidat sau de tip cheie primară.
11
Fig. 1.5 Definirea unei relaţii între două tabele
Cu ajutorul câmpurilor A şi B, legătura dintre tabelele T1 şi T2 poate fi unul dintre următoarele trei
tipuri:
• 1:1 (one-to-one): unei valori V din câmpul A îi corespunde o unică valoare din câmpul B;
• 1:n (one-to-many): unei valori V din câmpul A îi corespund mai multe valori din câmpul B;
• n:1 (many-to-one): unei valori V din câmpul B îi corespund mai multe valori din câmpul A;
• m:n (many-to-many): unei valori din câmpul A, ce se regăseşte în mai multe înregistrări ale
tabelei T1, îi corespund mai multe valori din câmpul B.
Dintre acestea, în Visual FoxPro sunt implementate doar primele trei tipuri de relaţii. Lipsesc relaţiile
de tipul m:n, deoarece ele se pot reduce la două relaţii, una de tipul n:1 şi alta de tipul 1:n prin intermediul
unor tabele suplimentare intercalate între primele două.
Un alt criteriu de clasificare a relaţiilor dintre tabele este cel al momentului definirii lor. Din acest
punct de vedere există:
• relaţii temporare sau dinamice, care sunt create prin comenzi introduse în programele de
prelucrare, deci sunt disponibile numai la rularea acestora. În afara programelor de prelucrare,
relaţiile respective nu există;
• relaţii permanante, care sunt create automat de sistem la deschiderea bazei de date care conţine
tabelele legate; aceste relaţii sunt disponibile imediat ce este deschisă baza de date, deoarece
sunt memorate în fişierul bazei de date.
La crearea unei relaţii permanente între două tabele este necesară îndeplinirea unor condiţii
prealabile şi anume:
• tabelul primar trebuie să fie indexat cu un index candidat sau primar;
• tabelul referit poate fi indexat cu orice fel de index, de acesta depinzând însă tipul relaţiei
definite.
Condiţia indexării tabelului primar cu un index candidat sau primar determină stabilirea numai a unor
relaţii permanente de tip 1:1 sau 1:n, deoarece acest tip de index împiedică existenţa, în tabelul primar, a
mai multor înregistrări cu aceeaşi valoare a cheii de indexare. Dacă dorim crearea unei relaţii de tip n:1,
aceasta trebuie văzută dinspre tabelul referit înspre tabelul primar. Desigur că prin aceasta se inversează
rolurile primar – referit între tabele. Dacă dorim neapărat ca tabelul primar să-şi păstreze acest rol pentru o
altă relaţie, se poate crea o vedere (view) din cele două tabele legate, vedere care va deveni noul tabel primar
pentru relaţia respectivă.
În esenţă, legătura între două tabele constă într-un cậmp comun ce există în ambele tabele. În felul
acesta se leagă o înregistrare din primul tabel de (prima) înregistrarea corespunzătoare din tabelul referit,
adică legătura se stabileşte pe baza unor valori egale în cậmpul de legătură.
Fig. 1.6 Definirea relaţiilor permanente
12
Fig. 1.7 Adăugarea unei noi înregistrări în tabela copil a unei relaţii
Ştergerea unei înregistrări din tabelul primar al unei relaţii este de asemenea gestionată prin
intermediul integrităţii referenţiale. În acest caz, avem la dispoziţie următoarele opţiuni:
• ignorare (Ignore) – se permite această ştergere, indiferent dacă în tabelul referit există sau nu
înregistrări legate de înregistrarea primară ştearsă;
• restricţionare (Restrict) – opreşte ştergerea, generând un mesaj de eroare, atunci când există
înregistrări corespunzătoare în tabela referită;
• ştergere în cascadă (Cascade) – se şterg automat toate înregistrările din tabelul referit legate de
înregistrarea primară ştearsă.
Modificarea unor date din tabelul primar, ce afectează relaţia dintre tabele, este de asemenea tratată
prin regulile integrităţii referenţiale în felul următor:
• ignorare (Ignore) – se permit modificările respective, chiar dacă prin aceasta înregistrările
referite corespunzătoare rămân „în aer“, adică fără corespondent în tabelul primar;
• restricţionare (Restrict) – atunci când există înregistrări corespunzătoare în tabela referită,
modificarea este oprită şi este generat un mesaj de eroare;
• modificare în cascadă (Cascade) – sunt modificate automat toate înregistrările din tabelul
referit conform noii valori a cheii relaţiei.
În cadrul bazei de date curent deschise, <bază_de_date> se va crea tabela <tabelă1>. Aceasta va
conţine câmpurile <câmp1>, <câmp2>, ...<câmpn>. Fiecărui câmp i se vor preciza tipul <tip>, lungimea
<lungime> şi dacă este cazul numărul de zecimale <zecimale>.
Pentru ca într-un câmp să poată fi memorată o valoare nulă, se va apela la argumentul NULL din
sintaxa generală a comenzii. Împiedicarea acestui lucru se va face specificând clauza NOT NULL pentru
câmpul respectiv. În absenţa acestor specificări, câmpul se va comporta conform setării curente stabilite prin
comanda SET NULL ON | OFF. Pentru fiecare câmp se poate impune o regulă de validare a valorilor
acestora – CHECK <expl1>. Dacă condiţia <expl1> nu permite existenţa unui câmp necompletat, atunci
adăugarea unei înregistrări vide (de exemplu prin comanda APPEND BLANK) nu va fi posibilă şi va fi
generat un mesaj de eroare. Acest mesaj de eroare poate fi stabilit de către programator prin intermediul
clauzei ERROR <text1> (ERROR <text2>).
De asemenea, pentru fiecare câmp poate fi stabilită o valoare iniţială implicită – DEFAULT <expr2>,
la adăugarea unui noi înregistrări, câmpurile acesteia vor fi iniţializate cu valorile implicite specificate.
Dacă se doreşte definirea unui index de tip cheie primară, atunci se va apela la clauza PRIMARY KEY
în definirea câmpului ale cărui valori vor sta la baza generării indexului. Acesta va avea acelaşi nume ca şi
câmpul.
Se poate defini un index unic pe baza valorilor unui câmp al tabelei (UNIQUE), acesta va face ca
numai prima dintre înregistrările ce conţin aceeaşi valoare a cheii de indexare să fie accesibilă.
Tabela <tabelă1> creată prin comanda CREATE TABLE | DBF poate constitui un tabel referit într-o
relaţie permanentă, al cărei tabel primar se specifică prin <tabelă 2>. Revenind la figura 1.5, câmpul B este
cel căruia i s-a ataşat clauza REFERENCE <tabelă2>, iar câmpul A din tabelul primar, este cel pe baza
valorilor căruia s-a construit indexul <etichetă_index1>. În absenţa clauzei TAG <etichetă_index1> se ia în
considerare indexul de tip cheie primară al tabelului primar <tabelă2>.
Odată cu creerea tabelei <tabelă1> se poate defini şi un index de tip cheie primară al acesteia, ce are
are la bază o combinaţie de câmpuri ale tabelei şi care va asigura identificarea unică a înregistrărilor tabelei.
Cu valorile lui <expr3>, reprezentând combinaţia de câmpuri dorită, se va forma <etichetă_index2>. Clauza
PRIMARY KEY <expr3> TAG <etichetă_index2> nu va putea fi folosită, dacă s-a definit deja un index de
tip cheie primară cu valorile unui câmp (clauza PRIMARY KEY ataşată câmpului respectiv). Reamintim, că
o tabelă poate avea un singur index de tip cheie primară. Clauza UNIQUE <expr4> TAG <etichetă_index3>
crează un index candidat pe baza valorilor lui <expr4>, ce reprezintă un câmp sau o combinaţie de câmpuri
din tabela nou creată. Trebuie menţionat că, câmpul/câmpurile pe baza căruia/cărora s-a construit indexul de
tip cheie primară nu poate/pot apare în <expr4>. De asemenea, o tabelă poate avea mai mulţi indecşi de tip
candidat.
Clauza FOREIGN KEY <expr5> TAG <etichetă_index4> [NODUP] permite definirea unui index
normal (regular) <etichetă_index4>, pe baza valorilor cheii de indexare <expr5>, pentru tabela <tabelă1>,
fiind esenţială în stabilirea unei relaţii de tipul 1:n cu tabela primară <tabelă3>. Dacă se include specificarea
NODUP în clauză, se va creea un index de tip candidat pentru <tabelă1>, ce va constitui tabelul referit din
relaţia stabilită cu tabela primară <tabelă3>. Noua tabelă <tabelă1> poate fi creată şi cu ajutorul unui tablou,
ce conţine numele, tipul, lungimea şi precizia pentru fiecare câmp al tabelei. Conţinutul lui <tablou> va fi
stabilit în prealabil cu ajutorul funcţiei AFIELDS( ).
Considerând situaţia prezentată în figura 1.6, la nivel de comenzi Visual FoxPro, avem următoarele:
Baza de date <conta> conţine tabelele <conturi> şi <operatii>, între care s-a definit o relaţie de
tipul 1:n pe baza valorilor câmpului <simbol> ce apare în ambele tabele. Ambele tabele sunt indexate după
câmpul <simbol>, pentru tabela primară s-a generat o etichetă index de tip cheie primară, iar pentru tabelul
referit s-a creat un index normal (Regular), în conformitate cu tipul relaţiei 1:n.
Odată creată tabela <tabela1>, se poate apela la comenzile COPY STRUCTURE EXTENDED TO şi
CREATE …FROM pentru a crea o nouă tabelă, <tabela2>, cu o structură identică, utilizậnd următoarea
secvenţă de comenzi :
USE <tabela1>
COPY STRUCTURE EXTENDED TO <tabelă_structură>
CREATE <tabela2> FROM <tabelă_structură>
Comanda INDEX ON nu permite definirea unui index de tip cheie primară, foarte important în
problemele ce vizează integritatea referenţială a tabelelor legate între ele prin relaţii. Pe baza valorilor lui
<expr>, care poate reprezenta un câmp sau o combinaţie de câmpuri ale tabelei curent deschise, se poate
genera o <etichetă_index>, în cadrul indexului structural ataşat tabelei (.CDX), de tip unic sau candidat.
Este permisă modificarea tipului oricărui cậmp din structura unei tabele. Dacă cậmpul conţine
valori, se va încerca conversia acestora în conformitate cu noul tip stabilit pentru cậmp. În cazul unei
incompatibilităţi între noul tip şi vechiul tip al cậmpului, informaţia din cậmpul supus modificării de tip se
va pierde. Nu este recomandată modificarea tipului cậmpurilor de tip cheie primară sau candidat.
În ceea ce priveşte lungimea cậmpurilor, acestea pot fi deopotrivă mărite sau micşorate, la
micşorare trebuie avută însă în vedere trunchierea ce operează inevitabil.
8. NULL şi neNULL
Pentru unele atribute poate fi instituită la crearea tabelei obligativitatea valorilor nenule. În timp,
aceasta poate fi modificată într-un sens sau în celălalt.
9. Adăugarea/anularea restricţiilor
Restricţiile de tip cheie primară (PRIMARY KEY), de unicitate (UNIQUE), referenţială (FOREIGN
KEY) şi de comportament (CHECK) pot fi declarate ulterior creării tabelei sau pot fi anulate.
• Stabilirea unei chei primare şi crearea indexului corespunzător
ALTER TABLE <tabelă1>
ADD PRIMARY KEY <expr1> TAG <etichetă_index1>
procedura – frmmain_Activate
open database gest_mat
use stocuri order cod alias stocuri in 1
procedura – cmdInregistrare_Click
mat = val (thisform.cbocod.text)
if thisform.optiongroup1.option1.value = 1
nume_tabela = rtrim(thisform.cbocod.text) + "_Intrari.dbf"
cantitate = "Intrare"
else
nume_tabela = rtrim(thisform.cbocod.text) + "_Iesiri.dbf"
cantitate = "Iesire"
endif
if not file ((nume_tabela))
create table &nume_tabela (cod_mat N(10), data_op D(8) default { / / },;
&cantitate N(10), foreign key cod_mat tag cod_mat references stocuri)
use
select 1
seek mat
if not found( )
append blank
replace cod with mat
endif
endif
select 2
use &nume_tabela alias operatii
append blank
replace cod_mat with mat,;
&cantitate with val (thisform.txtcantitate.value),data_op with date( )
select 1
replace stoc with stoc + operatii.&cantitate
use in 2
procedura – cmdQuit_Click
close tables
close databases
thisform.release
1.5 Validări la nivel de câmp şi la nivel de
înregistrare
Dintr-o bază de date necesară unei contabilităţi informatizate fac parte şi tabelele “plan_ctb” şi
“solduri” – figura 1.10, în prima tabelă fiind memorat planul de conturi, iar în cea de-a doua tabelă soldurile
iniţiale la începutul exerciţiului contabil. Între cele două tabele se defineşte o relaţie de tipul 1 :1 pe baza
simbolurilor conturilor.
Pentru tabela “plan_ctb” se vor defini validări la nivel de cậmp, iar pentru tabela referită “solduri”
validări la nivel de înregistrare. Acestea din urmă sunt impuse de faptul că, un cont de activ poate avea
numai un sold iniţial debitor, iar un cont de pasiv un sold iniţial creditor.
Condiţia de validare la nivel de cậmp este dată de expresia
tip_cont = “Activ” .or. tip_cont = “Pasiv”,
iar regula impusă la nivelul înregistrărilor tabelei “solduri” este următoarea :
plan_ctb.tip_cont = “Activ” .and. sid >= 0 .and. sic = 0 .or.;
plan_ctb.tip_cont = “Pasiv” .and. sic >= 0 .and. sid = 0
În formularea celei de-a doua condiţii s-a apelat la cậmpul “tip_cont” al tabelei “plan_ctb”, acest
lucru fiind posibil datorită relaţiei existente între cele două tabele.
Fig. 1.12 Efectul regulii de validare definite la nivelul înregistrărilor tabelei “solduri”
procedura – cmdcreare_Click
nr1 = val(thisform.text1.text)
nr2 = val(thisform.text2.text)
nr3 = val(thisform.text3.text)
nr4 = val(thisform.text4.text)
for i = 1 to 4
nr_note = "nr"+ltrim (str(i))
nume_tabela = "anul"+ltrim(str(i))
create table &nume_tabela (nr_leg N(10) primary key ;
references date_pers, n1 N(2) check n1>0 and n1<11)
for j = 2 to &nr_note
nume_camp = "n"+ltrim(str(j))
alter table &nume_tabela add column &nume_camp N(2);
check &nume_camp >0 and &nume_camp<11
next j
next i
Pentru a opera cu datele dintr-o tabelă deja creată, ea trebuie mai întâi deschisă. La deschidere,
sistemul îi alocă o zonă de memorie specială, numită zonă de lucru. În această zonă de memorie sunt
memoraţi o serie de parametri ai tabelei, parametri necesari gestiunii tabelei, ca de exemplu numărul
înregistrării curente, numărul total de înregistrări din tabelă etc. Într-o zonă de lucru nu poate fi deschisă
decât o singură tabelă. Lucrul cu două sau mai multe tabele simultan implică folosirea a două sau mai multe
zone de lucru distincte. Visual FoxPro posedă o multitudine de zone de lucru (de ordinul zecilor de mii),
astfel încât, practic, nu există restricţii din acest punct de vedere.
După deschidere, asupra tabelei se pot executa o serie de operaţii de prelucrare dintre care cele mai
importante sunt: adăugarea de noi înregistrări, modificarea unor date din înregistrările existente, ştergerea
unor înregistrări, căutarea anumitor date, ordonarea datelor după diferite criterii etc. Când se termină lucrul
cu o tabelă, aceasta trebuie închisă, eliberându-se astfel zona de lucru respectivă.
O observatie importantă legată de lucrul cu datele din tabele este că operaţiile se efectuează la nivel
de înregistrare. Prin urmare, într-o tabelă nu putem adăuga sau şterge decât o înregistrare completă. Pentru a
ţine evidenţa înregistrării curent prelucrate dintr-o tabelă, sistemul foloseşte o variabilă specială, numită
indicatorul de înregistrări. Această variabilă indică totdeauna înregistrarea asupra căreia va acţiona
următoarea comandă.
Pentru prelucrarea datelor din bazele de date se pot folosi două metode:
• una interactivă, constând din utilizarea diferitelor instrumente ale mediului Visual FoxPro.
Operaţiile de prelucrare sunt realizate prin intermediul interfeţei sistemului, sarcina utilizatorului
constând în alegerea de opţiuni, întrebuinţarea unor ferestre de dialog etc.; metoda este folosită
atunci când operaţiile de prelucrare sunt executate de un cunoscător al mediului şi nu în mod
repetat (caz în care este mai avantajoasă realizarea unui program, a unei forme, care să
automatizeze operaţiile respective);
• una prin cod sau prin intermediul limbajului FoxPro: această metodă constă în folosirea
diferitelor comenzi, fie în diferite programe sau metode ale unor forme, rapoarte etc; realizarea
unui sistem informatic necesită folosirea acestei metode, prin construirea unor forme, rapoarte şi
a altor elemente, în ale căror câmpuri sunt introduse comenzi de prelucrare a datelor din bazele
de date.
Comanda USE deschide tabela <tabelă>, ce face parte din <bază_de_date>, în zona de lucru curentă
sau într-o altă zonă specificată în comandă. Modul de acces la conţinutul tabelei, adică modalitatea în care se
ajunge la înregistrările acesteia, poate fi:
• secvenţial, când pentru obţinerea unei informaţii anumite trebuie să parcurgem toate
înregistrările anterioare;
• direct, când putem stabili unde anume pe suport este înregistrarea vizată şi o utilizăm fără să ne
preocupăm de înregistrările anterioare; acest tip de acces este asigurat de o etichetă index
adecvată ataşată tabelei - <etichetă_index>; prin indexare, ordinea fizică a înregistrărilor din
tabelă nu se modifică, se schimbă însă modul în care utilizatorul are acces la datele acesteia;
“prima” înregistrare a tabelei indexate o constituie cea corespunzătoare celei mai mici
(ASCENDING)/mari (DESCENDING) valori a cheii de indexare, iar “ultima” înregistrare a
fişierului indexat este cea care conţine cea mai mare (ASCENDING)/mică (DESCENDING)
valoare a cheii de indexare.
Pentru tabela nou deschisă, se poate defini un pseudonume <alias>, ce va putea fi folosit în
comenzile de prelucrare a tabelei, în locul numelui acesteia.
Tabela, al cărei început respectiv sfârşit se testează, poate fi cea curentă sau cea specificată prin
numărul zonei de lucru în care a fost deschisă sau prin pseudonumele <alias> al ei. Funcţiile returnează
valoarea logică .T., atunci când indicatorul de înregistrări este poziţionat la începutul, respectiv la sfârşitul
tabelei respective.
Comanda LOCATE parcurge tabela curentă căutând prima înregistrare pentru care <cond1> este
îndeplinită. Dacă comanda are succes, funcţia RECNO ( ) va returna numărul înregistrării localizate, iar
funcţia FOUND ( ) va lua valoarea logică .T. Dacă LOCATE găseşte o înregistrare, se poate folosi comanda
CONTINUE pentru a căuta următoarele înregistrări din tabela curentă care îndeplinesc condiţia <cond1>. La
execuţia comenzii CONTINUE, procesul de căutare continuă de la înregistrarea imediat următoare celei
găsite anterior. Comanda CONTINUE poate fi executată repetat până la detectarea sfârşitului de fişier sau
până la epuizarea domeniului de căutare stabilit prin clauza <domeniu> a comenzii LOCATE sau până la
execuţia unei alte comenzi LOCATE.
Dacă LOCATE nu găseşte nici o înregistrare corespunzătoare, funcţia RECNO ( ) va returna o
valoare egală cu numărul total de înregistrări plus 1 (RECCOUNT ( ) + 1), iar FOUND ( ) valoarea .F. În
mod implicit, comanda LOCATE caută prima înregistrare care îndeplineşte condiţia <cond1> în întreaga
tabelă. Se poate reduce domeniul de căutare (ALL) incluzând clauza <domeniu> în sintaxa comenzii, în una
din următoarele forme: NEXT, RECORD sau REST. Totodată, se poate limita căutarea incluzând clauza
WHILE <cond2> în sintaxa comenzii LOCATE, aceasta având loc atâta timp cât condiţia <cond2> este
adevărată.
SEEK <expr>
[ORDER [TAG] <etichetă_index>
[ASCENDING | DESCENING]]
[IN <zonă_de_lucru>]
Comanda SEEK caută prima înregistrare din tabela curentă sau din cea deschisă în zona de lucru
specificată prin <zonă_de_lucru>, pentru care valoarea cheii de indexare este egală cu <expr>. Căutarea se
poate face pe baza etichetei index curente sau prin intermediul celei specificate prin <etichetă_index>.
Dacă valoarea <expr> nu se regăseşte printre valorile cheii de indexare, dar setarea curentă SET
NEAR are valoarea ON, prin comanda SEEK se va localiza înregistrarea corespunzătoare celei mai
apropiate -mai mari- valori a cheii de indexare de valoarea expresiei <expr>.
Dacă expresia <expr> este alfanumerică şi nu se regăseşte exact printre valorile cheii de indexare, dar
setarea curentă SET EXACT are valoarea OFF, prin comanda SEEK se va localiza înregistrarea pentru care
<expr> constituie un subşir stâng al cheii de indexare.
Numărul înregistrării localizate prin intermediul comenzii SEEK este returnat de funcţia RECNO ( ),
iar funcţia logică FOUND ( ) va lua, în această situaţie, valoarea .T.
5. Implementarea mecanismului de căutare secvenţială şi directă
do form form2
do form form3
LOCATE
CONTINUE
procedura – cmdAfisare_Click( )
open database aplic
use magazin
locate for val(cod) = val(thisform.txtcod.value)
do while found( ) and not eof( )
browse noedit nodelete title "afisare"
continue
enddo
use
close databases
SEEK
Prima apariţie a valorii căutate se localizează cu ajutorul comenzii SEEK – figura 2.3, celelalte
apariţii urmậndu-i acesteia şi putậndu-se identifica cu ajutorul comenzii SKIP.
procedura – cmdAfisare_Click( )
open database aplic
use magazin order codr
seek thisform.cbocod.value
if found( )
do while cod = thisform.cbocod.value and not eof( )
browse
skip
enddo
endif
close databases
Există diferite modalităţi de acces la înregistrările unei tabele în vederea implementării algoritmilor de
prelucrare a datelor conţinute de către acestea.
♦ comanda @ SAY
Comanda permite afişarea pe ecran, începând cu o anumită poziţie şi într-un anumit format, a valorii
expresiei <expr>.
DISPLAY
[[FIELDS] <listă_cậmpuri>]
[<domeniu>] [FOR <cond1>] [WHILE <cond2>]
[OFF]
[TO PRINTER | TO FILE <fişier>]
Comanda permite vizualizarea conţinutului tabelei curente, în mod implicit fiind afişat conţinutul
înregistrării curente în cadrul formei sau ferestrei curent active. Se poate limita afişarea la anumite cậmpuri
prin introducerea clauzei [FIELDS] <listă_cậmpuri> în sintaxa comenzii. Afişarea conţinutul unui cậmp de
tip “memo” este posibilă numai prin includerea numelui acestuia în <listă_cậmpuri>.
Se poate extinde domeniul de afişare prin includerea clauzei <domeniu> în sintaxa comenzii, în una
din variantele: ALL, NEXT, RECORD sau REST.
Totodată, se poate limita afişarea înregistrărilor incluzând clauza WHILE <cond2> în sintaxa
comenzii DISPLAY, aceasta având loc atâta timp cât condiţia <cond2> este adevărată. Clauza FOR
<cond1> limitează afisarea înregistrărilor la acelea care îndeplinesc condiţia <cond1> din cadrul domeniului
luat în considerare.
Prin introducerea clauzei OFF în sintaxa comenzii DISPLAY se omite afişarea numerelor de
înregistrare în faţa înregistrărilor vizualizate. Inregistrarile vizate pot fi tipărite la imprimantă, prin
introducerea clauzei TO PRINTER în sintaxa comenzii sau pot fi memorate într-un fişier separat (clauza TO
FILE).
LIST
[[FIELDS] <listă_cậmpuri>]
[<domeniu>] [FOR <cond1>] [WHILE <cond2>]
[OFF]
[TO PRINTER | TO FILE <fişier>]
Comanda LIST este similară comenzii DISPLAY, în mod implicit fiind însă vizualizat întregul
conţinut al tabelei curente.
Comenzile permit introducerea de la tastatură a unei valorii pentru variabila <var>, textul <expc>
precedând pe ecran poziţia de introducere a acesteia. Particularitatea comenzii ACCEPT constă în faptul că,
prin intermediul ei se pot introduce de la tastatură numai valori alfanumerice.
♦ comanda @ GET şi combinaţia @ SAY … GET
@<lin>,<col>GET<var><câmp> [PICTURE<expc1>]
[FUNCTION <expc2>]
[DEFAULT <expr1>] [MESSAGE <expc3>]
[WHEN <expl2>]
[RANGE [<expr2>][,<expr3>]] [VALID <expl1>]
[FONT <expc4>[,<expn1>]][STYLE <expc5>]
[SIZE <expn2>,<expn3>]
[COLOR <culori>COLOR SCHEME <expn4>]
Comanda permite editarea unei variabile sau a unui câmp al unei tabele fie la coordonatele specificate
prin <lin>,<col>, fie la poziţia următoare de pe ecran care urmează după SAY (atunci când comenzile SAY
şi GET sunt grupate împreună). O comandă @GET (sau grup de comenzi @GET) este urmată de o
comandă READ, care va declanşa citirea cîmpului GET şi atribuirea valorii citite lui <var><câmp>.
Tabela curentă poată fi îmbogăţită cu noi înregistrări, al căror conţinut va fi preluat dintr-un alt fişier
specificat. <listă_cậmpuri> reprezintă cậmpurile ale căror valori vor fi adăugate în tabela curentă.
În mod implicit sunt preluate din <fişier> toate înregistrările şi adăugate la conţinutul tabelei curente.
Se poate limita setul de înregistrări din <fişier> care se vor adăuga la acelea care îndeplinesc o anumită
condiţie <expl1>. Dacă fişierul sursă nu este o tabelă de date (.DBF), atunci trebuie specificat tipul acestuia
în conformitate cu opţiunile oferite de către sintaxa generală a comenzii.
♦ comanda REPLACE
Comanda REPLACE actualizează înregistrările tabelei curente prin înlocuirea datelor din cậmpurile
<cậmp1>, <cậmp2>,… cu valorile expresiilor <expr1>, <expr2>…Prin ataşarea clauzei ADDITIVE
cậmpului <cậmpi> specificat în comanda REPLACE, la conţinutul curent al acestuia se va aduna valoarea
expresiei <expri>.
În mod implicit, sunt afectate cậmpurile înregistrării curente. Se poate extinde domeniul de acţiune al
comenzii prin includerea clauzei <domeniu> în sintaxa comenzii, în una din variantele: ALL, NEXT,
RECORD sau REST.
Înregistrările din <domeniu> afectate de comanda REPLACE pot fi numai acelea pentru care
condiţia <cond1> din clauza FOR este îndeplinită. Totodată, înlocuirea stabilită prin comanda REPLACE
poate avea loc atậta timp cật condiţia <cond2> este adevărată. Deoarece comanda REPLACE actualizează şi
index-urile active, este important ca operaţia de înlocuire să nu fie efectuată asupra cậmpului cheie atunci
cậnd există o clauză <domeniu>, FOR sau WHILE efectivă.
Pot fi actualizate prin REPLACE şi cậmpuri din tabele deschise în alte zone de lucru, dacă pentru
acestea se va utiliza sintaxa <alias>.<cậmpi>.
Modificarea valorilor cậmpurilor unei tabele se poate realiza cu ajutorul comenzii UPDATE – SQL.
Modificările se vor efectua în <tabela1> şi vor afecta cậmpurile <cậmp1>, <cậmp2>, ... ale acesteia
conform setărilor stabilite. Prin includerea clauzei WHERE în sintaxa comenzii, se va limita domeniul
înregistrărilor luate în considerare la acelea care îndeplinesc condiţia <expl1>.
Comanda marchează înregistrări pentru ştergere din tabela curent deschisă. Înregistrările marcate pot
fi recuperate prin comanda RECALL.
Din tabela specificată se vor şterge logic toate înregistrările pentru care condiţia <expl1> este
îndeplinită.
PACK
Comanda PACK se foloseşte pentru ştergerea fizică a înregistrărilor care anterior au fost marcate
logic.
procedura – frminreg_Activate
open database aplic3
use tabel1
opt = "d"
do while upper (opt) = "D"
append blank
@ 2,2 say "Cod client:" get cod_cl picture "9999"
@ 3,2 say "Nume :" get nume function "!xxxxxxxxxxxxxxx"
@ 4,2 say "Prenume:" get prenume function "!xxxxxxxxxx"
@ 5,2 say "Factura:" get fact picture "99999999"
@ 6,2 say "Cantitate:" get cant picture "9999999999"
@ 7,2 say "Pret:" get pret picture "99999999"
@ 8,2 say "Data facturii:" get data_fact
@ 11,2 say "Dorit sa continuati introducerea de date?D/N" get opt
read
replace valoare with cant*pret
enddo
use
close databases
procedura – frmAfisare_Activate
open database aplic3
use tabel1
go top
@ 2,1 say "Numele"
@ 2,17 say "Valoare"
@ 2,33 say "Data facturii"
linie = 3
do while not eof( )
@ linie,1 say nume
@ linie,17 say valoare
@ linie,33 say data_fact
linie = linie+1
skip
enddo
Fig. 2.6 Afişarea cu ajutorul comenzii @SAY use
close databases
(*)
( ** )
Operaţia de ştergere a înregistrărilor este implementată cu ajutorul unui control de tip GRID, prin
intermediul căruia este vizualizat conţinutul tabelei „tabel1”. Înregistrarea ce urmează a fi ştersă se
selectează în cadrul controlului de tip GRID prin poziţionare pe o anumită linie a acestuia, iar operaţiile ce
urmează a fi executate vor fi incluse în corpul procedurii eveniment AfterRowColChange asociate grid-ului.
procedura – frmstergere_Activate
public poz
thisform.cmdstergere.visible = .F.
open database aplicatie
procedura – grid1_AfterRowColChange
poz = recno( )
if deleted( )
thisform.cmdstergere.visible = .F.
cls
else
thisform.cmdstergere.visible = .T. (*)
endif
Controlul de tip GRID afişează toate înregistrările tabelei asociate, cele şterse logic prin comenzi de
tip DELETE fiind marcate corespunzător. Distincţia între o înregistrare efectivă şi una ştearsă logic se poate
face cu ajutorul funcţiei logice DELETED( ).
procedura – cmdstergere_Click ( ** )
go poz
@ 7,60 say "Nume: " + nume
@ 8,60 say "Valoare: " + ltrim(str(valoare))
thisform.command1.visible = .F.
on key label del delete
Pe ecran sunt afişate informaţii extrase din înregistrarea selectată, pentru ştergere urmậnd a se apăsa
tasta <Del>. Conform specificării efectuate prin comanda ON KEY LABEL, comanda DELETE va fi
executată după apăsarea acestei taste.
procedura – cmdintoarcere_Click
close tables
use tabel1
pack
use
close databases
on key
thisform.release
Comanda BROWSE determină apariţia pe ecran, în cadrul formei sau ferestrei curente, a ferestrei
speciale Browse. Aceasta reprezintă principalul instrument pentru realizarea diferitelor operaţii de prelucrare
asupra datelor din tabela curentă. În cadrul ferestrei Browse este afişat conţinutul tabelei, în mod implicit
într-un format tabelar, coloanele reprezentând câmpuri, iar liniile înregistrări), conţinut care poate fi
modificat de utilizator în mod interactiv. Se pot adăuga noi înregistrări sau şterge înregistrări existente, se
poate interveni asupra conţinutului oricărui câmp şi al oricărei înregistrări, se pot căuta diferite date, etc. În
mod implicit sunt afişate toate câmpurile din structura tabelei. Se poate restrânge afişarea la anumite câmpuri
utilizând clauza FIELDS. Printre câmpurile specificate pot să apară şi câmpuri dintr-o tabelă referită,
deschisă într-o altă zonă de lucru. În acest caz se va utiliza sintaxa <pseudonume>.<câmp>.
Formatul de afişare al datelor vizualizate în cadrul ferestrei Browse, poate fi impus prin intermediul
clauzelor FONT şi STYLE. În absenţa acestor clauze, pentru afişarea datelor în cadrul ferestrei Browse se
va utiliza fontul MS Sans Serif, stilul de afişare va fi cel normal, iar caracterele vor fi de dimensiune 8.
În mod implicit sunt afişate toate înregistrările tabelei curente. Se poate restrânge afişarea la anumite
înregistrări care îndeplinesc o anumită condiţie impusă prin intermediul clauzei FOR.
În mod implicit, prin intermediul ferestrei Browse este posibilă modificarea conţinutului oricărui
câmp afişat în fereastră. Dacă se va dori modificarea conţinutului a numai unui singur câmp, atunci se va
specifica acest câmp şi prin clauza FREEZE <câmpi>.
În cazul tabelelor indexate, se poate limita afişarea la acele înregistrări care conţin o anumită valoare a
cheii de indexare <expr2> sau care conţin valori ale acesteia cuprinse în intervalul [<expr2>, <expr3>].
Operarea în cadrul ferestrei Browse poate fi limitată prin introducerea clauzelor NOAPPEND,
NODELETE, NOEDIT sau NOMODIFY.
Fereastra Browse poate fi împărţită în două subferestre (partiţii) de vizualizare, limita dintre cele două
ferestre fiind specificată printr-un număr de coloană – PARTITION <coloană>. Dacă se apelează la clauza
LEDIT/REDIT, atunci partiţia (subfereastra) stânga/dreaptă va corespunde modului EDIT de afişare,
partiţia dreaptă/stângă fiind în modul standard Browse de afişare.
În mod implicit, în bara de titlu a ferestrei Browse apare numele tabelei vizualizate. Se poate impune
un text oarecare prin intermediul clauzei TITLE.
Clauza WIDTH <lungime> impune lăţimea coloanelor de afişare din ferestra Browse, indiferent de
dimensiunea câmpurilor tabelei. În cazul câmpurilor de dimensiuni mai mari decât <lungime>, coloanele
aferente acestora vor fi prevăzute cu bare de difilare pe orizontală.
Comenzile CHANGE şi EDIT prezintă o sintaxă similară lui BROWSE, fereastra de vizualizare a
conţinutului tabelei fiind însă diferită.
CHANGE | EDIT
[FIELDS <câmp1> [, <câmp2> ...]]
[FONT <font> [, <dimensiune>]] [STYLE <stil>]
[<domeniu> [FOR <expr1> ] [WHILE <expr2>]
[FREEZE <câmpi>]
[KEY <expr3 [, <expr4>]]
[NOAPPEND][NODELETE][NOEDIT | NOMODIFY]
[PARTITION <coloană> [LEDIT] [REDIT]]
[WIDTH <lungime>]
Prin clauza <domeniu> se poate stabili mulţimea înregistrărilor din tabela curentă ce vor fi afişate
într-o fereastră de tip Change sau Edit. Clauzele FOR şi WHILE se vor aplica numai înregistrărilor din
<domeniu>. Acesta poate fi ALL, NEXT n, REST sau RECORD n.
Comanda mută conţinutul unui set de variabile sau al unor elemente de tablou în câmpurile
înregistrării curente, fiind opusă comenzii SCATTER.
Operaţiile specificate se vor aplica asupra valorilor unor cậmpuri ale tabelei curent deschise şi/sau
variabile. Prelucrarea se poate limita la înregistrările care aparţin unui anumit <domeniu> şi/sau îndeplinesc
o anumită condiţie <expl1> şi/sau prelucrarea poate avea loc atâta timp cât o anumită condiţie <expl2>
rămâne adevărată. Rezultatul poate fi memorat în variabile sau într-un tablou.
procedura - cmdcreare_Click
create table linie_factura (nr_factura N(8), nr_linie N(2), cod_material N(8),;
pret N(8),cantitate N(8))
use
7
procedura - cmdadaugare_Click
do form frmadaugare
thisform.release
procedura - cmdvizualizare_Click
do form frmvizualizare
thisform.release
Introducerea liniilor unei facturi are loc prin intermediul unei forme distincte, pe care sunt plasate
controale de tip casetă de text. Conţinutul curent al unei casete de text este dat de valoarea proprietăţii Value
a acesteia. Instrucţiunile de iniţializare a formei se vor ataşa procedurii eveniment Activate.
procedura - frmadaugare_Activate
thisform.txtnrfactura.value = ""
thisform.txtcod.value = ""
thisform.txtpret.value = ""
thisform.txtcantitate.value = ""
use linie_factura
procedura cmdrev_Click
use
thisform.release
do form frmoptiuni
Vizualizarea facturii specificate prin nr are loc într-o fereastră Browse. Totodată se va calcula
valoarea totală a facturii şi se va afişa în bara de titlu a acesteia.
procedura frmvizualizare_Activate
set talk off
nr = 0
total = 0
use linie_factura
@2,10 say "NR. FACTURA: " get nr picture '99999999'
read
calculate sum(pret*cantitate) for nr = nr_factura to total
titlu = 'Factura: ' + ltrim(str(nr)) + ' Total: ' + ltrim(str(total))
browse fields nr_linie,cod_material,pret,cantitate nomodify noappend nodelete;
title titlu for nr = nr_factura
use
clear
set talk on
Totodată, într-o fereastră Browse sunt afişate operaţiile de intrare/ieşire pentru materialul ales. Orice
modificare în cadrul ferestrei Browse se va reflecta şi în actualizarea stocului curent după închiderea acestei
ferestre. Fereastra Browse se va deschide în cadrul unei ferestre utilizator definite prin DEFINE WINDOW.
Legarea unui control de un cậmp dintr-o tabelă deschisă este posibilă prin setarea corespunzătoare a
valorii proprietăţii ControlSource (stocuri.cod) a controlului respectiv. În ceea ce priveşte controlul de tip
ComboBox, lista de elemente ataşată acestuia se generează conform specificărilor făcute prin proprietăţile
RowSource Type (6-Fields) şi RowSource (stocuri.cod ) ale controlului.
procedura - frmlocaliz_Load
set talk off
public p
open database magazie
use stocuri order cod alias stocuri in 1
use io order cod alias io in 2
p=0
procedura – frmlocaliz_Activate
if p = 1
wait ""
endif
thisform.txtpret.visible = .F.
thisform.txtstoc.visible = .F.
thisform.lblpret.visible = .F.
thisform.lblstoc.visible = .F.
În fereastra utilizator op se vor afişa toate întrările/ieşirile ale materialului cod_spec. Deoarece, în
fereastra Browse se afişează numai conţinutul cậmpurilor data_op şi cantitate, înregistrările noi adăugate
prin intermediul acestei ferestre au cậmpul cod necompletat. Acesta se va completa ulterior cu valoarea
cod_spec. Apoi se va recalcula, printr-o comanda CALCULATE, stocul curent al acestui material.
procedura – cbocod_Click
p=1
cod_spec = val(thisform.cbocod.text)
define window op from 3,28 to 16,55
select stocuri
seek cod_spec
thisform.txtpret.value = pret
10
thisform.txtstoc.value = stoc
thisform.txtpret.visible = .T.
thisform.txtstoc.visible = .T.
thisform.lblpret.visible = .T.
thisform.lblstoc.visible = .T.
activate window op
select io
browse fields data_op,cantitate for cod = cod_spec
replace cod with cod_spec for cod<1
calculate sum(cantitate) to stoc_curent for cod = cod_spec
frmlocaliz.txtstoc.value = stoc_curent
deactivate window op
procedura – frmlocaliz_Unload
close databases
set talk on
procedura – cmdCreare_Click
create database gest
create table produse (codp N(5) primary key check codp>10000;
error "Codul produsului trebuie sa fie de 5 cifre !",;
denp C(16) not null check substr(denp,1,1)=upper(substr(denp,1,1));
error "Prima litera din denumire este obligatoriu majuscula !",ump C(3))
create table beneficiari (codb N(5) primary key check codb>0;
error "Codul beneficiarului trebuie sa fie mai mare ca zero !",;
denb C(30) not null, str C(20),nr n(3),loc c(20), tel n(7),ctbc c(15))
create table contracte (codp N(5) check codp>10000 ;
error "Codul produsului trebuie sa fie de 5 cifre !",;
codb N(5) check codb>0 error "Codul trebuie sa fie mai mare ca zero !",;
prl N(8,2),cantl N(7),termenl D(8), cl M(4),;
foreign key codp tag codp references produse,;
foreign key codb tag codb references beneficiari)
close tables
close databases
procedura – cmdInreg_Click
thisform.release
do form frminreg
procedura – cmdcb_Click
thisform.release
do form frmcontrbenef
Forma de întegistrare frminreg conţine un grup de butoane de comandă, acţionarea unui buton
activând o formă specifică pentru introducerea datelor. În ceea ce priveşte operaţia de înregistrare a unui nou
contract s-a proiectat forma CONTRACTE (figura 2.10), pentru introducerea produselor şi a clienţilor
apelându-se însă la ajutorul FormWizard-ului – figura 2.11.
procedura - frmContracte_Activate
open database gest
use produse order codp alias pr in 1
use beneficiari order codb alias benef in 2
thisform.txtprl.value = ""
thisform.txtcantl.value = ""
thisform.txttermen.value = { / / }
thisform.edit1.value = ""
procedura – cmdInregistrare_Click
p = val (thisform.combo1.text)
b = val (thisform.combo2.text)
insert into contracte (codp,codb,prl,cantl,termenl,cl);
values p,b,val (thisform.txtprl.value),val (thisform.txtcantl.value),;
thisform.txttermen.value,thisform.edit1.value)
12
thisform.txtprl.value = ""
thisform.txtcantl.value = ""
thisform.txttermen.value = { / / }
thisform.edit1.value = ""
thisform.combo1.value = ""
thisform.combo2.value = ""
procedura – cmdQuit_Click
close tables
close databases
thisform.release
do form frminreg
13
Ne propunem să afisăm într-o fereastră Browse contractele destinate unui anumit beneficiar specificat
cu ajutorul unui control de tip ComboBox legat de cậmpul "codb" al tabelei "Beneficiari". Datorită relaţiilor
definite între cele trei tabele, în fereastra Browse vor fi afişate contractile solicitate.
procedura – frmcontrbenef_Activate
open database gest
use produse order codp alias pr in 1
use beneficiari order codb alias benef in 2
use contracte alias contr in 3
procedura – cmdOk_Click
b = val(thisform.combo1.text)
select 3
browse fields codp, pr.denp, prl, cantl for codb = b title benef.denb
procedura – cmdCauta_Click( )
if isblank (thisform.txtCautare.text)
messagebox("Completati text box-ul ''Cont cautat'' !",48,"Avertizare")
return
endif
cautat = thisform.txtCautare.value
inf = 1
sup = thisform.lstPlan_ctb.listcount
do while inf < sup
val_cautat = (inf+sup)/2
if cautat == thisform.lstPlan_ctb.list (val_cautat)
exit
endif
if cautat > thisform.lstPlan_ctb.list (val_cautat)
inf = val_cautat
else
sup = val_cautat
endif
enddo
if inf = sup
messagebox ("Contul "+cautat+" nu este un cont valid !",48,"Avertizare")
else
thisform.lstPlan_ctb.selected (val_cautat) = .T.
thisform.lstPlan_ctb.topindex = val_cautat
endif
thisform.txtCautare.value = ""
B). În următorul exemplu vom programa conţinutul unui control de tip ListBox cu ajutorul unei
interogări SQL. Proprietatea RowSourceType a unui control de tip listă specifică tipul sursei de date pentru
acesta. Optậndu-se pentru 3-SQL statement, în proprietatea RowSource se poate include comanda
SELECT – SQL pentru generarea listei de informaţii a controlului. Proprietatea RowSource se poate seta şi
prin program, caz în care comanda SELECT se va pune între ghilimele. În secvenţa de iniţializare a formei,
comanda SELECT afişează cậmpurile "nume" + "prenume", "nrbi", "nrpass" şi "idcli" într-un cursor.
procedura – frmClienti_Init
select clients
15
C). Considerậnd baza de date evid – figura 1.13 – creată conform metodologiei prezentate în cadrul
paragrafului 1.6, vom prezenta un algoritm de înregistrare a unei note la o anumită disciplină dintr-un an de
studiu – figura 2.14.
(*)
procedura – frmInreg_Activate
public zona
open database evid
* se populează primul ComboBox cu studentii luaţi în evidenţă
use date_pers order nr_leg in 5
thisform.cbostud.rowsource = "select date_pers.nr_leg from date_pers;
into cursor c"
* zona marcată cu ( * ) nu va apare pe ecran decật după ce s-a selectat un anumit student,
* dar ea se pregăteşte cu informaţiile adecvate apariţiei sale ulterioare; totodată se vor
* deschide, în zone diferite, cele patru fişiere de note;
< se ascunde zona ( * )>
for i = 1 to 4
a = "anul" + ltrim(str(i))
select (i)
use &a
endfor
thisform.optiongroup1.option1.value = 1
select 1
zona = 1
16
nr_campuri = afields(t)-1
for i = 1 to nr_campuri
nota = "n" + ltrim(str(i))
thisform.cbonote.additem((nota),i)
next i
procedura – cmdOkStud_Click( )
nr = val(thisform.cbostud.text)
seek nr in 5
* în cazul specificării unui student nou, acesta va fi luat în evidenţă şi i se va
* insera cậte o înregistrare în cele 4 fişiere de note
if not found(5)
insert into date_pers (nr_leg) values (nr)
for i = 1 to 4
a = "anul" + ltrim(str(i))
insert into &a (nr_leg) values (nr)
next i
endif
< se face vizibilă zona ( * )>
Disciplinele vizualizate de către cel de-al doilea ComboBox depind de anul selectat din cadrul
grupului de butoane de opţiune.
procedura – optiongroup1_Click( )
with thisform
.cbonote.clear
do case
case .optiongroup1.option1.value = 1
select 1
case .optiongroup1.option2.value = 1
select 2
case .optiongroup1.option3.value = 1
select 3
case .optiongroup1.option4.value = 1
select 4
endcase
zona = select(0)
nr_campuri = afields(t)-1
for i = 1 to nr_campuri
nota = "n" + ltrim(str(i))
.cbonote.additem((nota),i)
next i
endwith
În final, înregistrarea unei note efectuậndu-se după cum urmează, în variabila globală "zona"
fiind memorat anul selectat.
procedura - cmdOkNota_Click( )
select (zona)
camp_nota = thisform.combo1.value
replace &camp_nota with val(thisform.text1.value)
procedura – cmdQuit_Click( )
thisform.release
17
close databases
D). În exemplul următor – figura 2.15 este propusă o variantă de parcurgere a unor tabele legate,
fiind definite în acest scop două butoane de comandă speciale. Deplasarea în tabela părinte este
implementată cu ajutorul comenzii SKIP, fiind tratat explicit momentul atingerii sfậrşitului/începutului
fişierului. Controalele de tip TextBox utilizate sunt legate de cậmpurile al căror conţinut trebuie să-l
vizualizeze.
procedura – frmAfis_Activate( )
use salar order marca in 2
use personal order marca in 1
select 1
set relation to marca into 2
procedura – cmdUrmator_Click ( )
if not bof ( )
thisform.cmdPredecesor.Enabled = .T.
endif
if not eof ( )
skip
if eof ( )
skip -1
thisform.cmdUrmator.Enabled = .F.
endif
endif
procedura – cmdPredecesor_Click ( )
if not eof ( )
thisform.cmdUrmator.Enabled = .T.
endif
if not bof ( )
skip -1
if bof ( )
skip
thisform.cmdPredecesor.Enabled = .F.
endif
endif
18
13
19
[<listă_proprietăţi1>]
[ADD OBJECT <nume_obiect> AS <tip_bază2>
[WITH <listă_proprietăţi2>]]...
[PROCEDURE <nume_procedură>
<comenzi>
ENDPROC]...
ENDDEFINE
Obiectele grafice aparţinậnd clasei <nume_clasă> sunt de tipul <tip_bază1> şi sunt înzestrate cu
proprietăţile specificate în <listă_proprietăţi1>. Ele pot conţine o serie de alte obiecte <nume_obiect> de
tipul <tip_bază2> şi avậnd proprietăţile specificate prin <listă_proprietăţi2>. Comportamentul tuturor
acestor obiecte este stabilit cu ajutorul procedurilor (metodelor) incluse în definiţia clasei. În exemplul de
mai jos fişierul de proceduri conţine definiţia unei clase de forme – frmutil, a unui grup de butoane de
opţiune – optutil, precum şi a unei liste - lstutil.
procedure def_clasa
define class frmutil as form
left = 300
top = 150
width = 375
height = 250
caption = 'Forma definita cu DEFINE CLASS'
add object cmdinreg as commandbutton;
with caption = 'Inregistrare',top = 40,left = 130,width = 115,;
height = 25, fontbold = .T.
add object cmdlist as commandbutton;
with caption = 'Listare',top = 80,left = 130,width = 115,height = 25,fontbold = .T.
add object cmdrev as commandbutton;
with caption = 'Revenire',top = 120,left = 130,width = 115,;
height = 25,fontbold = .T.
procedure cmdinreg.click
do form frminreg
endproc
procedure cmdlist.click
do form frmlist
endproc
procedure cmdrev.click
X.release
do form frmprinc
endproc
enddefine
define class optutil as optiongroup
buttoncount = 3
top = 60
left=75
height = 70
width = 110
procedure click
do case
case thisform.Y.value = 1
messagebox("S-a ales prima optiune !")
case thisform.Y.value = 2
20
obiectul X definit ca
instanţă a clasei frmutil
procedura – frmprinc_click
public X
set procedure to fisproc
procedura – cmdcont_click
thisform.release
X = createobject("frmutil")
X.activate
X.cmdinreg.setfocus
procedura – cmdiesire_click
thisform.release
21
X, Y şi Z sunt definite ca variablile globale la nivelul aplicaţiei şi reprezintă obiecte componente ale
claselor definite – figura 2.16. Conform codului procedurii eveniment cmdinreg.click inclus în definiţia
clasei frmutil, acţionarea acestui buton aduce în prim plan forma frminreg. Apariţia ferestrei MessageBox
are loc în conformitate cu cele stabilite în codul procedurii eveniment Click incluse în definiţia clasei
optutil.
procedura – frminreg_Activate
public Y
set procedure to fisproc
thisform.addobject('Y','optutil')
thisform.Y.option1.caption = 'Optiunea I'
thisform.Y.option2.caption = 'Optiunea a II-a'
thisform.Y.option3.caption = 'Optiunea a III-a'
thisform.Y.setall('width',110)
thisform.Y.visible = .T.
procedura – cmdrev_Click
release Y
thisform.release
În procedura eveniment Activate, asociată formei frmlist este inclusă secvenţa de creeare a obiectului
de tip listă Z, iar comportamentul său este descris în procedura eveniment Click specificată în cadrul
definiţiei clasei lstutil – figura 2.18.
procedura – frmlist_Activate
public Z
public tablou(3)
tablou(1) = "Unu"
tablou(2) = "Doi"
tablou(3) = "Trei"
set procedure to fisproc
thisform.addobject('Z','lstutil')
22
thisform.Z.rowsourcetype = 5
thisform.Z.rowsource = 'tablou'
thisform.Z.visible=.T.
procedura – cmdrev_Click
release Z
thisform.release
Pe lângă un bogat sortiment de clase predefinite, Visual FoxPro dispune de facilităţi ce oferă
programatorului posibilitatea creării şi utilizării propriilor clase 14. Acesta va decide dacă va creea sau nu câte
o clasă pentru fiecare formă sau control pe care doreşte să-l utilizeze în cadrul aplicaţiei sale. Acest lucru
poate avea însă consecinţe nedorite în ceea ce priveşte fiabilitatea aplicaţiei, şi anume:
o redundanţă nedorită, dată de clasele ale căror obiective se suprapun într-o
oarecare măsură, dar care trebuie întreţinute separat ;
un grad redus de reutilizare a software-lui, dat de numai cele câteva utilizări ale
unei clase în gradul aplicaţiei şi/sau în cadrul altor aplicaţii.
14
23
INTEROGAREA
3
BAZELOR DE DATE
[ORDER BY [<aliasi>.]<cîmpi>]]
[INTO <destinaţie>]
O interogare de selecţie simplă (joncţiune naturală) se poate obţine cu ajutorul următoarei fraze
SELECT:
2. În cadrul frazelor SELECT pot apare operatorii AND, OR, NOT, IN, IS NULL, BETWEEN şi
LIKE, cu ajutorul acestora fiind posibilă o construcţie mai amănunţită a interogărilor SQL precum şi o
creştere a complexităţii acestora. În SQL, pentru comparare, în afara clasicilor operatori ">", "≥", "<", "≤",
"=", "≠", mai pot fi definiţi şi alţi operatori – BETWEEN, LIKE, IN, IS NULL.
Considerăm cậteva exemple de utilizare a acestor operatori în definirea unor interogări simple ale
bazei de date din figura 3.1.
În ceea ce priveşte operatorul LIKE, acesta se foloseşte pentru a compara un atribut de tip şir de
caractere cu un literal (constantă de tip şir de caractere). Rezultatul evaluării unui predicat ce conţine
operatorul IN este True, dacă valoarea lui <expr1> este egală cu una din valorile <expr2>, <expr3>, ...,
<exprn>:
<expr1> IN (<expr2>, <expr3>, ..., <exprn>)
3. Pe lậngă interogările simple, SQL permite definirea unor cereri de interogare complexe
formulate cu ajutorul clauzelor GROUP BY şi HAVING, putậnd să implementeze şi diferitele tipuri de
joncţiuni JOIN precum şi combinaţiile UNION, INTERSECT, MINUS. Frazele SELECT aferente pot
să conţină şi funcţii predefinite de tip COUNT, SUM, AVG, MAX, MIN – figura 3.2.
Clauza GROUP BY precizează cậmpul sau cậmpurile pe baza cărora se va efectua gruparea
înregistrărilor. Funcţiile <funcţie1>, <funcţie2>,... vor fi recalculate la nivelul fiecărei grupări. Clauza
HAVING permite introducerea unor restricţii care sunt aplicate grupurilor de tupluri, deci nu tuplurilor
"individuale" ca şi clauza WHERE.
Grupurilor definite prin clauza GROUP BY de mai sus li se aplică o restricţie în ceea ce
priveşte data cậnd au fost efectuate operaţiile de intrare/ieşire de material. Un material va fi afişat,
doar dacă toate operaţiile sale de intrare/iesire au avut loc într-un anumit interval precizat (HAVING).
select materiale.cod, materiale.denumire, sum(operatii.cantitate) ;
from materiale,operatii;
where materiale.cod=operatii.cod;
group by operatii.cod ;
having operatii.data_op between {^2001-11-01} and {^2001-11-14}
4. În afara joncţiunii naturale, frazele SQL pot implementa atật echi-joncţiunea cật şi theta-
joncţiunea cu ajutorul clauzei INNER JOIN.
26
5. Cele trei tipuri de joncţiune prezentate (theta, echi, naturală) prezintă ca extensie, joncţiunea
externă. Ideea de bază a joncţiunii externe constă în a include în rezultat şi înregistrări dintr-o tabelă (sau din
ambele tabele), care prezintă valori ale cậmpului de legătură ce nu se regăsesc în cealaltă tabelă. Dacă
celelalte tipuri de joncţiune sunt comutative, în cazul joncţiunii externe trebuie specificat din care tabelă se
extrag liniile fără corespondent în celălalt tabel. De aceea, există joncţiune externă la stậnga şi joncţiune
externă la dreapta. La acestea se adaugă joncţiunea externă totală, care reprezintă reuniunea celor două.
27
Prin joncţiunea externă sunt adăugate în tabela rezultat şi înregistrările din cele două tabele, care nu au
participat la join. Acestea sunt completate cu valori nule pentru cậmpurile tabelei din stậnga join-ului (LEFT
JOIN), respectiv pentru cậmpurile tabelei din dreapta join-ului (RIGHT JOIN).
În exemplul de mai sus este implementată o joncţiune externă la stậnga a tabelelor "materiale" şi
"operatii". În rezultatul de interogării astfel definite, va fi inclus şi ultimul material din tabela părinte, chiar
dacă nu există nici o înregistrare corespunzătoare în tabela fiu.
6. Operatorii asamblişti - reuniune, intersecţie şi diferenţă – prezintă operatori SQL dedicaţi şi pot
opera numai cu tabele unicompatibile.
Pentru exemplificare, considerăm situaţia prezentată în figura 3.4, între tabelele "materiale",
"operaţii_11" şi "operaţii_12" fiind definite două relaţii permanente de tipul 1:n pe baza valorilor cậmpului
cod şi cod_material. Lista (se va memora într-o tabelă distinctă) cu toate operaţiile se poate obţine în felul
următor:
select materiale.cod,materiale.denumire,;
operatii_11.data_op,operatii_11.cantitate;
from materiale left join operatii_11 on materiale.cod = operatii_11.cod_material;
union all ;
select materiale.cod,materiale.denumire,;
operatii_12.data_op,operatii_12.cantitate;
from materiale left join operatii_12 on materiale.cod = operatii_12.cod_material;
into table lista
28
În tabela rezultat cậmpurile "data_op" şi "cantitate" pot avea valori nule. În această situaţie cậmpul
numeric "cantitate" va fi completat cu 0, iar "data_op" cu { }.
update lista;
set cantitate = 0, set data_op = {} where lista.cantitate is null