Invatare Atomica

Structura unei baze de date de farmacie

Tabelul de produse, tabelul de furnizori si tabelul de intrari, construite in Microsoft Access — cum se organizeaza informatia de gestiune fara sa o rescrii de fiecare data

Progres lectie:
0%
🎯

Obiectivul lectiei

Vei intelege cum este structurata o baza de date folosita la farmacie pentru gestiune, construita in Microsoft Access (aplicatia de baze de date din Microsoft Office, aceeasi familie cu Word si Excel folosite in modulele anterioare): de ce informatia este impartita in mai multe tabele legate intre ele (produse, furnizori, intrari), ce este un camp, ce este un tip de date (regula care spune ce fel de informatie poate contine un camp: text, numar, data etc. — o detaliem la atomul 6, dar termenul apare inca de la atomul urmator) si de ce fiecare tabel are nevoie de o cheie primara — un identificator unic care nu se repeta niciodata.

Dupa aceasta lectie vei putea:

  • Sa explici diferenta dintre un tabel, o inregistrare (rand) si un camp (coloana)
  • Sa descrii ce campuri contine tabelul Produse si ce tip de date are fiecare
  • Sa descrii ce campuri contine tabelul Furnizori si de ce unele coduri se stocheaza ca text
  • Sa descrii ce campuri contine tabelul Intrari si cum leaga produsul de furnizorul care l-a livrat
  • Sa explici ce este o cheie primara si sa recunosti un camp potrivit pentru acest rol
  • Sa recunosti tipurile de date de baza (Text, Number, Currency, Date/Time, AutoNumber) si sa le potrivesti cu un camp corect

Incearca singur!

Provocare — inainte sa citesti:

La farmacie tineti evidenta pe hartie, intr-un caiet. Rasfoind caietul gasesti trei randuri scrise in zile diferite, toate pentru acelasi produs: o data cu pretul 12,50 lei, alta data 12,80 lei, a treia oara doar "12" fara sa se stie daca sunt lei intregi sau a fost uitata virgula. Nu se stie care e pretul actual, cine a adus marfa ultima data si cand expira lotul aflat pe raft acum. Scrie mai jos: ce informatii separate ar trebui sa existe intr-o evidenta electronica, in ce "tabele" le-ai imparti si de ce crezi ca ar disparea aceasta confuzie.

💡 Ai nevoie de un indiciu?

Ganditi-va la trei liste separate, dar legate intre ele: o lista cu produsele si pretul lor actual (un singur pret pe produs, nu unul pe fiecare rand din caiet), o lista cu furnizorii si datele lor de contact, si o a treia lista cu fiecare livrare in parte — cand a intrat, de la cine, ce lot si cand expira. Confuzia din caiet apare pentru ca aceeasi informatie (pretul) e scrisa de mai multe ori, in locuri diferite, fara reguli.

Subiectul lectiei de azi arata exact cum se construiesc aceste trei liste (tabele) intr-o baza de date.

1

Tabel, inregistrare, camp — si de ce farmacia foloseste trei tabele legate

O baza de date pastreaza informatia in tabele. Un tabel arata ca un tabel obisnuit, cu randuri si coloane, dar cu reguli fixe:
Fiecare rand se numeste inregistrare — un exemplar complet de date (de exemplu, tot ce stim despre un produs anume).
Fiecare coloana se numeste camp — o singura categorie de informatie, aceeasi pentru toate randurile (de exemplu, coloana Pret contine numai preturi).
De ce nu ajunge un singur tabel urias:

Daca ai pune totul intr-un singur tabel de "intrari marfa", ar trebui sa rescrii denumirea furnizorului si adresa lui la fiecare livrare, si denumirea produsului si pretul de vanzare la fiecare rand. Orice greseala de scriere (o virgula in plus, un pret vechi copiat din greseala) creeaza exact confuzia din caietul de hartie: acelasi produs cu preturi diferite scrise in locuri diferite.

Solutia — trei tabele legate intre ele:

Produse — un singur rand pentru fiecare produs din nomenclator, cu pretul lui actual.
Furnizori — un singur rand pentru fiecare firma de la care se cumpara marfa.
Intrari — un rand pentru fiecare livrare (receptie) — ce produs, de la ce furnizor, in ce lot, cu ce data de expirare.
Tabelul Intrari "citeste" datele produsului si ale furnizorului din celelalte doua tabele, in loc sa le copieze. Detaliem fiecare tabel in atomii urmatori.

2

