Atestia

Baze de date şi SQL la atestatul de informatică

CREATE TABLE, INSERT, SELECT cu WHERE, UPDATE şi DELETE — structura în patru paşi a subiectului I de la atestat, cu toate problemele rezolvate.

Subiectul I de la atestat e cel mai previzibil din toată proba. Toate cele 40 de variante din sesiunea Dolj 2026 au exact aceeaşi structură în patru paşi:

Cerinţa Ce se cere Instrucţiunea
a) creează structura tabelului CREATE TABLE
b) introdu înregistrările INSERT INTO
c) afişează ceva filtrat SELECT ... WHERE
d) modifică sau şterge UPDATE / DELETE

Odată ce ştii scheletul, rămâne doar traducerea corectă a cerinţei în condiţii.

a) Traducerea structurii

Enunțul dă tipurile într-o notaţie prescurtată. Traducerea e mecanică:

Notaţia din enunţ Ce înseamnă Tip SQL
(N,5) numeric, 5 cifre INTEGER
(N,6.2) numeric, 6 cifre, 2 zecimale DECIMAL(6,2)
(T,80) text, 80 de caractere VARCHAR(80)
(T,1) un singur caracter CHAR(1)
(D) dată calendaristică DATE
(Y/N) da / nu CHAR(1)
CREATE TABLE Carti (
    Nr_inventar INTEGER,
    Titlu       VARCHAR(80),
    Pret        DECIMAL(6,2),
    Situatia    VARCHAR(40)
);

Când enunțul se contrazice cu datele, datele au dreptate. Unele subiecte declară un câmp ca numeric, dar pun valori text în el. Nu poţi introduce „Light" într-o coloană numerică — declari VARCHAR şi scrii un comentariu.

Ce se stochează ca text, deşi arată ca număr

Regula: dacă nu faci calcule cu el, e text.

b) Inserarea datelor

INSERT INTO Carti VALUES (18211, 'Ghid practic', '1/G33', 4.50, 'In biblioteca');

Patru reguli:

Formatul ISO al datelor nu e o toană: scrise aşa, datele se sortează corect şi se compară cu <, >, BETWEEN ca numerele.

Pentru valori lipsă se scrie NULL, fără apostrofuri. NULL nu e zero şi nu e şir gol — înseamnă „nu se ştie". Orice comparaţie cu NULL e nici adevărată, nici falsă, deci rândul nu trece de WHERE. Ca să-l cauţi explicit, foloseşti IS NULL, niciodată = NULL.

c) Filtrarea cu WHERE

SELECT * FROM Carti WHERE Situatia = 'Imprumutata';

SELECT * ia toate coloanele. Dacă enunțul cere „afişaţi numele şi vechimea", listezi exact acele coloane: SELECT Nume, Vechime.

Traducerea formulărilor

Aici se pierd cele mai multe puncte — nu la sintaxă, ci la citire:

În enunț În SQL
peste 2 / mai mult de 2 > 2
cel puţin 2 / mai mare sau egal >= 2
între 50 şi 100 inclusiv BETWEEN 50 AND 100
intervalul [20, 50] BETWEEN 20 AND 50
diferit de zero <> 0
anterioară datei de 20 < '...-20'

Operatori utili

WHERE Clasa = 11 AND Seria = 'B'              -- ambele conditii
WHERE Nume LIKE 'C%'                          -- incepe cu C
WHERE LOWER(Descriere) LIKE '%poet%'          -- contine cuvantul
WHERE Denumire IN ('Productie', 'Vanzari')    -- una dintre valori
WHERE Data BETWEEN '2016-01-01' AND '2016-12-31'   -- tot anul

= vs LIKE: = pentru valoarea întreagă, LIKE pentru o bucată dintr-un text. % înseamnă „orice şir". LIKE 'A+%' ar prinde şi A++ — atenţie când clasele diferă printr-un singur caracter.

Ordonarea

ORDER BY Pret DESC              -- descrescator (ASC e implicit)
ORDER BY Nume ASC, Prenume ASC  -- al doilea criteriu, la egalitate

Ordinea clauzelor e fixă: SELECTFROMWHEREGROUP BYORDER BY.

Agregare şi grupare

Când enunțul spune „pentru fiecare X", ai nevoie de GROUP BY X.

