Inserarea, modificarea şi ştergerea înregistrărilor Inserarea liniilor într-un tabel Sintaxa comenzii de inserare a unei linii într-un tabel este următoarea [Tudor N. L., 2007]: INSERT INTO <nume tabela> [(<camp_1>[, <camp_2>,, <camp_n>])] VALUES (<val_1>[, <val_2>,, <val_n>]) Argumentele folosite sunt: <nume tabela> - numele tabelului la care este adăugată înregistrarea; (<camp_1>[, <camp_2>,, <camp_n>]), respectiv (<val_1>[, <val_2>,, <val_n>]) - se vor introduce valorile: val_1, val_2,, val_n în câmpurile: camp_1, camp_2,, camp_n. Observaţii: - Lista de câmpuri este opţională. Dacă lipseşte, trebuie să existe compatibilitate de tip, număr şi ordine între lista de valori şi lista de câmpuri corespondente din tabel; - Se poate schimba ordinea introducerii valorilor în tabel numai dacă se modifică şi ordinea în lista de câmpuri. - Introducerea datelor în tabele între care există o relatie părinte copil trebuie să se facă respectând restricţiile referenţiale de inserare: nu se pot insera date într-un tabel copil, dacă în tabelul părinte nu există valori corespondente pentru coloana comună. Astfel, în programe, se introduc mai întâi date în tabelul părinte. 1
Exemplu : Fie baza de date FIRMA cu tabelele: DEPART (departamente), ANG (angajaţi), SALGRD (grade salarii). Să se insereze următoarele date în tabele: Tabelul depart.dbf. Nrdepart Numedepart Loc 10 CONTABILITATE Ploiesti 20 PROIECTARE Campina 30 SOFTWARE Bucuresti 40 VANZARI Arad Tabelul ang.dbf. Codang Nume Functie Manager Datan Salariu Comision Nrdepart 7839 Petre PRESEDIN.NULL. 08/01/60 3800.NULL 10 TE 7698 Toma MANAGER 7839 10/28/71 2600 NULL 40 7762 Badea MANAGER 7839 12/25/69 1900 NULL 10 7562 Dinu PROGRA 7762 8/01/60 2100 NULL 30 MATOR 7329 Tache PROIEC 7762 10/22/77 2300 NULL 20 TANT 7446 Florea PROIEC 7698 07/09/62 1960 NULL 40 TANT 7586 Popa VANZATOR 7698 05/12/82 1770 1200 40 Tabelul salgrd.dbf. Grad Salmin Salmax 1 1600.00 1900.00 2 1901.00 2200.00 3 2201.00 2600.00 4 2601.00 3000.00 5 3001.00 4000.00 2
Programul care inserează aceste date în tabelele bazei de date FIRMA este următorul: close all clear open database firma.dbc insert into depart values(10,'contabilitate','ploiesti') insert into depart values(20,'proiectare','campina') insert into depart values(30,'software','bucuresti') insert into depart values(40,'vanzari','arad') select * from depart insert into ang values(7839, 'Petre', 'PRESEDINTE', null, ; {^1960/08/01},3800,null,10) insert into ang values(7698, 'Toma', 'MANAGER', 7839, ; {^1971/10/28}, 2600, null, 40) insert into ang values(7762,'badea','manager', 7839, ; {^1969/12/25}, 1900, null, 10) insert into ang values(7562, 'Dinu', 'PROGRAMATOR', 7762, ; {^1960/08/01}, 2100, null, 30) insert into ang values(7329, 'Tache', 'PROIECTANT', 7762, ; {^1977/10/22}, 2300, null, 20) insert into ang values(7446, 'Florea', 'PROIECTANT', 7698, ; {^1962/07/09}, 1960, null, 40) insert into ang values(7586, 'Popa', 'VANZATOR', 7698,; {^1982/05/12}, 1770, 1200, 40) select * from ang insert into salgrd values(1, 1600, 1900) insert into salgrd values(2, 1901, 2200) insert into salgrd values(3, 2201, 2600) 3
insert into salgrd values(4, 2601, 3000) insert into salgrd values(5, 3001, 4000) select * from salgrd close databases Erori posibile în cazul inserării unei linii într-un tabel Introducerea unei linii într-un tabel copil poate genera erori dacă este încălcată restricţia referenţială de inserare şi nu există valori corespondente în coloana PRIMARY KEY din tabelul părinte. Inserarea de linii părinte se poate efectua întotdeauna [Tudor N. L., 2007]. Exemplu : La execuţia comenzii INSERT INTO ang VALUES(7522, 'Kioko', 'TEHNICIAN', 7698,; {^1982/05/12}, 1770, 1200, 60) este generată eroare (figura 1) deoarece în tabelul depart.dbf nu există departamentul 60: Exemple: Citiţi numărul departamentului, numele departamentului, localitatea şi adăugaţi aceste date la tabelul DEPART : Versiunea SQL - Visual FoxPro: CLOSE ALL @ 10,10 SAY 'nrdepart' @ 10,20 GET a DEFAULT 0 @ 12,10 SAY 'numedepart:' 4
@ 12,20 GET b DEFAULT SPACE (14) @ 14,10 SAY 'loc:' @ 14,20 GET c DEFAULT SPACE (13) read OPEN DATABASE firma EXCLUSIVE USE depart INSERT INTO depart VALUES (a, UPPER(b),; ALLTRIM (PROPER (c))) SELECT * FROM depart CLOSE DATABASES Versiunea clasică de program Visual FoxPro care adaugă linii într-un tabel folosind comenzile append blank şi replace generează eroare datorită restricţiei CHECK (figura 2): Se citeşte de la tastatură în mod repetat o variabilă a (codul unui angajat). Căutaţi persoana cu codul a în tabelul ang.dbf (baza de date FIRMA); dacă nu există, inseraţi în tabelă toate informaţiile despre persoana respectivă (se citesc numele, funcţia, manager, data naşterii, salariul, comisionul şi numărul departamentului unde lucrează). Dacă există, afişaţi salariul. Citirea se opreşte în momentul când introduceţi n ca răspuns la întrebarea Mai 5
introduceţi date?. Să se scrie o funcţie de validare pentru asigurarea respectării restricţiilor referenţiale. CLOSE ALL r='d' DO WHILE UPPER(r)<>'N' CLEAR CLEAR ALL OPEN DATABASE firma.dbc EXCLUSIVE USE ang.dbf @10,10 SAY 'introduceti codul angajatului' @10,40 GET a DEFAULT 0 PICTURE '9999' READ LOCATE FOR a = codang IF FOUND() @12,10 SAY 'angajatul cu acest cod este' @12,40 SAY nume @12,60 SAY 'si are salariul:' @12,75 SAY salariu ELSE @12,10 SAY 'introduceti datele pentru noul angajat:' @13,10 SAY 'nume: ' @13,20 GET b DEFAULT SPACE (12) @14,10 SAY 'functie: ' @14,20 GET c DEFAULT SPACE (16) @15,10 SAY 'manager: ' @15,20 GET d DEFAULT 0 @16,10 SAY 'data nasterii: ' @16,20 GET e DEFAULT {//} @17,10 SAY 'salariul: ' @17,18 GET f DEFAULT 0 PICTURE '99999999' 6
@18,10 SAY 'comision: ' @18,22 GET g DEFAULT 0 @19,10 SAY 'numarul departamentului: ' @19,40 GET h DEFAULT 0 PICTURE REPLICATE('9',2) READ VALID exista_departament(h) clear INSERT INTO ang (codang,nume,functie,manager,; datan,salariu, comision, nrdepart); VALUES (a,proper(alltrim(b)),upper(alltrim(c)),d,e,f,g,h) BROWSE ENDIF @22,10 SAY 'mai introduceti date' @22,30 GET r default space (1) READ CLOSE ALL ENDDO FUNCTION exista_departament && funcţie de validare PARAMETER h OPEN DATABASE firma USE depart sw=.f. SCAN IF nrdepart=h sw=.t. ENDIF ENDSCAN IF NOT sw @20,10 SAY 'Numarul departamentului trebuie sa fie dintre cele' @21,10 SAY ' existente in tabelul DEPART.DBF' ENDIF 7
CLOSE ALL RETURN sw Observaţie: Funcţia exista_departament() asigură respectarea restricţiei referenţiale la inserare, verificănd dacă numărul departamentului citit (parametrul h) există în tabelul depart.dbf. Modificarea înregistrărilor unui tabel Comanda SQL - UPDATE permite modificarea valorilor unor atribute pentru înregistrările selectate în clauza WHERE. Sintaxa comenzii este [Fotache M., 2001]: UPDATE [baza_de_date!]tabel SET coloana_1 = expresie1[, coloana_2 = expresie2...] WHERE exprl1 [AND OR expl2...]] Observaţii: Comanda UPDATE - SQL utilizează blocarea înregistrărilor pentru un tabel deschis în reţea. Se recomandă deschiderea tabelului în mod exclusiv sau blocarea cu funcţia FLOCK( ). Exemple: Pentru baza de date Firma.dbc să se realizeze următoarele actualizări: - Modificaţi în tabela depart.dbf localitatea departamentului 40 în Ploieşti : UPDATE depart SET loc='ploiesti' WHERE nrdepart=40 - Modificaţi în tabela ang.dbf comisionul pentru toţi angajaţii din departamentul 40 la valoarea 1500: UPDATE ang SET comision=1500 WHERE nrdepart=40 - Modificaţi tabelul salgrd.dbf astfel încât salariul maxim de la categoria de salarizare 5 să fie 7000: UPDATE salgrd SET salmax=7000 WHERE grad=5 8
Erori posibile în cazul actualizării valorilor unor atribute Actualizarea valorilor unor atribute dintr-o linie - copil poate genera erori dacă este încălcată restricţia referenţială de actualizare şi nu există valori corespondente în câmpul PRIMARY KEY din tabelul părinte [Popescu I., 2001]. Exemplu : La execuţia comenzii UPDATE ang SET nrdepart=45 WHERE nrdepart=40 este generată eroarea Trigger Failed deoarece în tabelul părinte depart.dbf nu există departamentul 45. Actualizarea valorilor unor atribute dintr-o linie - părinte poate genera erori dacă este încălcată restricţia referenţială de actualizare şi nu mai există valori corespondente în câmpul PRIMARY KEY din tabelul părinte pentru valorile din coloana FOREIGN KEY din tabelul copil. Exemplu : La execuţia comenzii UPDATE depart SET nrdepart=15 WHERE nrdepart=10 este generată eroarea Trigger Failed deoarece în tabelul copil ang.dbf mai există linii cu departamentul 10 care rămân fără corespondent în tabelul părinte depart.dbf. Ştergerea liniilor unui tabel Comanda SQL DELETE marchează pentru ştergere înregistrările selectate în domeniul specificat prin clauza WHERE (ştergere logică). Sintaxa comenzii este : DELETE FROM [baza_de_date!]tabel [WHERE exprl1 [AND OR expl2...] ] 9
Observaţii: - Înregistrările marcate pentru ştergere nu sunt şterse fizic din tabel până la folosirea comenzii PACK (ştergere fizică). - Marcajul pentru ştergere poate fi anulat cu RECALL. - Pentru utilizarea comenzii SQL - DELETE este necesară deschiderea bazei de date în mod exclusiv. Exemple: Pentru baza de date Firma.dbc să se realizeze următoarele ştergeri: - Stergeţi din tabela ang.dbf salariatul cu numele Dinescu: OPEN DATABASE firma.dbc EXCLUSIVE DELETE FROM ang WHERE nume='dinescu' BROWSE FIELDS nume, functie, nrdepart PACK BROWSE FIELDS nume, functie, nrdepart CLOSE ALL - Marcaţi pentru ştergere angajaţii cu salariul <= 2000. Să se afişeze persoanele marcate pentru ştergere şi numărul lor, apoi să se anuleze marcajul. CLOSE DATABASES CLEAR OPEN DATABASE firma exclusive DELETE FROM ang WHERE salariu <= 2000 LIST FIELDS nume, salariu FOR DELETED( ) COUNT FOR DELETED( )=.T. TO n && numără liniile selectate pentru ştergere?'au fost marcate pentru stergere ', n, ' persoane' RECALL ALL && anulează toate marcajele pentru ştergere CLOSE ALL && se închid toate fişierele 10
Erori posibile în cazul ştergerii unei linii dintr-un tabel Ştergerea unei linii - părinte poate genera erori dacă este încălcată restricţia referenţială de ştergere şi mai există valori în câmpul FOREIGN KEY din tabelul copil fără corespondent în coloana PRIMARY KEY din tabelul părinte [Tudor N. L., 2007]. Stergerea de linii copil se poate efectua întotdeauna. Exemplu : La execuţia comenzii delete from depart where nrdepart=10 este generată eroarea Trigger Failed deoarece în tabelul ang.dbf există înregistrări cu departamentul 10 si nu a fost selectată obţiunea de ştergere în cascadă. Observaţie: In cazul prezenţei clauzei ON DELETE CASCADE, odată cu linia din tabelul părinte depart sunt şterse şi liniile corespondente din tabelelul copil ang. Exemplu : Să se scrie o procedură care să realizeze ştergerea în cascadă a unui departament x (x parametru) şi a angajatilor din departamentul x : Procedure ştergere Parameter x Use ang exclusive locate for nrdepart = x if found() delete from ang where nrdepart = x pack endif use depart exclusive && tabelul se deschide exclusiv, pentru ştergere delete from depart where nrdepart = x pack 11
return endproc Procedura se poate apela astfel: DO ştergere WITH 20 Bibliografie 1. Marin Fotache, SQL Dialecte DB2, Oracle, Visual Foxpro, Editura Polirom, 2001 2. Popescu I., Modelarea bazelor de date, Editura Tehnica, 2001 3. Tudor N. L., SISTEME INFORMATICE SI GESTIUNEA BAZELOR DE DATE, Editura Universităţii din Ploieşti, 2007, 144 pag. 12