Tabelul Produse — nomenclatorul farmaciei

Tabelul Produse contine un singur rand pentru fiecare produs pe care farmacia il tine in nomenclator, indiferent cate livrari a avut de-a lungul timpului. Campurile tipice:
Structura tabelului Produse:

cod_produs — cod intern unic (cheia primara), ex: P0001
denumire_produs — denumirea comerciala afisata pe raft si pe bon
forma_farmaceutica — ex: comprimate, sirop, unguent, solutie
unitate_masura — ex: cutie, flacon, tub
pret_amanuntul — pretul de vanzare actual, in lei
stoc_minim — cantitatea sub care produsul trebuie recomandat spre comanda

Exemplu de inregistrare (un rand din tabel):

cod_produs = P0001 · denumire_produs = "Exemplu produs A" · forma_farmaceutica = "comprimate" · unitate_masura = "cutie" · pret_amanuntul = 12,50 · stoc_minim = 20

De retinut

In tabelul Produse exista un singur pret actual pentru fiecare produs — nu unul pentru fiecare livrare. Pretul se actualizeaza pe randul produsului cand se schimba; istoricul livrarilor (cu pretul de achizitie al fiecarui lot) sta in alt tabel, Intrari, pe care il vedem in atomul 4.

3

Tabelul Furnizori — de la cine se cumpara marfa

Tabelul Furnizori contine un singur rand pentru fiecare firma de la care farmacia primeste marfa. Datele de contact se scriu o singura data aici, nu la fiecare livrare.
Structura tabelului Furnizori:

cod_furnizor — cod intern unic (cheia primara), ex: F001
denumire_firma — numele firmei furnizoare
cui — codul unic de inregistrare al firmei (text, nu numar)
adresa — adresa sediului sau a depozitului
telefon — numarul de contact (text, nu numar)
email — adresa de e-mail pentru comenzi

Exemplu de inregistrare:

cod_furnizor = F001 · denumire_firma = "Exemplu Distributie Farma SRL" · cui = "RO12345678" · adresa = "Str. Exemplu nr. 10" · telefon = "0721000000" · email = "comenzi@exemplu-distributie.ro"

⚠ Greseala tipica

Daca alegi tipul de date Number pentru campul telefon, un numar ca 0721000000 este interpretat ca valoare numerica si zero-ul din fata dispare automat (ramane 721000000), iar numarul nu mai este valid. Solutia: telefonul, ca si CUI-ul, se stocheaza ca Text — un cod de contact, nu o valoare cu care faci calcule.

4

Tabelul Intrari — fiecare livrare, cu lot si data de expirare

Tabelul Intrari (receptii) are un rand pentru fiecare livrare — chiar daca acelasi produs, de la acelasi furnizor, intra de mai multe ori pe an, fiecare intrare are randul ei, cu propriul lot si propria data de expirare.
Structura tabelului Intrari:

id_intrare — numar generat automat pentru fiecare intrare (cheia primara)
numar_factura — numarul facturii de la furnizor
data_intrare — data la care marfa a fost receptionata
cod_produs — leaga randul de tabelul Produse (ce produs a intrat)
cod_furnizor — leaga randul de tabelul Furnizori (de la cine a intrat)
lot — seria/lotul de fabricatie a marfii primite
data_expirare — data de expirare a acelui lot
cantitate — cate unitati au intrat
pret_achizitie — pretul platit furnizorului pentru o unitate

Exemplu de calcul complet — de la pretul de achizitie la pretul cu amanuntul:

La o intrare, pret_achizitie = 10,00 lei/bucata (fara TVA). Farmacia aplica intai un adaos comercial (marja de vanzare) de exemplu 25%, apoi TVA de 19% — exact ordinea invatata la lectia C2 (Formule si adaos): intai adaosul, apoi TVA, niciodata invers.
Pasul 1 — pret cu adaos, fara TVA: pret_achizitie × (1 + adaos_comercial ÷ 100) = 10,00 × 1,25 = 12,50 lei
Pasul 2 — pret cu amanuntul, cu TVA: pret_cu_adaos × (1 + TVA ÷ 100) = 12,50 × 1,19 = 14,88 lei
Aceasta valoare de 14,88 lei — nu 12,50 lei, care este doar pretul dupa adaos, inainte de TVA — este cea care se scrie in campul pret_amanuntul din tabelul Produse (atomul 2) — un singur pret actual, actualizat la fiecare schimbare, nu unul separat pentru fiecare intrare.