SELECT Gen, AVG(Durata) AS Durata_medie
FROM Filme
GROUP BY Gen;
Funcţie Ce face
COUNT(*) câte rânduri
COUNT(DISTINCT col) câte valori diferite
SUM(x) suma
AVG(x) media
MIN(x) / MAX(x) extremele

Regula de aur: în SELECT pot apărea doar coloanele după care grupezi şi funcţii de agregare. SELECT Titlu, AVG(Durata) ... GROUP BY Gen n-are sens — într-un gen sunt mai multe titluri.

Funcţiile acceptă orice expresie: SUM(Pret_buc * Nr_buc) calculează întâi pe rând, apoi adună. Nu e acelaşi lucru cu SUM(Pret_buc) * SUM(Nr_buc).

Fără GROUP BY, agregarea se face pe tot tabelul şi întoarce un singur număr.

Când ai nevoie de subinterogare

Enunțul cere Soluţia
doar valoarea extremă SELECT MAX(Pret) FROM t;
rândul care conţine extrema subinterogare
DELETE FROM Stocuri WHERE Pret = (SELECT MAX(Pret) FROM Stocuri);

Motivul: MAX comprimă rândurile şi pierde informaţia despre care rând a produs valoarea. Şi funcţiile de agregare nu se pot folosi direct în WHERE.

d) UPDATE şi DELETE

UPDATE Carti
SET Situatia = 'Pierduta'
WHERE Titlu = 'Coliba unchiului Tom';

DELETE FROM Autori
WHERE LOWER(Descriere) LIKE '%poet%';

WHERE lipsă = toate rândurile modificate sau şterse. Nu apare nicio eroare; pur şi simplu pierzi datele. E cea mai gravă greşeală din toată categoria.

Excepţie: dacă enunțul nu restrânge grupul („măriţi salariul mecanicilor cu 2%"), WHERE chiar nu se pune. Regula corectă e „pune WHERE când enunțul restrânge", nu „pune WHERE întotdeauna".

La SET, mai multe coloane se despart prin virgulă, nu prin AND:

SET Clasa = 11,
    Seria = 'A'

DELETE şterge rânduri întregi — nu se specifică nicio coloană.

Calculul procentual

Partea dreaptă a lui SET poate folosi valoarea curentă a coloanei:

Cerinţa SQL
scade cu 7% SET Pret = Pret * 0.93
creşte cu 5% SET Pret = Pret * 1.05
scade 9 lei (fix) SET Pret = Pret - 9
creşte cu 1 SET Nr = Nr + 1
la jumătate SET Credit = Credit / 2
valoare fixă SET Rating = 3

Scădere cu p% → * (1 - p/100); creştere → * (1 + p/100). Greşeala clasică e * 0.07 în loc de * 0.93 — ar lăsa 7% din preţ.

Când coloana e întreagă, enunțul cere de obicei rotunjire: ROUND(Pret * 1.05).

Capcana împărţirii întregi

Compensare / 100        -- 5 / 100 = 0   (!!)
Compensare / 100.0      -- 5 / 100.0 = 0.05

Între doi întregi, împărţirea e întreagă. Rezultatul e 0, formula pare că nu face nimic, şi nu apare nicio eroare. Scrie mereu 100.0.

Identificarea unui singur rând

La UPDATE şi DELETE, ţinteşte prin cheia unică — cod, număr matricol, CNP — nu prin nume:

WHERE Cod_parafa_medic = 9813      -- sigur
WHERE Prenume = 'Mircea'           -- doi medici se numesc asa

Datele din subiecte sunt construite special cu omonime, ca să prindă exact această greşeală.

Greşeli care se repetă

Unde se scriu

Instrucţiunile de mai sus sunt SQL standard. În Microsoft Access se lipesc în Create → Query Design → SQL View. Câteva echivalenţe:

SQL standard Access
VARCHAR(80) TEXT(80)
'1998-05-12' #05/12/1998#
SUBSTR(x, 1, 2) Mid(x, 1, 2)
CAST(x AS INTEGER) CInt(x)
DATE(d, '+25 days') DateAdd("d", 25, d)
LIMIT 1 SELECT TOP 1

Toate problemele din această categorie

Toate cele 40 de subiecte, cu rezolvări complete în SQL, verificate rulând efectiv instrucţiunile.