De retinut

Cod_produs si cod_furnizor din tabelul Intrari sunt aceleasi coduri care apar ca cheie primara in tabelul Produse, respectiv Furnizori. Aceasta este legatura dintre tabele — se numeste cheie externa (foreign key) — si e motivul pentru care nu mai trebuie rescrisa denumirea produsului sau adresa furnizorului la fiecare livrare.

5

Cheia primara — identificatorul care nu se repeta niciodata

Cheia primara (Primary Key) este campul (sau combinatia de campuri) care identifica in mod unic fiecare inregistrare dintr-un tabel. Doua reguli obligatorii: valoarea din acest camp nu se repeta niciodata in tabel si nu poate ramane goala. Datorita ei, tabelele se pot lega intre ele (asa cum am vazut la atomul 4: cod_produs si cod_furnizor).
Cum setezi cheia primara in Microsoft Access:

1. Deschizi tabelul in Design View (clic dreapta pe numele tabelului din panoul din stanga → Design View).
2. Dai clic pe randul cu numele campului pe care il alegi cheie primara (de exemplu cod_produs).
3. Din fila Design a panglicii (ribbon), apesi butonul Primary Key (are o iconita cu o cheita galbena) — sau clic dreapta pe selectorul randului si alegi Primary Key din meniul contextual.
4. Langa numele campului apare simbolul cheitei, semn ca acel camp este acum cheia primara a tabelului.

AutoNumber — o cheie primara generata automat:

Pentru tabelul Intrari, unde nu exista niciun cod natural care sa fie mereu unic, se foloseste tipul de date AutoNumber: Access genereaza singur un numar nou (1, 2, 3, ...) la fiecare inregistrare noua, fara sa fie nevoie sa il scrii tu. Campul id_intrare din atomul 4 este exact acest tip de cheie.

⚠ Greseala tipica

Alegerea campului denumire_produs ca si cheie primara. Problema: doua produse diferite pot avea denumiri scrise identic din greseala (spatiu in plus, litera mare/mica diferita nu se vede cu ochiul liber), sau denumirea comerciala a unui produs se poate schimba in timp — iar o cheie primara nu ar trebui sa se schimbe niciodata. Solutia sigura este un cod intern stabil (cod_produs) sau un AutoNumber.

6

Tipurile de date — fiecare camp isi are tipul lui

In Microsoft Access, fiecare camp dintr-un tabel are un tip de date ales o singura data, la crearea tabelului. Tipul de date controleaza ce se poate scrie in acel camp si ce operatii se pot face cu el (calcule, sortare, cautare).
Tipurile de date de baza si toate campurile din cele trei tabele:

Short Text — text scurt (pana la 255 caractere), folosit si pentru coduri care "arata" a numar dar nu se calculeaza cu ele: denumire_produs, forma_farmaceutica, unitate_masura, cod_produs, denumire_firma, cui, adresa, telefon, email, cod_furnizor, numar_factura, lot
Number — valori numerice cu care se fac calcule: cantitate, stoc_minim
Currency — valori banesti, stocate cu precizie de pana la patru zecimale (afisate implicit cu doua): pret_amanuntul, pret_achizitie
Date/Time — date calendaristice: data_intrare, data_expirare
AutoNumber — numar generat automat, unic: id_intrare
Yes/No — o singura alegere din doua variante, ex: un camp "produs_activ" care arata daca produsul mai este inca in nomenclatorul curent

⚠ Greseala tipica

Daca stochezi pretul ca Short Text, Access sorteaza valorile alfabetic, nu numeric: sirul "12", "2", "9" apare in aceasta ordine (pentru ca cifra "1" vine inaintea lui "2" si a lui "9" alfabetic), desi numeric 2 < 9 < 12. In plus, nu poti face nicio suma sau medie pe un camp text. Solutia: campurile cu care faci calcule sau sortari numerice folosesc mereu Number sau Currency, niciodata Short Text.

7

Recapitulare si conexiuni

O baza de date de farmacie functionala se sprijina pe trei tabele legate prin coduri, fiecare cu campurile lui potrivite, fiecare cu o cheie primara unica.
Harta celor trei tabele:

Produse (cheie primara: cod_produs) — denumire, forma farmaceutica, unitate de masura, pret_amanuntul, stoc_minim
  ↑↓ legat prin cod_produs
Intrari (cheie primara: id_intrare, AutoNumber) — numar_factura, data_intrare, cod_produs, cod_furnizor, lot, data_expirare, cantitate, pret_achizitie
  ↑↓ legat prin cod_furnizor
Furnizori (cheie primara: cod_furnizor) — denumire_firma, cui, adresa, telefon, email

Conexiune cu urmatoarea lectie:

Acum ca stii cum arata cele trei tabele, in lectia urmatoare vei invata cum se completeaza efectiv un formular de receptie cand soseste marfa noua si ce validari se aplica la introducerea datelor, astfel incat sa nu poti salva din greseala un lot fara data de expirare sau o cantitate negativa.

De retinut pentru activitatile practice:

Rand = inregistrare, coloana = camp.
Trei tabele, trei roluri: Produse (nomenclator si pret actual), Furnizori (contacte), Intrari (istoricul livrarilor, cu lot si expirare).
Cheia primara: unica, niciodata goala, niciodata schimbata — nu alege un nume ca cheie primara, alege un cod stabil sau un AutoNumber.
Tipul de date potrivit: Currency pentru preturi, Date/Time pentru date calendaristice, Short Text pentru coduri si nume, chiar daca "arata" a numar (cui, telefon).

Exercitii practice

Exercitiul 1 (Nivel minim) — Camp sau inregistrare?

Ai tabelul Produse din farmacie cu randul: cod_produs = P0007, denumire_produs = "Exemplu produs B", forma_farmaceutica = "sirop", pret_amanuntul = 18,40. Raspunde: (a) acest rand intreg reprezinta o inregistrare sau un camp? (b) valoarea "sirop" apartine unui camp — cum se numeste acel camp? (c) care valoare din acest rand este cheia primara?

Vezi rezolvarea

(a) Randul intreg (cod_produs, denumire_produs, forma_farmaceutica, pret_amanuntul impreuna) este o inregistrare — un exemplar complet de date despre un singur produs.

(b) Valoarea "sirop" apartine campului forma_farmaceutica — coloana care arata sub ce forma se prezinta produsul (comprimate, sirop, unguent, solutie).

(c) Cheia primara este cod_produs = P0007, pentru ca acesta este identificatorul unic al tabelului Produse — nu se repeta la niciun alt rand, spre deosebire de denumire, forma sau pret, care se pot repeta la produse diferite.

Exercitiul 2 (Nivel standard) — Alege tabelul si tipul de date corect

Ai urmatoarele sase informatii pe care trebuie sa le introduci in baza de date a farmaciei: (1) denumirea unui produs nou; (2) numele firmei care a livrat marfa; (3) data la care expira lotul primit azi; (4) cate cutii au intrat la ultima livrare; (5) pretul cu amanuntul al unui produs; (6) codul unic de inregistrare (CUI) al furnizorului. Pentru fiecare informatie, spune: in ce tabel intra (Produse, Furnizori sau Intrari) si ce tip de date i-ai da (Short Text, Number, Currency sau Date/Time).

Vezi rezolvarea
  1. Denumirea unui produs nou — tabelul Produse, campul denumire_produs, tip Short Text.
  2. Numele firmei care a livrat marfa — tabelul Furnizori, campul denumire_firma, tip Short Text.
  3. Data la care expira lotul primit azi — tabelul Intrari, campul data_expirare, tip Date/Time.
  4. Cate cutii au intrat la ultima livrare — tabelul Intrari, campul cantitate, tip Number.
  5. Pretul cu amanuntul al unui produs — tabelul Produse, campul pret_amanuntul, tip Currency.
  6. CUI-ul furnizorului — tabelul Furnizori, campul cui, tip Short Text (nu Number, pentru ca poate incepe cu literele RO si nu se fac calcule aritmetice cu el).

Exercitiul 3 (Nivel performanta) — Proiecteaza si calculeaza

Farmacia primeste o livrare noua: numar_factura FF-2027-118, data_intrare 03.12.2027, produsul cu cod_produs = P0015, de la furnizorul cu cod_furnizor = F003, lot L2027-04, data_expirare 30.11.2028, cantitate 40 cutii, pret_achizitie 8,00 lei/cutie (fara TVA), adaos comercial aplicat de farmacie 30%, TVA 19%. Cerinte: (a) scrie randul complet care s-ar adauga in tabelul Intrari, cu toate cele noua campuri din atomul 4 (pentru id_intrare scrie "generat automat", fiind AutoNumber); (b) calculeaza pretul cu amanuntul rezultat, in doi pasi (intai adaosul, apoi TVA), folosind formula din atomul 4, si arata care camp din tabelul Produse s-ar actualiza cu aceasta valoare; (c) explica de ce tabelul Intrari are nevoie de cod_produs si cod_furnizor si nu de intreaga denumire a produsului si a furnizorului scrisa direct pe rand.

Vezi rezolvarea

Schita de rezolvare (nu produsul gata):

  1. Completeaza pe rand cele 9 campuri din structura Intrari (atomul 4): id_intrare ("generat automat"), numar_factura, data_intrare, cod_produs, cod_furnizor, lot, data_expirare, cantitate, pret_achizitie — fiecare cu valoarea ei exacta din enunt.
  2. Calculul se face in DOUA pasi, in ordinea din atomul 4: intai adaosul — pret_achizitie x (1 + adaos/100); apoi TVA — rezultatul pasului 1 x (1 + TVA/100). Foloseste cifrele din enuntul acestui exercitiu (8,00 lei, 30%, 19%), nu pe cele din exemplul lectiei. Rezultatul final se scrie in campul pret_amanuntul din tabelul Produse — nu ramane in Intrari.
  3. Explica rolul cod_produs si cod_furnizor ca chei externe: leaga randul de Produse si Furnizori dupa cod, ca sa nu se rescrie denumirea si adresa la fiecare livrare si sa nu apara variante diferite ale aceleiasi informatii.

Capcane: inversarea ordinii adaos-TVA; scrierea rezultatului in campul gresit; uitarea ca pret_achizitie e fara TVA.

Criterii: rand complet cu 9 campuri corecte (2p) · calcul in 2 pasi cu formula si rezultat numeric (3p) · identificarea campului pret_amanuntul din Produse (2p) · explicatia corecta a cheilor externe — evitarea duplicarii si inconsistentei (3p).

Ce ai invatat astazi

  • Un tabel are randuri (inregistrari) si coloane (campuri); fiecare camp pastreaza un singur tip de informatie
  • Tabelul Produse: cod_produs, denumire_produs, forma_farmaceutica, unitate_masura, pret_amanuntul, stoc_minim — un singur rand pe produs
  • Tabelul Furnizori: cod_furnizor, denumire_firma, cui, adresa, telefon, email — CUI si telefon se stocheaza ca text, nu ca numar
  • Tabelul Intrari: id_intrare, numar_factura, data_intrare, cod_produs, cod_furnizor, lot, data_expirare, cantitate, pret_achizitie — un rand pe fiecare livrare
  • Cheia primara este unica si nu se schimba niciodata; se seteaza in Access din Design View, butonul Primary Key
  • cod_produs si cod_furnizor din Intrari leaga tabelele intre ele (cheie externa), fara sa duplice datele
  • Tipuri de date: Short Text (nume, coduri), Number (cantitati), Currency (preturi), Date/Time (date), AutoNumber (id generat automat)
  • Calcul de exemplu: pret_amanuntul = pret_achizitie × (1 + adaos_comercial ÷ 100) × (1 + TVA ÷ 100) — 10,00 lei cu adaos 25% devine 12,50 lei fara TVA, apoi cu TVA 19% devine 14,88 lei (pretul cu amanuntul afisat la raft)

Vrei mai mult?

Provocare: Proiecteaza pe hartie un al patrulea tabel, Comenzi, cu care ai retine o comanda trimisa catre un furnizor inainte sa soseasca marfa - deci inainte sa existe vreun rand in Intrari. Scrie campurile lui, cheia lui primara si campul prin care se leaga de Furnizori. Ce camp nu poate lipsi ca sa poti verifica mai tarziu, cand vine marfa, daca a sosit exact ce ai comandat?

De gandit: De ce campul cod_produs din Intrari trebuie sa existe deja, cu exact aceeasi valoare, in tabelul Produse? Ce s-ar strica la interogarile de gestiune daca Access ar accepta orice cod, chiar unul care nu apare in Produse?

Deschidere: Regula de trei tabele legate, in loc de un tabel urias, se numeste normalizare si e folosita identic in orice sistem de gestiune stoc, de la o farmacie mica pana la un lant national: cu cat mai putine copii ale aceleiasi informatii, cu atat mai putine sanse sa apara doua preturi diferite pentru acelasi produs.

Urmatoarea lectie

Continua cu Operatii si incarcare — cum completezi formularul de receptie pentru marfa noua si ce validari asigura ca datele introduse sunt corecte (fara date de expirare lipsa, fara cantitati negative).

Continua →