Sunteți pe pagina 1din 30

150 Partea l Utilizarea general a sistemului MySQL

[... ] corespunde oricrui caracter plasat ntre paranteze drepte. Putei specifica un meniu de caractere prin
precizarea extremitilor domeniului, separate printr-o liniu (* Pentru a nega sensul clasei (astfel nct s
corespund tuturor caracterelor care nu se afl j list), specificai * ca prim caracter al clasei:
"abc" REGEXP "[a-z]" ^ 1
"abc" REGEXP "[Aa-z]" ^o
* corespunde oricrui numr de elemente la fel cu cel anterior semnului. De exemplu,: corespunde oricrui
numr de caractere x:
"abcdef" REGEXP "a.*f" o 1
"abc" REGEXP "[0-9]*abc' ^1
"abc" REGEXP " [0-9][0-9]*" <* O
Orice numr" nseamn i zero apariii, motiv pentru care a doua expresie este ac vrat.
'mod i mod$ ancoreaz o coresponden cu un model astfel nct modelul mod punde numai atunci cnd survine
la nceputul sau la sfritul unui ir, iar "mod$ cor punde numai dac mod corespunde ntregului ir:
"abc" REGEXP "b" <* 1
"abc" REGEXP "'b" * O
"abc" REGEXP "b$" oO
"abc" REGEXP "Aabc$" o 1
"abcd" REGEXP "Aabc$" * O
Modelul REGEXP poate fi luat din coloana unui tabel, dei aceast operaie va fi mai le dect un model de tip
constant, n cazul n care coloana conine numeroase va diferite. Modelul trebuie examinat i convenit n form
intern de fiecare dat valoarea din coloan se modific.
Stabilirea corespondenelor cu expresiile regulate din MySQL dispune si de alte > tere model speciale. Vezi
Anexa C pentru mai multe informaii.
Precedena operatorilor
Cnd MySQL evalueaz c expresie, examineaz operatorii pentru a determina ordinel care trebuie s grupeze
termenii expresiei. Unii operatori au o preceden mai ridicat,; sunt mai puternici" dect ali1., n sensul c
sunt evaluai naintea altora. De exemjj nmulirea si mprirea au o preceden mai ridicat dect adunarea i
scade Urmtoarele dou expresii sunt echivalente, deoarece * i / sunt evaluate nainte de + $L 3
1+2*3-4/5 * 6.2
1 + 6 - .8 t* 6.2
Precedena operatorilor este prezentat n lista urmtoare, n ordine descresctoare^
Operatorii menionai pe aceeai linie au aceeai preceden. Operatorii cu un nivd
preceden mai ridicat sunt evaluai naintea operatorilor cu un nivel de preceden i
redus.
BINARY
NOT !
- (minus unar)
Capitolul 2 Lucrul cu date n MySQL i SQL 151
/%
&
<<==<=> i= <> >= > IN IS LIKE REGEXP RLIKE
BETWEEN
AND &&
OR II
Putei folosi paranteze pentru a ignora precedena operatorilor i pentru a modifica
ordinea n care sunt evaluai termenii unei expresii:
1+2*3-4/5 * 6.2
(1 + 2) * (3 - 4) / 5 * -0.6
Valorile NULL n expresii
Fii atent cnd folosii valoarea NULL n expresii, deoarece rezultatul s-ar putea s nu fie ntotdeauna cel scontat,
ndrumrile urmtoare v vor ajuta s evitai surprizele.
Dac specificai NULL ca operand pentru orice operator aritmetic sau la nivel de bit, rezultatul este NULL:
1 + NULL <* NULL
1 | NULL O NULL
Dac folosii NULL cu un operator logic, valoarea NULL este considerat fals:
1 AND NULL O O
1 OR NULL O 1
O AND NULL * O
0 OR NULL ^ O
NULL ca operand pentru orice operator de comparaie produce un rezultat NULL, cu
excepia operatorilor <=>, IS NULL i IS NOT NULL, care sunt special concepui pentru manipularea valorilor
NULL:
1 = NULL O NULL NULL = NULL
* NULL 1 <=> NULL O O NULL <=> NULL
* 1
1 IS NULL <* 0
NULL IS NULL * 1
In general, funciile returneaz NULL dac primesc argumente NULL, cu excepia acelor funcii concepute
pentru a manipula argumente NULL. De exemplu, IFNULL() poate manipula argumente NULL i returneaz
adevrat" sau fals" n consecin. STRCMP() presupune argumente non-NULL; dac descoper c i-ai
transferat un argument NULL, returneaz NULL, nu adevrat" sau fals".
In cadrul operaiilor de sortare, valorile NULL se grupeaz la un loc. NULL este plasat, dup sortare, naintea
tuturor valorilor non-NULL (inclusiv irul vid) n cazul unei sortri ascendente, respectiv dup toate aceste valori
la o sortare descendent.
"VC&fV.
m*m-"->-
-'V'"*;.
&w?5
152 Partea l Utilizarea general a sistemului MySQL
Conversia de tip
MySQL execut automat conversii masive de tip, n conformitate cu genul de operaii pe care o efectuai, ori de
cte ori o valoare de un tip este folosit ntr-un context cari necesit o valoare de un alt tip. Conversia de tip se
poate produce din oricare din urm| toarele motive:
Conversia operanzilor la un tip adecvat pentru evaluarea unui operator
Conversia argumentului unei funcii la un tip scontat de funcie
Conversia unei valori pentru repartizarea ntr-o coloan de tabel care este de un alt tj
Expresia urmtoare necesit conversia de tip. Expresia const din operatorul de adur i doi operanzi, 1 i "2":
1 + "2"
Operanzii sunt de tipuri diferite (numr si ir), deci MySQL l convertete pe unul pent a-i aduce la un numitor
comun. Dar care este operandul care trebuie modificat? n: caz, + este un operator numeric, deci MySQL dorete
ca operanzii s fie numere i coi vertete irul " 2" n numrul 2. Apoi, evalueaz expresia pentru a produce
rezultatul 3.^
Iat un alt exemplu. Funcia CONCAT () concateneaz irurile pentru a produce dref rezultat un ir mai lung.
Pentru aceasta, funcia i interpreteaz argumentele sub for de iruri, indiferent de tipul acestora. Dac i
transferai o mulime de numere, CONCAT(| le va converti n iruri, dup care va returna rezultatul concatenrii
acestora:
CONCAT(1,2,3) <* "123"
Dac apelul la funcia CONCAT face parte dintr-o expresie mai mare, vor mai avea loc alte conversii de tip. S
lum urmtoarea expresie i rezultatul ei:
REPEATCX'.CONCATH^.SJ/IO) ^> 'XXXXXXXXXXXX"
CONCAT (1,2,3) produce irul" 123". Expresia " 123" /10 este convertit n 123 /10, deoa mprirea este un
operator aritmetic. Rezultatul aceste expresii va fi 12.3 ntr-un cone cu virgul mobil, dar funcia REPEAT ()
presupune un numr ntreg de repetri, deciv execut o mprire ntreag pentru a se obine rezultatul 12.
Apoi, func REPEAT(' X' ,12) are ca rezultat un ir format din 12 caractere ' X'.
Un principiu general care trebuie reinut este acela c MySQL ncearc s convertea valorile n tipul cerut de o
expresie, n loc de a genera o eroare, n funcie de cont MySQL va converti valorile fiecreia din cele trei
categorii generale (numere, iruri i date si ore) n valori ale oricreia din celelalte categorii. Totui, valorile nu
pot fi n deauna convertite dintr-un tip n altul. Dac o valoare care trebuie convertit ntr-un t dat nu este o
valoare admis pentru tipul respectiv, conversia eueaz. Conversia^ numere a unor obiecte precum " abc" care
nu prezint un aspect numeric are ca re valoarea 0.
Conversia n tipuri dat i or a unor obiecte care au aspectul unor date sau ore rezultat valoarea zero" pentru
tipul respectiv. De exemplu, conversia irului "abc" nj dat are ca rezultat data de tip zero "0000-00-00". Pe de
alt parte, orice valoare poat? tratat sub forma unui ir, deci n general conversia unei valori ntr-un ir nu
constitute problem.

Capitolul 2 Lucrul cu date n MySQL i SQL 153


De asemenea, MySQL execut i conversii minore de tip. Dac folosii o valoare cu virgul mobil ntr-un
context ntreg, valoarea este convertit (cu rotunjire). Conversia n cealalt direcie este de asemenea posibil; un
ntreg poate fi folosit fr probleme ca numr n virgul mobil.
Constantele hexazecimale sunt tratate ca iruri, cu excepia situaiilor cnd contextul indic cu claritate un
numr, n contextele ir, fiecare pereche de cifre hexazecimale este convertit ntr-un caracter i rezultatul este
folosit ca ir. Urmtoarele exemple ilustreaz acest principiu:
0x61 o "a"
0x61 +0 o 97
CONCAT(OX61) O "a"
CONCAT(OX61 +0) O "97"
Acelai principiu de interpretare se aplic si n cazul comparaiilor: o constant hexazecimal este tratat ca ir,
cu excepia cazurilor cnd este comparat cu un numr:
10 = OxOa 01
10 = 0x09 00
"\n" = OxOa 01
"\n" = OxOa + 0 oO
("\n" = OxOa) +0 o1
Unii operatori foreaz conversia operanzilor n tipul ateptat de operator, indiferent de tipul operanzilor.
Operatorii aritmetici sunt un exemplu n acest sens; ei ateapt numere, iar operanzii sunt convertii n
consecin:
3 + 4 07
"3" +4 07
"3" + "4" O7
Nu este suficient ca un ir s conin pur i simplu un numr pe undeva. MySQL nu caut n tot irul, n sperana
c va gsi un numr; caut numai la nceput. Dac un ir nu are nici o parte numeric la nceput, rezultatul
conversiei este 0.
"1973-2-4" +0 O 1973
"12:14:01" +0 o 12
"23-valea" +0 o 23
"-23-valea" +0 o -23
"carbon-14" +0 oo
Reinei c regula de conversie ir-numr din MySQL s-a modificat ncepnd de la versiunea 3.23. Anterior
acelei versiuni, irurile cu aspect numeric au fost convertite n valori ntregi, cu rotunjire. De la versiunea 3.23,
acestea vor fi convertite n valori cu virgul mobil:
"-428.9" +0 O -429 (MySQL < 3.23)
"-428.9" +0 O -428.9 (MySQL 3.23)
Operatorii logici i cu bii sunt chiar mai strici dect operatorii aritmetici. Acetia impun ca operanzii s nu fie
numai numerici, ci ntregi, iar conversia de tip se execut m consecin. Aceasta nseamn c un numr cu
virgul mobil cum este 0,3 nu este considerat adevrat, chiar dac este diferit de zero; aceasta deoarece, atunci
cnd este
an
154 Partea l Utilizarea general a sistemului MySQL
convertit la un ntreg, rezultatul este 0. n expresiile urmtoare, operanzii nu sunt con| siderali adevrai dect
atunci cnd au o valoare cel puin egal cu 1. 0.3 OR .04 OO
1 .3 OR . 04 O 1
0.3 AND .04 00 l
1.3 AND .04 O O
1.3 AND 1.04 01
Acest tip de conversie se produce i n cazul funciei IF(), care presupune ca primv argument s fie un ntreg.
Pentru a testa n mod adecvat valorile cu virgul mobil, c mai bine este s folosii o comparaie explicit. In
caz contrar, valorile mai mici dect vor fi considerate false:
IF(1.3,"non-zero","zero") o "non-zero"
IF(0.3,"non-zero","zero") o "zero"
IF(0.3>0,"non-zero","zero") o "non-zero"
Operatorii de stabilire a corespondenelor cu un model se ateapt s opereze cu Aceasta nseamn c putei
folosi operatorii MySQL de stabilire a corespondenelor i un model folosind numere ca operanzi, deoarece
acetia vor converti numerele n iruri| n ncercarea de a gsi o coresponden!
12345 LIKE "1%" O 1
12345 REGEXP "1.*5" O 1
Operatorii de comparaie a mrimii (<, <=, = i aa mai departe) sunt sensibili la contes cu alte cuvinte, sunt
evaluai n conformitate cu tipul operanzilor lor. Expresia urmi toare compar operanzii prin mijloace numerice,
deoarece ambii operanzi sunt numere
2 < 11 01
Aceast expresie implic o comparaie ntre iruri (lexicografic), deoarece ambii ope ranzi sunt iruri:
"2" < "11" 00
n urmtoarele comparaii, tipurile sunt combinate, deci MySQL le compar sub for de numere. Ca rezultat,
ambele expresii sunt adevrate:
"2" < 11 01
2 < "11" 01
n comparaii, MySQL convertete operanzii conform necesitilor, n conformitate urmtoarele reguli:
n afara celor care implic operatorul <=>, comparaiile care implic NULL au ca rezi tat NULL. (Operatorul
<=> este similar cu =, cu excepia faptului c afirmaia NULL NULL este adevrat.)
Dac ambii operanzi sunt iruri, atunci vor fi comparai lexicografic ca i: Comparaiile ntre iruri sunt
efectuate folosind setul de caractere aflat n vigoare server.
Dac ambii operanzi sunt ntregi, vor fi comparai numeric ca ntregi.
Constantele hexazecimale care nu sunt comparate cu un numr sunt comparate iruri binare.
,,,
Capitolul 2 Lucrul cu date n MySQL i SQL 155
Dac oricare dintre operanzi este o valoare TIMESTAMP sau DATETIME si cellalt este o constant, operanzii
sunt comparai ca valori TIMESTAMP. Acest lucru se face cu scopul de a determina comparaiile s funcioneze
mai bine pentru aplicaiile ODBC.
n caz contrar, operanzii sunt comparai numeric ca valori cu virgul mobil. Reinei c aici este inclus i cazul
comparaiei unui ir cu un numr. irul este convertit la un numr, ceea ce are ca rezultat valoarea O dac irul
nu arat ca un numr. De exemplu, "14.3" este convertit la 14.3, dar "L4.3" este convertit la zero.
Reguli de interpretare a datei i a orei
MySQL convertete liber irurile i numerele n valori de tip dat i or, conform cerinelor contextului unei
expresii, i viceversa. Valorile de tip dat i or sunt convertite n numere ntr-un context numeric; numerele sunt
convertite n date sau ore ntr-un context de tip dat sau or. Aceast conversie la o valoare de tip dat sau or se
produce atunci cnd repartizai o valoare ntr-o coloan de tip dat sau or, respectiv cnd o funcie necesit o
valoare de tip dat sau or. n comparaii, regula general este ca valorile de tip dat i or s fie comparate ca
iruri.
Dac tabelul tabeluljneu conine o coloan DATE denumit data_col, urmtoarele instruciuni sunt echivalente:
INSERT INTO tabeluljneu SET data_col = "1997-04-13"
INSERT INTO tabeluljneu SET data_col = "19970413"
INSERT INTO tabeluljneu SET data_col = 19970413
n exemplele urmtoare, argumentul funciei TO_DAYS() este interpretat ca fiind una i aceeai valoare pentru
toate cele trei expresii:
TO J)AYS("1997-04-10")
TO_DAYS("19970410")
TO J)AYS(19970410)
Testarea i forarea conversiei de tip
Pentru a examina modul de efectuare a conversiei de tip ntr-o expresie, folosii programul mysql pentru a emite
o interogare SELECT care evalueaz expresia: mysql> SELECT 0x41, 0x41 + 0;
0x41 j 0x41 + O
729489 729489 729489
65
Aa cum v putei imagina, am fcut o mulime de lucruri ca acesta n timpul scrierii capitolului de fa!
Testarea evalurii expresiilor este important mai ales pentru instruciunile precum DELETE sau UPDATE care
modific nregistrri, deoarece dorii s fii sigur c modificai numai rndurile scontate. O modalitate de a
verifica o expresie este de a rula o instruciune SELECT preliminar cu aceeai clauz WHERE pe care urmeaz
s o folosii pentru instruciunea DELETE sau UPDATE, pentru a verifica n ce msur clauza selecteaz rn-
durile adecvate. S presupunem c tabelul tabeluljneu are o coloan CHAR denumit char_col, care conine
urmtoarele valori:
156 Partea l Utilizarea general a sistemului MySQL
"abc" "def"
"00"
"ghi"
"jkl"
"00"
"mno"
Dac se dau aceste valori, care este efectul urmtoarei interogri?
DELETE FROM tabeluljneu WHERE char_col = 00 Efectul scontat este probabil tergerea celor dou rnduri
care conin valoarea "(X)' Efectul real este tergerea tuturor rndurilor; o surpriz neplcut. Aceasta se ntmplj
ca o consecin a regulilor de comparaie folosite n MySQL. char_col este o coloan tip ir, dar 00 nu este
inclus ntre ghilimele, deci este tratat ca numr. Conform regulilo de comparaie din MySQL, o comparaie ntre
un ir i un numr este considerat ca | comparaie ntre dou numere. La executarea interogrii DELETE,
fiecare valoare coloana char_col este convertit ntr-un numr si comparat cu 0: "00" se convene la O, dar tot la
O se vor converti si celelalte iruri care nu au aspect numeric. Ca at clauza WHERE este adevrat pentru fiecare
rnd, iar instruciunea DELETE terge tabehi Evident, aceasta este o situaie unde ar fi fost prudent s se testeze
clauza WHERE eu instruciune SELECT naintea execuiei instruciunii DELETE, deoarece aceasta v-ar fi ar^j
tat c expresia selecteaz prea multe rnduri:
mysql> SELECT char_col FROM tabelul_Beu WHERE char_col = 00;
char col
"abc"
"def"
00"
"ghi"
"jkl"
"00"
"mno"
Cnd nu suntei sigur cu privire la modul n care va fi folosit o valoare, putei dori exploatai mecanismul
MySQL de evaluare a expresiilor, pentru a fora conversia la valoare de un anumit tip:
Adugai +0 sau +0.0 la un termen pentru a fora conversia la o valoare numeric:
0x65 <> "e"
0x65 + 0 ^101 ;i:
0x65 + 0.0 <* 101.0 ')
Folosii CONCAT () pentru a transforma o valoare ntr-un ir:
14 * 14
CONCAT(14) * "14"
Utilizai ASCII () pentru a obine valoarea ASCII a unui caracter:
"A" t, "A"
ASCII("A") O 65
Capitolul 2 Lucrul cu date n MySQL i SQL 157
Folosii DATE_ADD() pentru a fora tratarea unui ir sau a unui numr ca dat:
19990101 <* 19990101
DATE_ADD( 19990101, INTERVAL O DAY) * "1999-01-01"
"19990101" <* 19990101
DATE_ADD("19990101", INTERVAL O DAY) * "1999-01-01"
Conversia valorilor din afara domeniului sau a valorilor nepermise
Principiul de baz este: semeni vnt, culegi furtun. Dac nu v verificai datele n prealabil nainte de a le stoca,
s-ar putea s nu v plac rezultatele obinute. Acestea fiind zise, iat cteva principii generale care descriu
modalitile folosite de MySQL pentru manipularea valorilor situate n afara domeniului sau necorespunztoare
din alte motive:
Pentru coloane numerice sau de tip TIME, valorile care se afl n afara domeniului admis sunt tiate" pn la
valoarea celei mai apropiate extremiti a domeniului, iar valoarea rezultant este stocat.
Pentru coloane de tip ir altele dect ENUM sau SET, irurile prea lungi sunt trunchiate, pentru a se ncadra n
lungimea maxim a coloanei. Repartizrile ntr-o coloan ENUM sau SET depind de valorile care sunt
menionate ca permise la declararea coloanei. Dac repartizai ntr-o coloan ENUM o valoare care nu este
menionat ca membru al enumerrii, n locul acesteia este repartizat membrul eroare" (adic irul vid care
corespunde membrului cu valoare zero). Dac repartizai coloanei SET o valoare care conine sub-iruri care nu
sunt menionate ca membri ai setului, irurile respective sunt eliminate i coloana primete o valoare care const
din membrii rmai.
Pentru coloanele de tip dat sau or, valorile incorecte sunt convertite n valorile zero" adecvate pentru tipul
respectiv (vezi tabelul 2.11). Pentru coloanele de tip dat i or altele dect TIME, valorile care se gsesc n afara
domeniului aferent tipului de coloan pot fi convenite la valoarea zero", la NULL sau la o alt valoare. (Cu alte
cuvinte, rezultatele sunt imposibil de anticipat.)
Aceste conversii sunt raportate ca avertismente pentru instruciunile ALTER TABLE, LOAD DATA, UPDATE,
precum i pentru instruciunile INSERT cu mai multe rnduri, n clientul mysql, aceste informaii sunt afiate n
linia de stare care este raportat pentru o interogare. Intr-un limbaj de programare, v putei procura aceste
informaii prin alte mijloace. Dac folosii interfaa API din MySQL pentru C, putei apela funcia mysql_inf o().
Cu ajutorul interfeei API pentru modulul DBI din Perl, putei folosi atributul mysql_inf o () al conexiunii
dumneavoastr cu baza de date. Informaiile furnizate reprezint numrul de avertismente. Pentru a vedea care
au fost rndurile modificate, putei emite o interogare SELECT ... INTO OUTFILE i comparai rezultatul cu
rndurile originale.
CAPITOLUL 3
Sintaxa i utilizarea SQL n MySQL
Pentru a putea ntreine comunicaii cu serverul MySQL este necesar s vorbii" fluer limbajul MySQL. De
exemplu, cnd folosii un program cum este clientul mysql, acest funcioneaz cu precdere ca un mijloc care v
permite s trimitei instruciuni SQ ctre server n vederea executrii acestora. De asemenea, trebuie s
cunoatei limbajv SQL dac dorii s scriei programe care folosesc interfaa MySQL furnizat de limbaj jul
dumneavoastr de programare, deoarece vei continua s comunicai cu server transmindu-i instruciuni SQL.
Capitolul l, Introducere n MySQL i SQL", a prezentat o introducere n stil manual" pentru numeroase dintre
caracteristicile sistemului MySQL. Acest capitol se bazeaz materialul respectiv pentru a intra n detalii privind
numeroase domenii ale sistemului SQI implementate de ctre MySQL. Se discut despre modul de referire la
elementele bazelor i date, inclusiv regulile de denumire i restriciile care se aplic privind sensibilitatea la
diferent! ntre majuscule i minuscule. De asemenea, sunt descrise multe dintre instruciunile SQL i importante,
precum cele pentru crearea i distrugerea bazelor de date, a tabelelor si a inde rilor, instruciunile pentru
regsirea datelor folosind unirile i instruciunile care informaii despre bazele de date si tabelele dumneavoastr.
Expunerea scoate n evideni unele dintre extensiile aduse de MySQL limbajului SQL standard.
Ce exist i ce lipsete n MySQL?
Instruciunile SQL din MySQL pot fi grupate n mai multe categorii largi, aa cum , poate vedea n figura 3.1. n
acest capitol, vom discuta despre instruciunile din prime patru categorii prezentate n aceast figur. Unele
dintre utilitarele MySQL furnizea ceea ce este, n esen, o interfa de tip linie de comand cu anumite
instruciuni SQI De exemplu, mysqlshow este o interfa cu instruciunea SHOW COLUMNS. Acolo unde <
posibil, aceste echivalene sunt descrise si n capitolul de fa.
Dintre instruciunile care nu au fost prezentate aici, numeroase vor fi discutate n capitole. De exemplu,
instruciunile GRANT si REVOKE pentru configurarea privilegiilor < utilizator sunt prezentate n capitolul 11,
Administrarea general a sistemul* MySQL". Sintaxa de invocare a tuturor instruciunilor este prezentat n
Anexa Referin de sintax SQL". De asemenea, trebuie s consultai manualul de referin MySQL pentru
informaii suplimentare, mai ales pentru modificrile efectuate n ve unile mai recente ale limbajului MySQL.
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 159
Irearea, tergerea i selectarea bazelor de date CREATE DATABASE DROP DATABASE USE
Irearea, modificarea i tergerea tabelelor i a indexurilor ALTER TABLE CREATE INDEX CREATE TABLE
DROP INDEX DROP TABLE
Obinerea de informaii despre baze de date, tabele i interogri DESCRIBE EXPLAIN SHOW
Selectarea informaiilor din tabele SELECT
Codificarea informaiilor din tabele DELETE INSERT LOAD DATA OPTIMIZE TABLE REPLACE UPDATE
Instruciuni administrative FLUSH GRANT KILL REVOKE
Alte instruciuni
CREATE FUNCTION
DROP FUNCTION
LOCK TABLES
SET
UNLOCK TABLES

Figura 3.1 Instruciuni SQL acceptate de MySQL.


Seciunea final a capitolului descrie ceea ce nu conine MySQL, n spe caracteristicile care i lipsesc. Acestea
sunt funcionaliti care se gsesc n alte sisteme de baze de date, dar nu n MySQL. Printre aceste caracteristici
se numr subselectri, tranzacii, integritate ref erenial, declanatoare, proceduri stocate i vederi. Aceste
omisiuni nseamn cumva c MySQL nu este un sistem autentic" de baze de date? Unii cred asta, dar ca
160 Partea l Utilizarea general a sistemului MySQL
ii
rspuns m-a limita s observ c lipsa acestor caracteristici n MySQL n-a mpiedicai folosirea sistemului de
ctre numeroi utilizatori. Aceasta probabil deoarece, pent multe aplicaii, lipsa acestor caracteristici nu conteaz,
n alte situaii, exist metode pertl tru compensarea unei faciliti care lipsete. Lipsa tergerilor n cascad, de
exemplu nseamn c trebuie s emitei o interogare suplimentar n aplicaiile dumneavoast atunci cnd tergei
nregistrri dintr-un tabel. Lipsa suportului pentru tranzacii poa s nu conteze prea mult pentru dumneavoastr,
dac vi se pre suficient capacitatea sisJ ternului MySQL de a grupa instruciuni pentru o execuie nentrerupt,
delimitndu-1 prin instruciuni LOCK TABLES si UNLOCK TABLES.
(Adevrata problem n acest caz nu este, de fapt, lipsa tranzaciilor; este lipsa une reveniri automate pentru
anularea tuturor instruciunilor, dac vreuna din ele esueaz Dac avei aplicaii cu necesiti precum aceea de
efectuare a unor tranzacii financia complexe, care implic numeroase instruciuni cu interblocare care trebuie
executate grup sau deloc, atunci v putei orienta spre un sistem de baze de date cu faciliti di nregistrare,
respectiv anulare a nregistrrii, precum Postgres.) Unele caracteristid lipsesc pur si simplu deoarece nu au fost
nc implementate. De exemplu, subseleciili nu sunt prezente n MySQL n timpul scrierii acestei cri, dar sunt
planificate a incluse n versiunea 3.24, care este posibil s fi aprut deja n momentul n care dunifj neavoastr
citii rndurile de fa.
Reguli de denumire n MySQL
Aproape fiecare instruciune SQL se refer, ntr-un fel sau altul, la o baz de date sau i elementele sale
constitutive. Aceast seciune descrie regulile sintactice pentru referir la bazele de date, la tabele, la coloane,
indexuri i aliasuri. Numele in cont de consic rente privind sensibilitatea la diferena ntre majuscule si
minuscule, care sunt de asem^ nea descrise.
Referirea la elementele din bazele de date
Cnd folosii nume pentru a v referi la elemente ale bazelor de date, suntei limitat i numrul de caractere pe
care le putei folosi si la lungimea pe care o pot avea nume Forma numelor depinde i de contextul n care le
folosii: .,,
Caractere permise n nume. Numele pot fi constituite din orice caractere alfarw merice din setul de caractere
folosit de server, plus caracterele _ i $. Numele ncepe cu orice caracter care este permis ntr-un nume, inclusiv
o cifr. Totui, nume nu poate fi compus numai din cifre, deoarece astfel s-ar confunda, practic, cu u; numr.
Posibilitatea furnizat de MySQL de a ncepe un nume cu un numr neobinuit. Dac folosii un asemenea
nume, fii foarte atent la numele care conin i e sau un E, deoarece aceste caractere pot duce la expresii ambigui.
23e + 14 nsea coloana 23e plus 14, dar ce ne facem cu 23e+14? nseamn acelai lucru sau estei| numr scris
folosind notaia tiinific?
Lungimea numelui. Numele bazelor de date, ale tabelelor, coloanelor si indexur pot avea maximum 64 de
caractere lungime. Numele aliasurilor pot avea maximu 256 de caractere lungime.
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 161
Calificatori de nume. Pentru a v referi la o baz de date, pur i simplu specificai numele acesteia:
USE nume_baza_de_date
SHOW TABLES FROM nume_baza_de_date
Pentru a face referire la un tabel, avei dou opiuni. Un nume de tabel complet determinat const din numele
bazei de date si numele tabelului:
SHOW TABLES FROM nume__baza__de_date.nums_tabel
SELECT * FROM nume_baza_de_date.nume_tabel
Un nume de tabel singur face referire la un tabel din baza de date curent (prestabilit). Dac samp_db este baza
de date prestabilit, urmtoarele instruciuni sunt echivalente:
SELECT * FROM membru
SELECT * FROM samp_db.membru
Pentru a face referire la o coloan, exist trei opiuni: nume complet determinat, nume parial determinat i nume
nedeterminat. Un nume complet determinat (scris sub forma nume_baza_de_date.nume_tabel. nume_coloana)
este complet precizat. Un nume parial determinat (scris sub forma nume_tabel. nume_coloana) se refer la o
coloan din tabelul desemnat. Un nume nedeterminat (scris sub forma simpl nume_coloana) se refer la tabelul
indicat de contextul nconjurtor. Urmtoarele dou interogri fac referire la aceleai nume de coloan, dar
contextul furnizat de clauzele FROM indic tabelele din care se vor selecta coloanele:
SELECT nume, prenume FROM preedinte
SELECT nume, prenume FROM membri
De regul, precizarea unor nume complet determinate nu este necesar, dei este ntotdeauna permis dac dorii
acest lucru. Dac selectai o baz de date cu o instruciune USE, baza de date respectiv devine baz de date
prestabilit i este implicit n fiecare referin nedeterminat la un tabel. Dac folosii o instruciune SELECT
care face referire la un singur tabel, tabelul respectiv este implicit pentru fiecare referire la coloan din
instruciune. Este necesar s precizai numele numai atunci cnd un.tabel sau o baz de date nu pot fi determinate
din context. Iat cteva situaii n care poate aprea echivocul:
Interogri care fac referire la tabele din mai multe baze de date. Orice tabel care nu se gsete n baza de date
prestabilit trebuie desemnat folosind forma nume_ba-za_de_date.nume_tabel, pentru a permite sistemului
MySQL s identifice baza de date n care trebuie s caute pentru a gsi tabelul.
Interogri care selecteaz o coloan din mai multe tabele, unde mai multe tabele conin o coloan cu numele
respectiv.
Sensibilitatea instruciunilor SQL la diferena ntre majuscule i minuscule
Sensibilitatea instruciunilor SQL la diferena ntre majuscule i minuscule variaz pentru diferitele componente
ale unei instruciuni; de asemenea, mai poate depinde de entitatea la care facei referire si la sistemul de operare
pe care ruleaz serverul:
a-.
162 Partea l Utilizarea general a sistemului MySQL
Cuvinte cheie i nume de funcii SQL. Cuvintele cheie i numele de funcii nu sur sensibile la diferena ntre
majuscule i minuscule. Ele pot fi scrise folosindu-se oric< mrime de liter. Urmtoarele instruciuni sunt
echivalente:
SELECT NOW() select now() sElEcT nOw()
Numele bazelor de date i ale tabelelor. Bazele de date si tabelele din MySQL cores-j pund cataloagelor i
fiierelor din sistemul de fiiere de baz al gazdei serverului, consecin, sensibilitatea numelor bazelor de date i
a numelor tabelelor la diferent^ ntre majuscule i minuscule depinde de modul de tratare a numelor fiierelor de
cat sistemul de operare al gazdei respective. Un server care ruleaz sub UNIX tratea numele bazelor de date si
ale tabelelor ca sensibile la diferena ntre majuscule minuscule, deoarece numele de fiiere UNIX prezint
aceast sensibilitate. Numele < fiiere Windows nu sunt sensibile la diferena ntre majuscule i minuscule, deci
server care ruleaz sub Windows nu trateaz numele bazelor de date i ale tabelelor< fiind sensibile la diferena
ntre majuscule i minuscule.
Trebuie s fii la curent cu aceast caracteristic dac creai o baz de date pe un serv<f| UNIX si pe care ntr-o zi
s-ar putea s o mutai pe un server Windows: dac creai dou tabele denumite abc si ABC, acestea vor fi
imposibil de difereniat pe un calc Windows. O modalitate de a evita transformarea acestui aspect ntr-o
problem este dej selecta o anumit dimensiune a literelor (minuscule, de exemplu) i s creai ntotdeaur nume
de baze de date i de tabele folosind acea dimensiune de liter. Apoi, mrime^ literei numelor nu va mai fi o
problem daca mutai baza de date pe un alt server.
Nume de coloane i de indexuri. Numele coloanelor i ale indexurilor n MySQL i sunt sensibile la diferena
ntre majuscule i minuscule. Urmtoarele interogri si echivalente:
SELECT nume FROM elev SELECT NUME FROM elev SELECT NuMe FROM elev
Numele aliasurilor. Aliasurile sunt sensibile la diferena ntre majuscule i minusc Putei specifica un alias
folosind orice dimensiune de liter (majuscule, minuscule i combinate), dar trebuie ca toate referirile la alias din
interogare s foloseasc ace mrime de liter.
Indiferent dac un nume de baz de date, tabel sau alias este sau nu sensibil la difere ntre majuscule si
minuscule, trebuie s facei referire la un nume dat al oricreia dinj| aceste categorii folosind aceeai dimensiune
a literei pe parcursul ntregii intere Acest lucru nu este valabil pentru cuvintele cheie SQL, pentru numele de
funcii,l numele coloanelor i al indexurilor, la care se poate face referire cu dimensiuni de lite variabile pe
parcursul unei interogri. Natural, interogarea va fi mai lizibil dac folc o aceeai mrime de liter n loc de
stilul scrisoare anonim" (SeLeCt NuMe FrOm
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 163
Crearea, tergerea i selectarea bazelor de date
MySQL furnizeaz trei instruciuni la nivelul bazelof de date: CREATE DATABASE pentru crearea bazelor de
date, DROP DATABASE pentru eliminarea lor, respectiv USE pentru selectarea unei baze de date prestabilite.
Instruciunea CREATE DATABASE
Crearea unei baze de date este o operaie simpl; pur i simplu denumii baza de date ntr-o instruciune
CREATE DATABASE:
CREATE DATABASE nume_baza_de_date
Restriciile sunt acelea c numele trebuie s fie permis, baza de date trebuie s nu existe deja, iar dumneavoastr
trebuie s avei suficiente privilegii pentru a o crea.
Instruciunea DROP DATABASE
tergerea unei baze de date este la fel de simpl ca i crearea acesteia, presupunnd c avei suficiente privilegii:
DROP DATABASE nume_baza_de_date
Totui, instruciunea DROP DATABASE nu este ceva ce trebuie folosit cu un sentiment de genul Dup mine,
potopul!". Instruciunea elimin baza de date i toate tabelele din interiorul acesteia. Dup ce ai ters o baz de
date, s-a terminat cu ea. Cu alte cuvinte, nu ncercai aceast instruciune numai pentru a vedea cum
funcioneaz. Dac administratorul dumneavoastr a efectuat sistematic copii de siguran ale bazei de date, v
vei putea recupera baza de date. Dar v pot garanta c nici un administrator nu va manifesta nelegere cnd i
vei spune: A, pi m jucam cu DROP DATABASE ca s vd ce se-ntmpl, i, ... mi putei restaura si mie
baza de date?"
Reinei c o baz de date este reprezentat printr-un catalog aflat sub catalogul de date. Dac ai inserat n acel
catalog fiiere care nu reprezint tabele, acele fiiere nu vor fi terse de instruciunea DROP DATABASE, n acel
caz, nici catalogul bazei de date nu este eliminat.
Instruciunea USE
Instruciunea USE selecteaz o baz de date pentru a o transforma n baz de date curent (prestabilit) pentru o
conexiune dat cu serverul:
USE nume_baza_de_date
Trebuie s avei unele privilegii de acces la baza de date; altfel, nu o putei selecta. De rapt, nu este necesar s
selectai o baz de date pentru a folosi tabelele acesteia, deoarece putei face referire la tabelele sale folosind
forma nume_baza_de_date.nume_tabel. Totui, este mult mai convenabil s facei referire la tabele fr a fi
necesar s specificai un calificator pentru baza de date.
Selectarea unei baze de date prestabilite nu nseamn c aceasta trebuie s fie baza de date prestabilit pe durata
conexiunii. Putei emite orice numr de instruciuni USE pentru a comuta de la o baz de date la alta oricnd
dorii, cu condiia s avei privilegii de
-5
X i>- -
t * >*>
v f,'C">
164 Partea l Utilizarea general a sistemului MySQL
acces pentru a le folosi. De asemenea, selectarea unei baze de date nu v oblig s folos, tabele numai din acea
baz de date. Putei continua s facei referire la tabele din baze de date prin specificarea, alturi de numele
tabelului, a numelui bazei de date.
Cnd o conexiune cu serverul se ncheie, orice noiune a serverului cu privire la ider tatea bazei de date
prestabilite dispare. Astfel, dac v conectai din nou la server, ace nu-si amintete baza de date pe care ai
selectat-o anterior. De fapt, aa ceva nici nu ; avea sens, dat fiind c MySQL este multi-fir i poate manipula mai
multe conexiunii la un utilizator dat, care se poate conecta si deconecta n orice ordine, n acest mediu,.j este clar
care ar putea fi semnificaia noiunii de baz de date selectat anterior".
Crearea, tergerea, indexarea i modificarea tabelelor
MySQL v permite s creai tabele, s le tergei si s le modificai structura folosind inst iunile CREATE
TABLE, DROP TABLE i ALTER TABLE. Pentru fiecare din aceste instruciuni < extensii specifice sistemului
MySQL care le mresc utilitatea. Instruciunile CREATE It> DROP INDEX v permit s adugai sau s
eliminai indexuri din tabelele existente.
Instruciunea CREATE TABLE
Tabelele sunt create cu ajutorul instruciunii CREATE TABLE. Sintaxa complet a acea instruciuni este destul
de stranie, datorit numrului foarte mare de clauze opional dar n practic instruciunea respectiv este, de
obicei, relativ simplu de utilizat, exemplu, toate instruciunile CREATE TABLE pe care le-am folosit n
capitolul l prezentate ntr-o form rezonabil de simpl.
Ca o ironie, o bun parte din aceast complexitate suplimentar este determinat* clauzele pe care MySQL le
analizeaz si apoi le arunc! V putei convinge de dim^J siunea acestei complexiti consultnd Anexa D.
Examinai informaiile afere instruciunii CREATE TABLE i observai cum o bun parte din sintaxa
instruciunii dedicat clauzelor REFERENCES, CONSTRAINT i CHECK. Aceste clauze se refer la externe,
integritate referenial i restricii privind valorile de intrare. MySQL i accept aceste caracteristici, dar
analizeaz sintaxa pentru a face definiiile tabelelor i uor de utilizat dect cele pe care le-ai creat n alte sisteme
de baze de date. folosi mai uor acel program cu mai puine editri.) Dac v scriei propriile dese de tabel
pornind de la zero, putei uita complet de necesitatea de a manipula ac clauze. Eu unul nu voi mai sufla un
cuvnt despre ele n aceast seciune.
Instruciunea CREATE TABLE precizeaz cel puin numele tabelului si o list a coloanei din cadrul acestuia. De
exemplu CREATE TABLE tabelul meu
nume CHAR(20), vrsta INT NOT NULL, greutate INT, sex ENUM('F','M')
Capitolul 3 Sintaxa i utilizarea SQL n MySQL
165
n afar de coloanele care alctuiesc un tabel, putei specifica modul de indexare a tabelului atunci cnd l creai.
O alt opiune este de a lsa tabelul neindexat atunci cnd l creai i s adugai indexuri ulterior. Aceasta este o
strategie indicat dac intenionai s populai tabelul .eu foarte multe date nainte de a ncepe s-l utilizai pentru
interogri. Actualizarea indexurilor la inseria fiecrui rnd este mult mai lent dect ncrcarea datelor ntr-un
tabel neindexat i crearea indexurilor dup inseria tuturor datelor.
Am discutat deja despre sintaxa elementar a instruciunii CREATE TABLE n capitolul l, iar n capitolul 2,
Lucrul cu date n MySQL", am discutat modul de descriere a tipurilor de coloane. Presupun c ai citit aceste
capitole, deci nu vom repeta aici cele discutate anterior, n schimb, n continuare, vom discuta despre unele
extensii importante ale instruciunii CREATE TABLE, care au fost introduse n MySQL 3.23 i care v ofer o
mare flexibilitate n ceea ce privete modul de construcie a tabelelor:
Specificatori ai tipului de stocare a tabelului
Crearea unui tabel numai dac acesta nu exist deja
Tabele temporare, care sunt terse automat la ncheierea sesiunii client
Posibilitatea de creare a unui tabel prin simpla selectare a datelor pe care dorii s le conin
Specificatori ai tipului de stocare a tabelului
Anterior versiunii MySQL 3.23, toate tabelele create de utilizator foloseau metoda de stocare ISAM. n MySQL
3.23, putei crea n mod explicit tabele n oricare din cele trei tipuri, prin specificarea opiunii TYPE = tip dup
acea parte a instruciunii CREATE TABLE care conine lista coloanelor. Tip poate avea valorile MYISAM,
ISAM sau HEAP. De exemplu:
CREATE TABLE tabeluljneu (i INT, c CHAR(20)) TYPE = HEAP Putei converti tabele dintr-un tip n altul
folosind instruciunea ALTER TABLE:
ALTER TABLE tabeluljneu TYPE = ISAM
ALTER TABLE tabeluljneu TYPE = MYISAM
ALTER TABLE tabeluljneu TYPE = HEAP
Totui, nu se recomand conversia unui tabel la tipul HEAP dac dorii ca tabelul s existe si dup nchiderea
serverului. Tabelele HEAP sunt stocate n memorie si dispar cnd serverul nchide conexiunea.
Caracteristicile generale ale acestor trei tipuri de tabele sunt urmtoarele:
Tabele MylSAM. Formatul de stocare MylSAM este tipul de tabel prestabilit n MySQL, ncepnd de la
versiunea 3.23:
Fiierele pot fi mai mari dect n cazul metodei de stocare ISAM, dac sistemul de operare nsui permite
fiiere mai mari.
Datele sunt stocate ntr-un format independent de main, cu bitul cel mai puin semnificativ scris primul.
Aceasta nseamn c putei copia tabele de la un calculator la .altul, chiar dac acestea au arhitecturi diferite.
Valorile unui index numeric ocup mai puin spaiu de stocare, deoarece sunt stocate cu bitul cel mai
semnificativ scris primul. Valorile unui index tind s varieze mai rapid n domeniul biilor mai puin
semnificativi, deci biii mai semnificativi sunt mai expui la comprimare.
166 Partea l Utilizarea general a sistemului MySQL
Manipularea atributului AUTO_INCREMENT este mai bun dect n caz tabelelor ISAM. Detaliile despre
acest atribut sunt discutate n capitolul 2, i seciunea Lucrul cu secvene".
Numeroase restricii privind indexarea au fost eliminate. De exemplu, put indexa coloane care conin valori
NULL, dup cum putei indexa si coloane i tip BLOB i TEXT.
Pentru o verificare mai bun a integritii tabelului, fiecare tabel are un infe ctor care este activat (setat) cnd
tabelul este verificat de ctre myisamcli Putei folosi opiunea myisamchk -fast pentru a nu efectua verific
tabelelor care nu au fost modificate de la ultima verificare, ceea ce m viteza acestei operaii administrative. De
asemenea, tabelele dispun de indicator care arat dac un tabel a fost nchis n mod adecvat. Dac servei se
nchide ntr-o manier anormal sau calculatorul sufer o cdere, ind torul se poate folosi pentru a detecta
tabelele care trebuie verificate momentul pornirii serverului.
Tabele ISAM. Formatul de stocare ISAM este formatul mai vechi, folosit nainte H versiunea MySQL 3.23, dar
continu s existe i n prezent, n general, tabele MylSAM sunt preferate tabelelor ISAM, deoarece prezint mai
puine restrict Probabil c suportul pentru tabelele ISAM va disprea, deoarece acest format de care este
nlocuit de formatul de tabel MylSAM.
Tabele HEAP. Formatul de stocare HEAP creeaz tabele stocate n memorie, folosesc rnduri de lungime fix,
ceea ce le face foarte rapide. De asemenea, nsea c sunt temporare, n sensul c dispar la terminarea conexiunii
de ctre server. Tot spre deosebire de tabelele temporare create cu CREATE TEMPORARY TABLE, tabele
HEAP sunt vizibile si altor clieni. Tabelelor HEAP li se aplic restricii care nu valabile pentru tabelele ISAM
sau MylSAM:
Indexurile sunt folosite numai pentru comparaii care utilizeaz operatorii si <=>.
O coloan indexat nu poate conine valori NULL.
Nu se pot utiliza coloanele BLOB i TEXT.
Nu se pot utiliza coloanele AUTO_INCREMENT.
Crearea condiionata a tabelelor
Pentru a crea un tabel numai dac acesta nu exist deja, folosii instruciunea TABLE IF NOT EXISTS. Putei
folosi aceast instruciune ntr-o aplicaie care nu face: un fel de presupuneri cu privire la faptul dac tabelele de
care are nevoie au fost sau| configurate n prealabil i pur i simplu ncearc s creeze tabelele ca un lucru de la:
neles. Modificatorul IF NOT EXISTS este util mai ales pentru scripturi rulate ca : de grup cu mysql. n acest
context, o instruciune CREATE TABLE obinuit funcioneaz foarte bine. La prima rulare a sarcinii, tabelele
sunt create, dar a doua < se va produce o eroare, deoarece tabelele exist deja. Dac folosii IF NOT EXISTS, nu
< nici o problem. La prima rulare, tabelele vor fi create, ca n situaia anterioar. A . oar si la rulrile ulterioare,
ncercrile de creare a tabelului eueaz, dar nu este gene nici o eroare. Astfel, prelucrarea sarcinii poate continua
ca si cum ncercarea ar fi re
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 1 67
Tabele temporare
Putei folosi CREATE TEMPORARY TABLE pentru a crea tabele temporare, care dispar automat la ncheierea
sesiunii. Aceasta este o facilitate convenabil, deoarece nu trebuie s mai emitei o instruciune DROP TABLE
explicit pentru a scpa de tabel, iar tabelul nu mai continu s existe dac sesiunea se ncheie n mod anormal.
De exemplu, dac avei o interogare ncapsulat ntr-un fiier, pe care o rulai cu mvsql i decidei s nu mai
ateptai ncheierea acesteia, putei lichida scriptul n perfect siguran chiar n timpul execuiei, iar serverul va
elimina toate tabelele temporare.
n versiunile mai vechi ale sistemului MySQL, nu exist tabele temporare autentice, cu excepia situaiei cnd
dumneavoastr le considerai ca atare. Pentru aplicaii care necesit un atare tabel, trebuie s v amintii s-l
tergei personal. Dac uitai s-l tergei, sau dac la client se produce o eroare care l oblig s-si ncheie
prematur execuia, tabelul temporar persist fr rost, pn cnd cineva l observ si-l elimin.
Un tabel temporar este vizibil numai clientului care creeaz tabelul. Numele poate fi acelai cu al unui tabel
permanent existent. Aceasta nu reprezint o eroare si nici nu constituie un atac la adresa tabelului permanent. S
presupunem c ai creat un tabel temporar n baza de date samp_db, denumit membru. Tabelul membru original
devine ascuns (inaccesibil), iar referinele la tabelul membru trimit la tabelul temporar. Dac emitei o
instruciune DROP TABLE membru, tabelul temporar este eliminat i tabelul membru original reapare". Dac
pur i simplu v deconectai de la server fr a elimina tabelul temporar, serverul va terge automat tabelul
temporar. La urmtoarea conectare, tabelul membru original este din nou vizibil.
Mecanismul de ascundere a numelui este valabil la un singur nivel. Cu alte cuvinte, nu putei crea dou tabele
temporare cu acelai nume.
Crearea tabelelor pe baza rezultatelor instruciunii SELECT
Unul dintre conceptele cheie ale bazelor de date relaionale este c toate informaiile sunt reprezentate sub forma
unui tabel compus din rnduri i coloane, iar rezultatul fiecrei instruciuni SELECT este de asemenea un tabel
compus din rnduri i coloane, n multe situaii, tabelul" care rezult dintr-o instruciune SELECT este pur i
simplu o imagine a unor rnduri i coloane care se deruleaz de sus n jos pe ecranul dumneavoastr n timp ce
v continuai lucrul. Anterior versiunii MySQL 3.23, dac doreai s salvai rezultatele unei instruciuni SELECT
ntr-un tabel ce urma a fi folosit n interogri viitoare, erau necesare unele operaiuni speciale:
1. Rulai o interogare DESCRIBE sau SHOW COLUMNS pentru a determina tipurile coloanelor din tabelele de
unde dorii s capturai informaia.
2. Creai un tabel, specificnd n mod explicit numele si tipurile coloanelor n care tocmai ai cutat.
3. Dup crearea tabelului, emitei o interogare INSERT . . . SELECT, pentru a regsi rezultatele i pentru a le
insera n tabel.
In MySQL 3.23, situaia s-a schimbat. Instruciunea CREATE TABLE . . . SELECT elimin toate acele
ncurcturi dizgraioase i permite crearea instantanee a unui nou tabel folosind rezultatul unei interogri
SELECT arbitrare. Putei face aceast operaie ntr-o
168 Partea l Utilizarea general a sistemului MySQL
singur etap, fr a fi obligat s cunoatei sau s specificai tipurile de date coloanelor pe care le regsii.
Astfel, este excepional de simplu s creai un tabel comJ plet populat cu datele care v intereseaz i gata de a fi
utilizat n interogri ulterioare. J
Putei copia un tabel prin selectarea integral a coninutului su (fr clauza WHERE): putei crea o copie vid
prin adugarea unei clauze WHERE care eueaz ntotdeauna: CREATE TABLE nume_tbl_nou SELECT *
FROM nume_tbl CREATE TABLE nume_tbl_nou SELECT * FROM nume_tbl WHERE 1 = O Crearea unei
copii vide este util dac dorii s ncrcai un fiier de date n fiierul orig nai folosind LOAD DATA, dar nu
suntei sigur dac avei opiunile pentru specificare corect a formatului datelor. Nu dorii s v trezii cu
nregistrri deteriorate n tabeli original dac nu precizai corect opiunile din prima ncercare! Utilizarea unei
copii vie a tabelului original v permite s exersai opiunile LOAD DATA pentru specificarea delimjl tatorilor
de coloan i de linie, pn cnd datele dumneavoastr de intrare sunt interj pretate corect. Dup ce ai realizat
acest lucru, putei ncrca datele n tabelul original.,
Putei combina instruciunea CREATE TEMPORARY TABLE cu SELECT pentru a crea un tab temporar ca o
copie a lui nsui:
CREATE TEMPORARY TABLE tabeluljneu SELECT * FROM tabeluljneu Aceast instruciune v permite s
modificai coninutul tabelului tabeluljneu fr; afecta originalul. Acest fapt este util cnd dorii s ncercai
unele interogri care adtti! modificri-coninutului tabelului, fr a modifica tabelul original. Pentru a folosi erif
turi scrise anterior care folosesc numele tabelului original, nu trebuie s le editai pent a face referire la un alt
tabel; pur si simplu adugai instruciunea CREATE TEMPOR/ TABLE la nceputul scriptului. Scriptul va crea
o copie temporar i va lucra cu aceasta! iar serverul va terge copia atunci cnd scriptul i ncheie execuia.
Pentru a crea un tabel sub forma unei copii vide a lui nsui, folosii o clauz WHERE O i conjuncie cu
CREATE TEMPORARY ... SELECT:
CREATE TEMPORARY TABLE tabel SELECT FROM tabel WHERE 1 = O Totui, exist numeroase capcane
de care trebuie s v ferii cnd creai tabele instanti neu. Cnd creai un tabel prin selectarea unor date n acesta,
numele coloanelor si preluate de la coloanele pe care le selectai. Dac o coloan este calculat ca rezultai unei
expresii, numele" coloanei este textul expresiei. O expresie nu este permisaf nume de coloan. Putei constata
acest lucru dac rulai urmtoarea interogare n mys
mysql> CREATE TABLE tabeluljneu SELECT 1;
ERROR 1166 at line 1: Incorrect column name 'V (Eroare 1166 la linia 1: Nume de coloan incorect ' l')
Pentru a remedia eroarea, furnizai un alias al coloanei, pentru a atribui coloanei ' nume permis:
mysql> CREATE TABLE tabeluljneu SELECT 1 AS coloanajnea;
Query OK, 1 row affected (0.01 sec) O problem asemntoare apare dac selectai coloane cu acelai nume
din tabe diferite. S presupunem c tabelele t1 i t2 au ambele o coloan c i dumneavc dorii s creai un tabel
din toate combinaiile de rnduri din cele dou tabele, furniza aliasuri pentru a specifica nume unice de coloan
n noul tabel:
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 169
CREATE TABLE t3 SELECT tl.C AS c1, t2.c AS C2 FROM t1, t2; Crearea unui tabel prin selectarea unor
date n acesta nu copiaz n mod automat nici un index din tabelul original.
Instruciunea DROP TABLE
tergerea unui tabel este cu mult mai simpl dect crearea sa, deoarece nu trebuie s specificai nimic despre
coninutul tabelului; pur i simplu trebuie s denumii tabelul:
DROP TABLE nume_tabel
MySQL extinde instruciunea DROP TABLE n cteva moduri utile. Mai nti, putei terge mai multe tabele
specificndu-le pe toate n aceeai instruciune:
DROP TABLE nume_tabe!1, nume_tabe!2, ...
n al doilea rnd, dac nu suntei sigur cu privire la existena sau nu a unui tabel, dar dorii s-1 tergei dac
exist, putei aduga la instruciune opiunea IF EXISTS. Aceasta determin sistemul MySQL s nu fac
reclamaii si s nu emit erori dac tabelul sau tabelele specificate n instruciune nu exist:
DROP TABLE IF EXISTS nume_tabel
IF EXISTS este util n scripturi pe care le folosii cu clientul mysql, deoarece mysql, n mod prestabilit, i
ncheie execuia la producerea unei erori, iar ncercarea de a elimina un tabel care nu exista constituie o eroare.
De exemplu, putei avea un script de configurare care creeaz tabele pe care le folosii ca baz pentru prelucrri
ulterioare n alte scripturi, n aceast situaie, dorii s v asigurai c scriptul de configurare pornete pe curat".
Dac folosii o instruciune DROP TABLE normal la nceputul scriptului, acesta va eua prima dat, deoarece
tabelele nu au fost niciodat create.
Crearea si tergerea indexurilor
Indexurile reprezint metoda principal de accelerare a accesului la coninutul tabelelor dumneavoastr, mai ales
pentru interogri care implic uniri ale mai multor tabele. Acesta este un subiect suficient de important pentru ca
n capitolul 4, Optimizarea interogrilor", s se discute despre motivele utilizrii indexurilor, modul de
funcionare a acestora si despre modalitatea de utilizare optim a indexurilor n vederea optimizrii interogrilor,
n aceast seciune, vom discuta despre caracteristicile indexurilor i despre sintaxa pe care o folosii pentru
crearea i tergerea lor.
Caracteristicile indexurilor
MySQL asigur o flexibilitate remarcabil n ceea ce privete modul de construire a indexurilor. Putei indexa
coloane individuale sau combinaii de coloane. De asemenea, putei avea mai multe indexuri ntr-un tabel, dac
dorii s putei cuta rapid o valoare m diferite coloane ale tabelului. Dac o coloan este de un tip ir diferit de
ENUM sau SET, putei opta pentru indexarea numai a primelor n caractere (numrate de la stnga la dreapta) din
coloan, n cazul n care coloana este predominant unic sub aspectul primelor n caractere, de regul nu vei
sacrifica performanele, ba chiar le putei mbunti: indexarea prefixului unei coloane, i nu a ntregii coloane,
poate reduce att dimensiunea mdexului, ct i timpul de acces.
170 Partea! Utilizarea general a sistemului MySQL
Exist si unele restricii privind crearea unui index, dei acestea tind s se dilueze" msur ce sistemul MySQL
continu s se dezvolte. Tabelul urmtor prezint unele < rente dintre tabelele ISAM si MylSAM din punct de
vedere al posibilitilor de nde*
Caracteristica indexului
Valori NULL
Coloane BLOB i TEXT
Indexuri per tabel
Coloane per index
Dimensiune maxim a rndului index
Tabele MylSAM
Permise
Pot fi indexate
32
16
500 octei
Tabele ISAM
Interzise
Nu pot fi indexate
16
16
256 octei
Din tabel se poate observa c, n tabelele ISAM, o coloan indexat trebuie declarat l NULL, iar coloanele
BLOB i TEXT nu pot fi indexate. Tipul de tabel MylSAM elimin; restricii legate de crearea indexului i le
atenueaz pe altele. O consecin a ace diferene ntre cele dou tipuri de tabele n ceea ce privete
caracteristicile indexului > aceea c, n funcie de versiunea dumneavoastr de MySQL, s-ar putea s nu fii capa
de a indexa anumite coloane. De exemplu, putei folosi numai tabele ISAM dac ver nea dumneavoastr de
MySQL este anterioar versiunii 3.23, ceea ce nseamn c putei indexa anumite coloane dac dorii ca acestea
s poat conine valori NULL.
Dac dispunei de versiunea MySQL 3.23 sau ulterioar, putei avea tabele mai ve care au fost create de la bun
nceput ca tabele ISAM. Le putei converti cu uurin formatul de stocare MylSAM folosind instruciunea
ALTER TABLE, care v permitj beneficiai de unele dintre caracteristicile de indexare mai recente: ALTER
TABLE nume_tabel TYPE = MYISAM
Crearea indexurilor
Putei crea indexuri pentru un tabel nou atunci cnd folosii CREATE TABLE sau put! aduga indexuri la
tabelele existente utiliznd CREATE INDEX sau ALTER TABLE. Instr iunea CREATE INDEX a fost
introdus n MySQL 3.22, dar putei folosi ALTER TABLE < versiunea dumneavoastr de MySQL este
anterioar versiunii respective, (n pre MySQL mapeaz intern instruciunea CREATE INDEX peste ALTER
TABLE.)
Putei specifica dac indexul poate conine sau nu valori duplicate. Dac indextiM poate conine asemenea
valori, atunci trebuie creat ca index de tip PRIMARY KEY UNIQUE. Pentru un index unic pe o singur
coloan, aceast caracterizare asigur imp bilitatea existenei valorilor duplicate n coloana respectiv. Pentru un
index unic pe^ multe coloane, este astfel garantat imposibilitatea duplicrii unei combinaii de vale
Un index PRIMARY KEY este foarte asemntor cu un index UNIQUE. De fapt, indexul B MARY KEY nu este
altceva dect un index UNIQUE cu numele PRIMARY. Aceasta nsear un tabel poate conine un singur index
PRIMARY KEY, deoarece nu putei avea indexuri cu acelai nume. Putei plasa mai multe indexuri UNIQUE
ntr-un tabel, des se prea obinuiete. ,
Pentru a aduga un index la un tabel existent, putei folosi ALTER TABLE sau CRI INDEX. Instruciunea
ALTtR TABLE cea este mai versatil dintre cele dou, deoare putei folosi pentru a crea un index obinuit, un
index UNIQUE sau un index PRIMARY
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 171
ALTER TABLE nume_tbl ADD INDEX nume_index (lista_col)
ALTER TABLE nume_tbl ADD UNIQUE nume_index (lista_col)
ALTER TABLE nume_tbl ADD PRIMARY KEY (lista_COl)
nume_tbl este numele tabelului la care se va aduga indexul, iar lista_coJ precizeaz coloana sau coloanele care
trebuie indexate. Dac indexul este alctuit din cel puin dou coloane, numele acestora vor fi separate prin
virgul. Numele indexului nume_index este opional, deci l putei omite, iar MySQL va selecta un nume n
funcie de numele primei coloane indexate. Instruciunea ALTER TABLE v permite s specificai mai multe
modificri ale tabelului ntr-o singur instruciune, deci putei crea mai multe indexuri n acelai timp.
Instruciunea CREATE INDEX poate aduga ntr-un tabel un index obinuit sau UNIQUE:
CREATE UNIQUE INDEX nume_index ON nume_tbl (lista_col)
CREATE INDEX nume_index ON nume_tbl (lista_col)
Opiunile nume_tbl, nume_index i lista_col au aceeai semnificaie ca n cazul instruciunii ALTER TABLE.
Totui, numele indexului nu este opional. Nu putei crea un index PRIMARY KEY cu instruciunea CREATE
INDEX.
Pentru a crea un index ntr-un tabel nou atunci cnd emitei o instruciune CREATE TABLE, folosii o sintax
similar instruciunii ALTER TABLE, dar specificai clauzele de creare a indexului n acea parte a instruciunii
unde declarai coloanele tabelului: CREATE TABEL nume tabel
INDEX nume_index (lista_coloane), UNIQUE nume_index (lista_coloane), PRIMARY KEY (lista_coloane),
n ceea ce privete ALTER TABLE, numele indexului este opional pentru INDEX i UNIQUE, iar MySQL va
alege un nume, dac dumneavoastr nu o facei.
Ca un caz special, putei crea un index PRIMARY KEY cu o singur coloan prin adugarea opiunii PRIMARY
KEY la sfritul declaraiei coloanei: CREATE TABLE tabeluljneu
i INT NOT NULL PRIMARY KEY )
Instruciunea de mai sus este echivalent cu urmtoarea: CREATE TABLE tabelul meu
i INT NOT NULL, PRIMARY KEY (i)
172 Partea l Utilizarea general a sistemului MySQL
Fiecare din exemplele anterioare de creare a unui tabel au specificat NOT NULL pentru coloanele indexate.
Dac avei tabele ISAM, aceasta este o cerin obligatorie, deoarecCi nu putei indexa coloane care pot conine
valori NULL. Dac avei tabele MylSAM, coloanele indexate pot conine si valoarea NULL, cu condiia ca
indexul s nu fie de tip PRIMARY KEY.
Dac indexai un prefix al unei coloane ir (primele n caractere, de la stnga la dreapta,'( ale valorilor coloanei),
sintaxa pentru denumirea coloanei ntr-un specificatoi1 listaj^oloane este nume_coloana(n), nu doar un simplu
nume_coloana. De exemplu; prima din urmtoarele instruciuni creeaz un tabel cu dou coloane CHAR si un
ind care folosete ambele coloane. Cea de-a doua instruciune este similar, dar indexeazSj un prefix pentru
fiecare coloan: 1:
CREATE TABLE tabeluljneu
nume CHAR(30), adresa CHAR(60), INDEX (nume,adresa)
CREATE TABLE tabelul meu
nume CHAR(30),
adresa CHAR(60),
INDEX (nume(10),adresa(20))
n unele circumstane, vi se poate prea necesar indexarea unui prefix de coloan. D exemplu, lungimea
rndurilor index are o limit superioar, deci putei fi obligat s folosii prefixe dac lungimea coloanelor
indexate ar fi depit limita respectiv^ Prefixele sunt de asemenea necesare pentru coloanele BLOB sau TEXT
din indexuril tabelelor MylSAM.
Indexarea unui prefix de coloan impune modificri pe care le putei efectua n colo; la o dat ulterioar; nu
putei reduce lungimea coloanei pn la o dimensiune mai m dect lungimea prefixului fr a terge indexul si a-
1 re-crea ulterior folosind un pr< mai scurt.
tergerea indexurilor
Putei terge indexuri folosind DROP INDEX sau ALTER TABLE. Similar instruciunii CREA INDEX,
instruciunea DROP INDEX este manipulat intern ca o instruciune ALTER TABLE i a fost introdus n
MySQL versiunea 3.22. Sintaxa instruciunii de tergere a index este urmtoarea:
DROP INDEX nume_index ON nume_tabel
ALTER TABLE nume_tabel DROP INDEX nume_index
ALTER TABLE nume_tabel DROP PRIMARY KEY Primele dou instruciuni sunt echivalente. Cea de-a treia
este folosit numai pen tergerea unui index de tip PRIMARY KEY; n acest caz, nu este necesar nici un nume i
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 173
index, deoarece un tabel poate conine o singur asemenea cheie. Dac nici un index nu a fost creat n mod
explicit ca PRIMARY KEY, dar tabelul are dou sau mai multe indexuri de tip UNIQUE, MySQL l terge pe
primul dintre acestea.
Indexurile pot fi afectate dac tergei coloane dintr-un tabel. Dac tergei o coloan care face parte dintr-un
index, coloana va fi eliminat si din index. Dac sunt terse toate coloanele care alctuiesc un index, atunci
ntregul index va fi ters.
Instruciunea ALTER TABLE
ALTER TABLE este o instruciune versatil n MySQL si se poate folosi n multe scopuri. Deja am vzut cteva
dintre posibilitile sale (pentru crearea si tergerea indexurilor i pentru conversia tabelelor dintr-un format de
stocare n altul), n aceast seciune, vom discuta despre alte cteva aptitudini" ale acestei instruciuni. Sintaxa
complet a instruciunii ALTER TABLE este descris n Anexa D.
ALTER TABLE este util atunci cnd sesizai c structura unui tabel nu mai reflect finalitatea acestuia. Putei
folosi tabelul pentru a nregistra informaii suplimentare, sau poate c tabelul conine informaii care au devenit
superflue. Poate c dimensiunea coloanelor existente este prea mic sau poate c le-ai declarat mai mari dect
este necesar i dorii s le micorai pentru a economisi spaiu si pentru a mbunti performanele interogrilor.
Sau poate c pur i simplu ai tastat incorect numele tabelului atunci cnd ai emis instruciunea CREATE
TABLE. Iat cteva exemple:
Efectuai un chestionar bazat pe Web i stocai rezultatele fiecrui chestionar completat sub forma unei
nregistrri ntr-un tabel. Apoi, decidei s modificai chestionarul pentru a aduga unele ntrebri suplimentare.
Pentru a face loc noilor ntrebri, trebuie s mai adugai coloane n tabel.
Derulai un proiect de cercetare. Repartizai numere de caz nregistrrilor de cercetare folosind o coloan
AUTO_INCREMENT. Nu v-ai ateptat ca finanarea proiectului s dureze suficient pentru a permite generarea
a mai mult de aproximativ 50000 de nregistrri, deci declarai coloana de tip UNSIGNED SMALLINT, care
poate conine maximum 65536 valori unice. Totui, finanarea proiectului a fost reluat i se pare c vei mai
putea genera nc 50000 de nregistrri. Trebuie ca tipul coloanei s fie mai mare, pentru a permite inseria mai
multor numere de caz.
Modificrile dimensionale pot avea loc i n sens invers. Poate c ai creat o coloan CHAR (255), dar acum v
dai seama c nici o valoare din acest tabel nu are o lungime mai mare de 100 caractere. Putei reduce
dimensiunea coloanei pentru a economisi spaiu.
Sintaxa instruciunii ALTER TABLE se prezint astfel:
ALTER TABLE nume_tabel aciune, ...
Fiecare parametru aciune specific o modificare pe care dorii s o efectuai n tabel. MySQL extinde
instruciunea ALTER TABLE, permindu-v s specificai mai multe aciuni, separate prin virgul. Acest lucru
este util pentru reducerea volumului de text introdus de la tastatur, dar un motiv mai important al introducerii
acestei extensii l constituie imposibilitatea de a transforma tabelele cu rnduri de lungime variabil n tabele cu
rnduri de lungime fix fr a fi obligat s transformai n acelai timp toate coloanele VARCHAR n coloane
CHAR.
174 Partea l Utilizarea general a sistemului MySQL
Exemplele urmtoare prezint cteva dintre caracteristicile instruciunii ALTER TABLE:
Redenumirea unui tabel. O operaie simpl; pur i simplu specificai numele vechi sil numele nou:
ALTER TABLE nume_tabel RENAME AS nume_nou_tabel n MySQL 3.23, care dispune de tabele temporare,
redenumirea unui tabel temporar^ cu un nume care deja exist n baza de date determin ascunderea tabelului
original pel durata existenei tabelului temporar. Aceast operaie este similar cu procedeul ascundere a unui
tabel prin crearea unui tabel temporar cu acelai nume.
Modificarea tipului unei coloane. Pentru a modifica tipul unei coloane, putei folosjj una din clauzele
CHANGE sau MODIFY. S presupunem c n tabelul tabeluljneu exist ci coloan de tip SMALLINT
UNSIGNED i c dorii s o transformai n MEDIUMINt UNSIGNED. Putei face aceasta folosind oricare din
urmtoarele dou comenzi:
ALTER TABLE tabeluljneu MODIFY i MEDIUMINT UNSIGNED
ALTER TABLE tabeluljneu CHANGE i i MEDIUMINT UNSIGNED De ce numele coloanei este menionat de
dou ori n comanda care folosete CHANGE? Deoarece CHANGE are posibilitatea (pe care MODIFY nu o
are), n afar de modificare^ tipului coloanei, de a redenumi coloana. Dac ai fi vrut s redenumii coloana din i
n j simultan cu schimbarea tipului, ai fi procedat astfel:
ALTER TABLE tabeluljneu CHANGE i j MEDIUMINT UNSIGNED Aspectul important este c mai nti
denumii coloana pe care dorii s-o modificai i apoi specificai o declaraie complet a coloanei, care include
numele coloanei Numele coloanei trebuie inclus n declaraie, chiar dac este acelai ca vechiul nume.
Un motiv important pentru modificarea tipurilor de coloan const n mbuntire! eficienei interogrilor pentru
uniri care compar coloane din dou tabele. O com| paraie are loc mai rapid atunci cnd coloanele comparate
sunt de acelai tip. S pre< supunem c rulai o interogare ca aceasta:
SELECT ... FROM t1, t2 WHERE tl.nume = t2.nutne
Dac t1 .nume este CHAR(10) si t2.nume este CHAR(15), interogarea nu va rula la fel rapid ca n cazul n care
ambele coloane ar fi fost de tipul CHAR (15). Putei atribui cele dou coloane acelai tip prin modificarea tipului
coloanei t1 .nume, folosind orica din urmtoarele dou comenzi:
ALTER TABLE t1 MODIFY nume CHAR(15)
ALTER TABLE t1 CHANGE nume nume CHAR(15)
Pentru versiuni de MySQL anterioare versiunii 3.23, este esenial ca tipurile coloanele) dintr-o unire s fie
identice, n caz contrar indexurile neputnd fi folosite pentru COH| paraie. Pentru versiunea 3.23 i versiunile
ulterioare, indexurile se pot folosi pentif tipuri diferite, dar interogarea va fi din nou mai rapid dac tipurile sunt
identice. }|
Conversia unui tabel cu rnduri de lungime variabil n tabel cu rnduri de lung fix. S presupunem c avei
un tabel chartbl care conine coloane VARCHAR pe care dot s le convertii n coloane CHAR, pentru a vedea
care sunt mbuntirile de perfor
pe care le obinei, (n general, tabelele cu rnduri de lungime fix pot fi prelucrate i rapid dect tabelele cu
rnduri de lungime variabil.) Tabelul a fost creat astfel: CREATE TABLE chartbl (nume VARCHAR(40),
adresa VARCHAR(BO))
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 175
n acest caz, problema este c trebuie s modificai simultan toate coloanele, n aceeai instruciune ALTER
TABLE. Nu putei modifica fiecare coloan n parte, deoarece n acest caz ncercarea nu ar avea nici un efect.
Dac rulai interogarea DESCRIBE chartbl, vei descoperi c tipul coloanelor este n continuare definir ca
VARCHAR! Motivul este acela c, dac modificai o singur coloan la un moment dat, MySQL observ c
tabelul conine coloane cu lungime variabil si convertete coloana modificat napoi la tipul VARCHAR,
pentru a economisi spaiu. Pentru a rezolva problema, modificai simultan toate coloanele VARCHAR:
ALTER TABLE chartbl MODIFY nume CHAR(40), MODIFY adresa CHAR(BO) n acest moment,
instruciunea DESCRIBE va demonstra c tabelul conine coloane CHAR. Acest tip de operaii reprezint un
motiv pentru care este important ca instruciunea ALTER TABLE s accepte mai multe aciuni n cadrul unei
singure instruciuni.
Exist o capcan pe care trebuie s o cunoatei atunci cnd dorii s convertii un tabel ca acesta: prezena n
tabel a coloanelor BLOB i TEXT va anihila orice ncercare de a converti un tabel la un format cu rnduri de
lungime fix. Prezena fie i a unei singure coloane cu lungime variabil ntr-un tabel determin existena n tabel
a rndurilor cu lungime variabil, iar aceste tipuri de coloane (BLOB si TEXT - N.T.) nu au nici un echivalent cu
rnduri de lungime fix.
Conversia unui tabel cu rnduri de lungime fix n tabel cu rnduri de lungime variabil. Bun, deci chartbl este
mai rapid dac include numai rnduri cu lungime fix, dar ocup mai mult spaiu dect este necesar, deci decidei
s-1 reconvertii napoi la forma sa original, pentru a economisi spaiu. Conversia unui tabel n aceast direcie
este cu mult mai simpl. Trebuie s transformai o singur coloan CHAR n VARCHAR si MySQL va converti
n mod automat celelalte coloane CHAR. Pentru a converti tabelul chartbl, folosii oricare dintre urmtoarele
instruciuni:
ALTER TABLE chartbl MODIFY nume VARCHAR(40) ALTER TABLE chartbl MODIFY adresa VARCHAR
(80)
Conversia unui tip de tabel. Dac ai trecut de la o versiune MySQL anterioar versiunii 3.23 la aceast
versiune sau la una ulterioar, putei avea tabele mai vechi, care au fost create ca tabele ISAM. Dac dorii s le
creai n format MylSAM, procedai astfel:
ALTER TABLE nume_tabel TYPE = MYISAM
De ce ai proceda astfel? Un motiv, aa cum s-a artat n seciunea Crearea i tergerea indexurilor", este acela
c formatul de stocare MylSAM dispune de unele caracteristici de indexare inexistente n formatul ISAM, cum
ar fi capacitatea de a indexa valori NULL i tipurile de coloane BLOB i TEXT. Un alt motiv este acela c
tabelele MylSAM sunt mdependente de main, deci le putei deplasa i n alte calculatoare prin copierea direct
a fiierelor tabel, chiar dac sistemele de calcul au arhitecturi hardware diferite. Despre aceste aspecte vom
discuta mai detaliat n seciunea Realizarea copiilor de siguran a bazelor de date i copierea acestora" din
capitolul 11.
176 Partea l Utilizarea general a sistemului MySQL
Obinerea informaiilor despre baze de date i tabele
MySQL furnizeaz numeroase instruciuni pentru obinerea de informaii prrv bazele de date i tabelele pe care
le conin acestea. Instruciunile respective sunt ut pentru urmrirea coninutului bazelor dumneavoastr de date i
pentru a v rea structura tabelelor. De asemenea, le putei folosi ca ajutor n utilizarea instructiv ALTER
TABLE; este mai uor a determina modul de specificare a unei modificri nt coloan atunci cnd putei afla cum
este definit coloana la un moment dat.
Instruciunea SHOW poate fi folosit pentru a se obine informaii privind numere aspecte ale bazelor de date i
ale tabelelor dumneavoastr:
Afieaz bazele de date din server Afieaz tabelele din baza de date curent Afieaz tabelele din baza de date
specificat
Afieaz informaiile despre coloanele tabelul specificat
Afieaz informaiile despre indexurile tabelul specificat
Afieaz informaii descriptive despre tab din baza de date prestabilit
Afieaz informaii descriptive despre tabe din baza de date specificat
Instruciunile DESCRIBE nume_tabel i EXPLAIN nume_tabel sunt sinonime cu instruct: nea SHOW
COLUMNS FROM nume_tabel.
Comanda mysqlshow furnizeaz o parte din informaiile oferite de instruciunea SHOW,< ce v permite s
obinei din interpreter informaiile privind bazele de date i tabelele: j
A, j
% mysqlshow Afieaz bazele de date din server
% mysqlshow nume_db Afieaz tabelele din baza de date specificai
% mysqlshow nume_db nume_tabel Afieaz informaiile despre coloanele din:|(
belul specificat
% mysqlshow --keys nume_db nume_tabel Afieaz informaiile despre indexurile din
belul specificat
% mysqlshow --status nume_db Afieaz informaii descriptive despre tabl
din baza de date specificat
Utilitarul mysqldump v permite s vizualizai structura tabelelor dumneavoast forma unei instruciuni CREATE
TABLE. (Spre deosebire de instruciunea SHOW COLI eu sunt de prere c rezultatele comenzii mysqldump
sunt mai uor de citit i afie indexurile n tabel.) Dar, dac folosii mysqldump, nu uitai s invocai aceast cor
cu opiunea - -no-data, ca s nu v mpotmolii n datele tabelului dumneavoastr!
% mysqldump --no-data nume_db nume_tabel
Att pentru mysqlshow ct i pentru mysqldump, putei specifica opiunile uzuale, cur fi - -host, pentru a v
conecta la un server instalat pe o alt gazd.
SHOW DATABASES
SHOW TABLES
SHOW TABLES FROM nume_db
SHOW COLUMNS FROM nume_tabel
SHOW INDEX FROM nume_tabel
SHOW TABLE STATUS
SHOW TABLE STATUS FROM nume db
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 177
Regsirea nregistrrilor
SELECT lista_seJectie FROM lista_tabele WHERE restrictie_primara GROUP BY grupare_coloane ORDER
BY sortare_coloane HAVING restrictie_seci/ndara
LIMIT numr
Nu are nici un sens s plasai nregistrri ntr-o baz de date dac nu le regsii la un moment ulterior i nu le
utilizai ntr-un fel sau altul. Acesta este i rostul instruciunii SELECT: s v ajute s ajungei la datele
dumneavoastr. SELECT este probabil instruciunea cea mai folosit a limbajului SQL, dar poate fi i cea mai
dificil; restriciile pe care le folosii pentru a alege rndurile pot fi arbitrar de complexe si pot necesita, n multe
tabele, comparaii ntre coloane.
Sintaxa de baz a instruciunii SELECT se prezint astfel:
Coloanele care trebuie selectate Tabelele din care sunt selectate rndurile Condiiile pe care trebuie s le satisfac
rndurile Modul de grupare a rezultatelor Modul de sortare a rezultatelor
Condiii secundare pe care trebuie s le satisfac rndurile
Limitare aplicat rezultatelor
Toate elementele din aceast sintax sunt opionale, cu excepia cuvntului SELECT i a parametrului
lista_selectie, care specific datele pe care dorii s le regsii. Unele sisteme de baze de date impun si utilizarea
clauzei FROM. MySQL nu impune aceast clauz, ceea ce v permite s evaluai expresii fr a face referire la
vreun tabel:
SELECT SQRT(POW(3,2)+POW(4,2))
In capitolul l am acordat o atenie deosebit instruciunii SELECT, concentrndu-ne cu precdere asupra listei cu
selecia coloanelor si asupra clauzelorWHERE, GROUP BY, ORDER BY, HAVING i LIMIT, n acest capitol,
ne vom concentra asupra aspectului instruciunii SELECT care este, poate, cel mai derutant: unirea. Vom discuta
despre tipurile de uniri pe care le accept MySQL, despre sensul i modul de specificare a acestora. Astfel vei
putea ntrebuina limbajul MySQL ntr-un mod mai eficient, deoarece, n multe situaii, adevrata problem a
determinrii modului de a scrie o interogare l constituie sesizarea modalitii adecvate de unire a tabelelor. De
asemenea, poate dorii s examinai seciunea Breviar de soluii", care apare mai trziu n acest capitol. Acolo
vei gsi soluii la numeroase probleme SQL, din care marea majoritate implic, ntr-un fel sau altul,
instruciunea SELECT.
0 problem a instruciunii SELECT este aceea c, atunci cnd v ntlnii prima dat cu un nou tip de problem,
nu este ntotdeauna uor s determinai modul de a scrie o instruciune SELECT pentru a o rezolva. Totui, dup
ce v-ai dat seama cum trebuie scris interogarea, putei folosi experiena acumulat atunci cnd vei ntlni
probleme similare n viitor. SELECT este, probabil, instruciunea n cazul creia experiena acumulat este cea
mai important pentru capacitatea dumneavoastr de a o folosi eficient, pur 1 simplu datorit imensei varieti
de moduri n care putei utiliza instruciunea.
1 e msur ce dobndii experien, o vei putea aplica mai uor la noile probleme i v vei trezi gndindu-v
astfel: A, da, asta-i una din chestiile alea cu LEFT JOIN", respec-tlv Aha, pi asta este o unire pe trei ci
limitat de perechile comune de coloane cheie".
178 Partea! Utilizarea general a sistemului MySQL
(De fapt, mi-e cam jen s spun asta. Vi se poate prea ncurajator s aflai c experie v poate fi de folos. Pe de
alt parte, e puin cam nspimnttor s ajungei s gnc folosind un astfel de vocabular!)
n urmtoarele cteva seciuni, care demonstreaz modul de utilizare a formelor operatori de unire acceptai de
MySQL, majoritatea exemplelor folosesc urmtoare dou tabele. Tabelele sunt mici, ceea ce le face suficient de
simple pentru a permit sesizarea imediat a efectului fiecrui tip de unire: tabelul t1: tabelul t2:
it c1 12 C2
1 a 2 c
2 b 3 b
3 c 4 a
Unirea normal
Cea mai simpl unire este unirea normal, n care este denumit un singur tabel, n ac caz, rndurile sunt selectate
din tabelul specificat: SELECT * FROM t1
11 C1
1 a
2 b
3 c
Unii autori nu consider aceast form a instruciunii SELECT ca fiind o unire i folosq acest termen numai
pentru instruciunile SELECT care regsesc nregistrri din dou; mai multe tabele. Eu cred c este o problem
de perspectiv.
Unirea complet
Dac sunt specificate mai multe tabele, cu numele separate prin virgul, se execui unire complet. De exemplu,
dac unii dou tabele, fiecare rnd din primul tabel > combinat cu fiecare rnd din al doilea tabel: SELECT
t1.*,t2.* FROM t1, t2
i.1 C1 12 C2
* a 2 C
2 b 2 C
3 c 2 C
1 a 3 b
2 b 3 b
3 c 3 b
1 a 4 a
2 b 4 a
3 c 4 a
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 179
O unire complet se mai numete i unire ncruciat, deoarece fiecare rnd al fiecrui tabel este ncruciat cu
fiecare rnd din toate celelalte tabele pentru a produce toate combinaiile posibile. Aceast operaie mai este
cunoscut si sub numele de produs cartezian. Unirea n acest mod a tabelelor are potenialul de a genera un
numr foarte mare de rnduri, deoarece numrul de rnduri posibil este produsul numerelor de rnduri din
fiecare tabel. O unire complet ntre trei tabele care conin 100,200 si 300 de rnduri poate returna 100 x 200 x
300 = 6 milioane de rnduri, ceea ce nseamn un numr foane mare, chiar dac tabelele n sine sunt mici. n
situaii precum aceasta, n mod normal se va folosi o clauz WHERE pentru a reduce setul de rezultate la o
dimensiune mai rezonabil!
Dac adugai n clauza WHERE o condiie care s determine coroborarea tabelelor n funcie de valorile
anumitor coloane, unirea devine ceea ce se numete o echi-unire, deoarece selectai numai rndurile cu valori
egale din coloanele specificate: SELECT t1.*, t2.* FROM t1, t2 WHERE t1.i1 = t2.i2
11 C1 12 02
23 bc 23 C
b
Tipurile de unire JOIN, CROSS JOIN i INNER JOIN sunt echivalente cu operatorul de unire ,.
O unire STRAIGHT_JOIN este similar unei uniri complete, dar tabelele sunt unite n ordinea precizat n
clauza FROM, n mod normal, utilitarul de optimizare din MySQL i ia libertatea de a rearanja ordinea tabelelor
dintr-o unire complet pentru o regsire mai rapid a rndurilor. Ocazional, utilitarul de optimizare nu va efectua
o alegere optim, alegere pe care o putei impune folosind cuvntul cheie STRAIGHT_JOIN.
STRAIGHT_JOIN poate fi specificat n dou puncte ale instruciunii SELECT, l putei insera ntre cuvntul
cheie SELECT i lista de selecie, pentru a avea un efect global asupra tuturor unirilor complete din instruciune,
respectiv l putei specifica n clauza FROM. Urmtoarele dou instruciuni sunt echivalente:
SELECT STRAIGHT_JOIN ... FROM tabell, tabe!2, tabe!3 ...
SELECT ... FROM tabell STRAIGHT JOIN tabe!2 STRAIGHT JOIN- tabelS ...
Explicitatea referinelor la coloane
Referinele la coloanele tabelelor dintr-o instruciune SELECT trebuie s trimit fr echivoc la un singur tabel
denumit n clauza FROM. Dac este specificat un singur tabel, nu exist nici un echivoc, deoarece toate
coloanele trebuie s aparin tabelului respectiv. Dac sunt denumite mai multe tabele, toate numele de coloan
care apar ntr-un singur tabel sunt, de asemenea, fr echivoc. Totui, dac numele coloanei apare n mai multe
tabele, referirile la coloan trebuie s conin i numele tabelului, folosind sintaxa nume_tabel.nume_coloana,
pentru a preciza tabelul la care v referii. Dac un tabel denumit tabelul_meut conine coloanele a i b, iar un
tabel denumit tabelul_meu2 conine coloanele b i c, referinele la coloanele a si c sunt fr echivoc, dar
referinele la coloana b trebuie completate sub una din formele tabeluljneul. b sau tabelul_meu2. b:
SELECT a, tabeluljneul.b, tabelul_meu2.b, c
FROM tabeluljneul, tabelul_meu2...
n unele situaii, un element de explicitare de tip nume de tabel nu este suficient pentru clarificarea unei referine
de coloan. De exemplu, dac folosii un tabel de mai multe ori ntr-o interogare, nu este sufi-
180 Partea l Utilizarea general a sistemului MySQL
cient explicitatea unui nume de coloan cu numele tabelului, n acest caz, pentru comunicarea inten ilor
dumneavoastr sunt utile aliasurile de tabel. Putei atribui un alias oricrei instane a tabelului h facei referiri la
coloane din instana respectiv a tabelului sub forma nume_alias.nume_coloan$ Urmtoarea interogare unete un
tabel cu el nsui, dar atribuie un alias unei instane a tabelului, pen a permite specificarea fr echivoc a
referinelor la coloan:
SELECT tabeluljneu.coll, m.col2
FROM tabeluljneu, tabeluljneu AS m WHERE tabelul meu.coll > m.coll
Unirea la stnga
O echi-unire afieaz numai rndurile unde n ambele tabele exist o coresponden i anumite criterii de cutare.
O unire la stnga afieaz de asemenea corespondenele, da prezint i rndurile din tabelul din stnga care nu au
o coresponden n tabelul dreapta. Toate coloanele selectate din tabelul din dreapta pentru aceste rnduri uii
afiate ca NULL. Mecanismul de funcionare este acela c sunt selectate toate rndurile i tabelul din stnga.
Dac exist un rnd echivalent n tabelul din dreapta, rndul respe tiv este selectat. Dac nu exist nici o
echivalen, se selecteaz totui un rnd, dar ace este un rnd fals", n care toate coloanele au primit valoarea
NULL. Cu alte cuvinte^] unire la stnga foreaz setul de rezultate s conin un rnd pentru fiecare rnd al
tabel)! lui din stnga, indiferent dac pentru rndul respectiv exist sau nu un echivalent- tabelul din dreapta.
Stabilirea corespondenei se efectueaz conform coloanelor denur ntr-o clauz ON sau USING(). Putei folosi
opiunea ON indiferent dac numele coloane pe care le unii sunt identice:
SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON t1.i1 = t2.i2
11 C1 12 l c2
! a NULL';
NULL
2 b 2 i c
3 f\ 3 i b
Clauza USING() este similar clauzei ON, dar numele coloanei sau ale coloanelor ur trebuie s fie aceleai n
fiecare tabel. Interogarea urmtoare unete coloaa tabeluljneut .b cu coloana tabelul_meu2.b:
SELECT tabeluljneul.*, tabelulmeu2.* FROM tabeluljneul
LEFT JOIN tabelul_meu2 USING (b)
LEFT JOIN este util mai ales atunci cnd dorii s gsii numai acele rnduri ale tat lui din stnga care nu apar
n tabelul din dreapta. Pentru aceasta, adugai clauza' care caut rndurile tabelului din dreapta ce au valori
NULL:
SELECT t1.*, t2.* FROM t1 LEFT JOIN t2 ON t1.i1 = t2.i2
WHERE t2.i2 IS NULL
11 C1 \ C2
12 :
1 a i NUL
NUL L
L
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 181
n mod normal, nu vei selecta coloanele cu valoarea NULL, deoarece nu prezint interes. Ceea ce v intereseaz
sunt coloanele fr echivalent ale tabelului din stnga:
SELECT t1.* FROM t1 LEFT JOIN t2 ON t1.i1 = t2.i2
WHERE t2.i2 IS NULL
11 :. C1
Un aspect de care trebuie s v ferii n ceea ce privete LEFT JOIN este acela c, n cazul n care coloanele pe
care realizai unirea sunt declarate ca fiind NOT NULL, rezultatul poate conine rnduri nedorite.
LEFT JOIN are cteva sinonime si variante. LEFT OUTER JOIN este sinonim cu LEFT JOIN. De asemenea,
exist o notaie ODBC pentru LEFT JOIN care este acceptat de ctre MySQL (expresia o j are sensul de unire
exterioar - outer join):
{ oj nume_tatiel LEFT OUTER JOIN nume_tabel ON expr_unire. } NATURAL LEFT JOIN este similar cu
LEFT JOIN; execut o unire la stnga, stabilind corespondene pentru toate coloanele cu acelai nume ale
tabelelor din stnga, respectiv din dreapta.
Unele sisteme de baze de date au o instruciune RIGHT JOIN echivalent; MySQL nu dispune nc de aceast
instruciune.
Scrierea comentariilor
MySQL v permite s intercalai comentarii n liniile dumneavoastr de program SQL. Acest lucru poate fi util
pentru documentarea interogrilor pe care le stocai n fiiere. Putei scrie comentarii n dou moduri. Orice text
delimitat de un caracter # la stnga si sfritul liniei la dreapta este considerat comentariu. Sunt permise i
comentariile folosite n C. Cu alte cuvinte, orice text inclus ntre simbolurile de nceput, respectiv sfrit l* i 'V
este considerat comentariu. Comentariile n C se pot extinde pe mai multe linii:
# acesta este un comentariu pe o singura linie
/* si acesta este un comentariu pe o singura linie */
/* acesta, totui, este un comentariu pe mai multe linii
*/
ncepnd de la MySQL versiunea 3.23, putei ascunde" cuvintele cheie specifice limbajului MySQL n
comentarii de tip C, precednd comentariul prin caracterele /* l n ioc de /*. MySQL examineaz acest tip special
de comentariu i folosete cuvintele cheie, dar alte servere de baze de date le vor ignora, deoarece fac parte din
comentariu. Acest lucru v ajut s scriei programe care beneficiaz de funciile specifice sistemului MySQL
atunci cnd sunt executate n MySQL, dar care pot fi folosite si de ctre alte servere de baze de date, fr
modificri. Urmtoarele dou instruciuni sunt echivalente pentru servere de baze de date altele dect MySQL,
dar MySQL va efectua o operaie INSERT DELAYED pentru a doua instruciune:
182 Partea l Utilizarea general a sistemului MySQL
INSERT INTO absente (elev_id,data) VALUES(13,"1999-09-28") INSERT /*! DELAYED */ INTO absente
(elev_id,data) VALUES(13,"1999-09-28" ncepnd de la versiunea MySQL 3.23.3, n afar de stilurile de
comentariu descris anterior, putei iniia un comentariu cu dou liniue i un spaiu (- -); orice text pla ntre
aceste liniue i sfritul liniei este tratat ca un comentariu. Alte sisteme de baze i date folosesc cele dou liniue
pentru a ncepe un comentariu; MySQL permite ace lucru, dar impune utilizarea spaiului pentru eliminarea
oricrei confuzii.
Instruciuni cu expresii precum 5- -7 ar putea fi interpretate ca incluznd un come tariu. Este puin probabil s
scriei o expresie precum 5- - 7, deci aceasta este o euris tic util. Totui, nu este dect o euristic, deci
probabil este bine s folosii unul dir celelalte stiluri de comentarii, folosind liniuele duble numai n programe
pe care le pot tai din alte sisteme de baze de date.
Breviar de soluii
Aceast seciune seamn oarecum cu un corn al abundenei"; indic modul de scrie a interogrilor pentru
rezolvarea diferitelor categorii de probleme, n majoritatea caz rilor, acestea sunt soluii la probleme care mi-au
parvenit din lista de corespondent (Mulumiri persoanelor din list care au contribuit cu multe din aceste
rspunsuri.)
Rescrierea subselectiilor sub form de uniri
ncepnd cu versiunea 3.24, MySQL va dispune de subselecii. Lipsa acestei caracteri tici este una dintre cele
mai criticate omisiuni din MySQL, dar un lucru de care m par s nu-si dea seama este acela c interogrile scrise
folosind subselecii pot fi frecvi reformulate folosind uniri. De fapt, chiar si cnd MySQL va fi dotat cu
subselecii, chiar indicat s examinai interogrile pe care suntei nclinat s le scriei folosindu* deseori este mai
eficient s folosii o unire n locul subseleciei.
Rescrierea subselectiilor care selecteaz valori corespunztoare unui criteriu de cutare
Iat un exemplu de interogare care conine o subselecie; interogarea selecteaz pu: tajele din tabelul puncte
obinute la toate testele (adic ignor punctajele obinute chestionare):
SELECT * FROM puncte WHERE eveniment_id
IN (SELECT eveniment_id FROM eveniment WHERE tip = "T") Aceeai interogare se poate scrie fr o
subselecie, prin conversia ei ntr-o simpl
SELECT puncte.* FROM puncte, eveniment
WHERE puncte.eveniment_id = eveniment.eveniment_id AND eveniment.tip Exemplul urmtor selecteaz
punctajele obinute de elevii de sex feminin:
SELECT * FROM puncte
WHERE elev_id IN (SELECT elev_id FROM elev WHERE sex = "F")
,scr ;
!*V> -
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 183
Aceast interogare se poate converti ntr-o unire dup cum se va vedea mai jos:
SELECT puncte.* FROM puncte, elev
WHERE puncte.elev_id = elev.elev_id AND elev.sex = "F" Se observ existena unui model. Interogrile cu
subselecie respect urmtoarea form:
SELECT * FROM tabell WHERE coloanat
IN {SELECT coloana2 FROM tabe!2a WHERE coloana2b = valoare) Asemenea interogri pot fi convertite
ntr-o unire folosind aceast form:
SELECT tabell.* FROM tabell, tabel2
WHERE tabel1.coloana 1 = tabel2.coloana2a AND tafce!2.coloana2b = valoare
Rescrierea subseleciilor care selecteaz valori care nu corespund unui criteriu de cutare
O alt categorie comun de interogri cu subselecie caut valorile dintr-un tabel care nu se regsesc n alt tabel.
Aa cum am vzut mai sus, tipul de problem valori care nu exist" poate fi soluionat cu ajutorul unei
instruciuni LEFT JOIN. Iat o interogare cu subselecie care testeaz absena valorilor dintr-un tabel (i gsete
pe elevii cu prezen 100%);
SELECT * FROM elev
WHERE elev_id NOT IN (SELECT elev_id FROM absente) Aceast interogare se poate rescrie folosind o
instruciune LEFT JOIN dup cum urmeaz:
SELECT elev.*
FROM elev LEFT JOIN absente ON elev.elev_id = absente.elev_id
WHERE absente.elev_id IS NULL n termeni generali, forma interogrii cu subselecie este urmtoarea:
SELECT * FROM tabel1
WHERE coloanaT NOT EXISTS (SELECT coloana2 FROM tabe!2) O interogare cu aceast form se poate
rescrie astfel:
SELECT tabell.*
WHERE tabel1 LEFT JOIN tabe!2
ON tabel 7.coloana1 = tabe!2.coloana2
WHERE tabel2.coloana2 IS NULL Se presupune c declaraia coloanei tabe!2.coloana2 conine atributul NOT
NULL.
Depistarea valorilor inexistente ntr-un tabel
Deja am vzut n seciunea Regsirea nregistrrilor" c, atunci cnd dorii s tiri care sunt valorile dintr-un
tabel inexistente ntr-un alt tabel, folosii o instruciune LEFT JOIN pentru cele dou tabele si cutai rndurile n
care este selectat valoarea NULL din al doilea tabel. Atunci a fost prezentat o situaie simpl, care folosea
urmtoarele dou tabele: tabelul t1: tabelul t2:
11 C1 12 c2
1 a 2 c
2 b 3 b
3 c 4 a
184 Partea l Utilizarea general a sistemului MySQL
Instruciunea LEFT JOIN pentru gsirea tuturor valorilor din coloana t1.11 care nu afl n coloana 12.12 are
forma urmtoare:
SELECT t1.* FROM tt LEFT JOIN t2 ON t1.i1 = t2.i2
WHERE t2.i2 IS NULL '.
11 j C1
Acum, s ne gndim la o versiune mai dificil a ntrebrii Care sunt valorile c lipsesc?", n proiectul de eviden
a rezultatelor colare, menionat pentru prima datai capitolul l, avem un tabel elev care conine elevii, un tabel
eveniment care prezi evenimentele de tip examinare care s-au produs, respectiv un tabel puncte care enumi
punctajele obinute de fiecare elev la fiecare eveniment de tip examinare. Totui, daca elev a fost bolnav la data
susinerii unui chestionar sau a unui test, tabelul puncte nu conine nici un punctaj al elevului pentru evenimentul
respectiv, deci este necesar reii rea chestionarului sau a testului. Cum putem gsi aceste nregistrri lips, pentru
a, putea asigura c elevii respectivi susin repetarea examinrii?
Problema const n determinarea elevilor care nu au nici un punctaj la o examinare, p< tru fiecare examinare n
parte. Cu alte cuvinte, dorim s aflm care sunt combinai elev-eveniment care nu se regsesc n tabelul puncte.
Aceast formulare de tip care valorile inexistente" este o sugestie a faptului c se dorete o instruciune LEFT
JO! Unirea nu va fi la fel de simpl ca n exemplul anterior, totui, deoarece nu cutm nur valori inexistente
ntr-o singur coloan, ci o combinaie ntre dou coloane.
Combinaiile pe care le cutm sunt toate combinaiile elev-eveniment, care se prod din ncruciarea tabelului
elev cu tabelul eveniment:
FROM elev, eveniment Apoi, lum rezultatul unirii respective i executm o instruciune LEFT JOIN cu tabej
puncte pentru a gsi perechile cutate:
FROM elev, eveniment
LEFT JOIN puncte ON elev.elev_id = puncte.elev_id
AND eveniment.eveniment_id = puncte.eveniment_id " Reinei c clauza ON permite unirea rndurilor din
tabelul puncte n conformitate valorile echivalente din diferite tabele. Aceasta este cheia pentru rezolvarea
probleii Instruciunea LEFT JOIN foreaz generarea unui rnd pentru fiecare rnd obinut unirea ncruciat a
tabelelor elev si eveniment, chiar dac nu exist nici o nregisti corespunztoare n tabelul puncte. Rndurile din
setul de rezultate pentru aceste gistrri lips din tabelul puncte pot fi identificate prin faptul c toate coloanele.
tabelul puncte vor avea valoarea NULL. Putem selecta aceste nregistrri n clauza Wjlj Se poate utiliza orice
coloan din tabelul puncte, dar, deoarece cutm punctajele li|| probabil c din punct de vedere conceptual este
cel mai clar dac testm coloana pune]
WHERE puncte.puncte IS NULL
Putem pune rezultatele n ordine folosind o clauz ORDER BY. Cele mai logice dou jamente sunt n funcie de
elev i de eveniment, l voi alege pe primul:
ORDER BY elev_elev.id, eveniment.eveniment_id
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 185
Acum, tot ce avem de fcut este s specificm coloanele pe care dorim s le vedem ca date de ieire i am
terminat. Iat interogarea final: SELECT
elev.nume, elev.elev_id,
eveniment.data, eveniment.eveniment_id, eveniment.tip FROM
elev, eveniment
LEFT JOIN puncte ON elev.elev_id = puncte.elev_id
AND eveniment.eveniment_id = puncte.eveniment_id WHERE
puncte.puncte IS NULL ORDER BY
elev_elev.id, eveniment.eveniment_id La rularea interogrii se produc urmtoarele rezultate:
nume elev_id data eveniment_id tip
Megan 1 1999-09-16 4 C
Joseph 2 1999-09-03 1 C
Katie 4 1999-09-23 5 C
Devri 13 1999-09-03 1 n
Devri 13 1999-10-01 6 T
Will 17 1999-09-16 4 C
Ave r y 20 1999-09-06 2 C
Gregory 23 1999-10-01 6 T
Sarah 24 1999-09-23 5 C
Carter 27 1999-09-16 4 /
Carter 27 1999-09-23 5 C
Gabrielle 29 1999-09-16 4 c
Grace 30 1999-09-23 5 c
Aici este un element subtil. Datele de ieire afieaz identificatorii de elev i de eveniment. Coloana elev_id
apare att n tabelul elev, ct i n tabelul puncte, deci la nceput s-ar putea s credei c lista de selecie putea
conine fie elev.elev_id, fie puncte.elev_id. Nu este adevrat, deoarece fundamentul capacitii de a gsi nregis-
trrile care ne intereseaz este acela c toate cmpurile din tabelul puncte sunt returnate ca fiind NULL. Prin
selectarea coloanei puncte.elev_id s-ar fi obinut ca date de ieire numai o coloan de valori NULL. Un
raionament similar se aplic i n cazul coloanei eveniment_id, care apare att n tabelul eveniment, ct si n
tabelul puncte.
Efectuarea unei operaii UNION
Dac dorii s creai un set de rezultate prin selectarea nregistrrilor din mai multe tabele care au aceeai
structur, putei face acest lucru n unele sisteme de baze de date lolosind o anumit categorie de instruciuni
UNION. MySQL nu dispune de o asemenea instruciune (cel puin pn la MySQL versiunea 3.24), dar putei
ocoli acest neajuns n cteva moduri, n continuare sunt date dou posibile soluii:
186 Partea l Utilizarea general a sistemului MySQL
Efectuai mai multe interogri SELECT, cte una pentru fiecare tabel. Aceast solui| este posibil dac nu v
intereseaz ordinea rndurilor pe care le selectai.
Selectai rndurile din fiecare tabel ntr-un tabel temporar de stocare. Apoi selectat coninutul acelui tabel.
Acest lucru v permite s sortai rndurile aa cum dorii. MySQL 3.23 i versiunile ulterioare, putei rezolva cu
uurin aceast problem ] mind serverului s creeze automat tabelul de stocare. De asemenea, putei atribt]
acestui tabel un caracter temporar, astfel nct s fie ters automat la terminarea sesiunii dumneavoastr de lucru
cu serverul.
n programul urmtor, vom terge tabelul n mod explicit, pentru a permite serverii lui s elibereze resursele
asociate acestuia. Aceasta este o idee bun dac sesiunea clie va continua s efectueze si alte interogri. De
asemenea, vom folosi un tabel HEAP (st cat n memorie) pentru a obine performane sporite. CREATE
TEMPORARY TABLE tbl Stoc TYPE=HEAP ... FROM tabel f WHERE...
INSERT INTO tbl_stoc SELECT INSERT INTO tbl StOC SELECT
FROM tabe!2 WHERE FROM tabel3 WHERE
SELECT * FROM tbl_stoc ORDER BY ...
DROP TABLE tbl_stoc
Pentru versiunile de MySQL anterioare versiunii 3.23, ideea este similar, cu excepi faptului c trebuie s
declarai n mod explicit coloanele din tabelul tbl_stoc, i instruciunea DROP TABLE de la sfrit este
obligatorie, pentru a mpiedica existent tabelului dup sfritul perioadei de via a sesiunii client:
CREATE TABLE tbl_stoc (coloana? ..., coloana 2 ..., ...)
SELECT ... FROM tabel) WHERE ...
INSERT INTO tbl_stoc SELECT ... FROM tabel r WHERE ...
INSERT INTO tbl_stoc SELECT ... FROM tabel2 WHERE ...
INSERT INTO tbl_StOC SELECT ... FROM tabe!3 WHERE ...
SELECT * FROM tbl_StOC ORDER BY ...
DROP TABLE tbl_stoc
Adugarea unei coloane cu numere dintr-o secven
Dac folosii instruciunea ALTER TABLE pentru a aduga o coloan AUTO_INCREME> coloana este
completat automat cu numere dintr-o secven. Urmtorul set i instruciuni dintr-o sesiune mysql prezint
principiul de funcionare al acestei oper prin crearea unui tabel, inseria unor date n tabel i apoi adugarea unei
coloa AUTO_INCREMENT:
mysql> CREATE TABLE t(C CHAR(10)); '
mysql> INSERT INTO t VALUES("a"),("b"), ("C"); :
mysql> SELECT * FROM f, '
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 187
mysql> ALTER TABLE t ADD i INT AUTO_INCREMENT NOT NULL PRIMARY KEY mysql> SELECT *
FROM t;

Secvenierea1 sau resecvenierea unei coloane existente


Dac avei o coloan numeric, o putei secvenia (sau resecvenia dac a fost secvenial anterior, dar ai ters
rnduri i dorii s renumerotai valorile pentru ca acestea s fie contigui) astfel:
ALTER TABLE t MODIFY i INT NULL
UPDATE t SET i = NULL
ALTER TABLE t MODIFY i INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY Dar o
modalitate mai simpl de a efectua aceast operaie este de a terge pur i simplu coloana si de a o aduga din
nou, sub forma unei coloane AUTO_INCREMENT. Instruciunea ALTER TABLE permite specificarea mai
multor aciuni, deci toate aceste operaii se pot executa ntr-o singur instruciune:
ALTER TABLE t DROP i, ADD i INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY
Sortarea ntr-o ordine neobinuit
S presupunem c avei un tabel care conine personalul unei instituii sportive, cum ar fi o echip de fotbal:
dorii s sortai datele de ieire dup funcia membrilor personalului, astfel nct acestea s apar ntr-o anumit
ordine, cum ar fi urmtoarea: antrenor, antrenor secund, portari, fundai, mijlocai, atacani2. Definii coloana cu
tipul ENUM i menionai elementele enumerrii n ordinea n care dorii s le vedei. Rezultatele operaiilor de
sortare din coloana respectiv vor aprea n ordinea pe care o specificai.
Configurarea unui tabel contor
In seciunea Lucrul cu secvene" din capitolul 2, am prezentat modul de generare a unei secvene folosind
funcia LAST_INSERT_ID(expr). Exemplul de acolo ilustra modul de configurare a unui contor folosind un
tabel cu un singur rnd. Exemplul este foarte bun pentru un singur contor, dar, dac avei nevoie de mai multe
contoare, metoda respectiv duce la o multiplicare inutil a tabelelor. S presupunem c avei un sit Web i dorii
Adic transformarea unei secvene de numere fr nici o ordine ntr-o secven ordonat; prin ..resecveniere" se
va nelege revenirea la ordinea din secven, ordine alterat de o operaie sau alta. - N.T.
Am recurs la adaptarea" traducerii folosind posturile dintr-o echip de fotbal european, posturi mult mai
familiare cititorului romn dect cele din cadrul unei echipe de fotbal american, folosite de
autorul ediiei originale. - N.T.
188 Partea l Utilizarea general a sistemului MySQL
s inserai n mai multe pagini contoare de genul aceast pagin a fost deschis de nu ori". Probabil c nu dorii
s configurai un tabel contor separat pentru fiecare pagii care are un contor.
O modalitate de a evita crearea de tabele contor multiple este de a crea un singur tat cu dou coloane. O coloan
conine o valoare contor; cealalt conine numele contor lui. Putem folosi n continuare funcia
LAST_INSERT_ID(), dar vom determina rndii cruia i se aplic aceast funcie folosind numele contorului.
Tabelul se prezint astfei: CREATE TABLE contor
numr INT UNSIGNED,
nume VARCHAR(255) NOT NULL PRIMARY KEY
)
Numele este un ir, astfel nct putem apela un contor n orice mod dorim, motiv pe tru care l vom transforma n
coloan PRIMARY KEY pentru a preveni duplicarea numele Acest lucru presupune c aplicaiile care folosesc
tabelul convin asupra numelor pe cai le vor folosi. Pentru contoarele noastre din paginile Web, putem asigura
uniciti numelor contoarelor prin simpla utilizare ca nume de contor al unei pagini a nume cii de acces la
pagina respectiv din cadrul arborelui documentului. De exemplu, coi figurarea unui contor nou pentru pagina de
baz a sitului se realizeaz astfel:
INSERT INTO contor (nume) VALUES("index.html")
Aceast instruciune iniializeaz contorul denumit "index.html" cu valoarea ze Pentru a genera urmtoarea
valoare din secven, incrementai contorul n rndul ad vat al tabelului, dup care regsii-1 folosind funcia
LAST_INSERT_ID():
UPDATE contor
SET numr = LAST_INSERT_ID(numar-i-1) WHERE nume = "index.html"
SELECT LAST_INSERT_ID() O metod alternativ ar fi incrementarea contorului fr a folosi funcia
LAST_INSERT_IDf astfel:
UPDATE contor SET numr = numar+1 WHERE nume = "index.html"
SELECT numr FROM contor WHERE nume = "index.html"
Totui, metoda nu funcioneaz corect dac un alt client incrementeaz contorul duf emitei instruciunea
UPDATE i nainte de a emite instruciunea SELECT. Putei rezolva; problem delimitnd cele dou instruciuni
cu instruciunile LOCK TABLES i UNLOCK TA pentru a bloca ali clieni n timp ce folosii contorul. Dar
metoda LAST_INSERT_ID () aceeai operaie mult mai simplu. Deoarece valoarea sa este specific clientului,
ntotdeauna valoarea pe care ai inserat-o, nu pe cea a altui client, i nu trebuie s compli programul cu blocri
pentru a nu permite accesul altor clieni.
Verificarea existenei tabelului
Uneori este util s putem determina, din interiorul unei aplicaii, dac un tabel dat i sau nu. Pentru aceasta, putei
folosi oricare din urmtoarele instruciuni:
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 189
SELECT COUNT(*) FROM nume_tabel
SELECT * FROM nume_tabel WHERE 1=0
Fiecare din aceste instruciuni reuete dac tabelul exist, respectiv eueaz dac tabelul nu exist. Ele
reprezint interogri performante pentru aceast categorie de test si se execut foarte rapid, deci nu avei nevoie
de prea mult timp pentru a le rula. Aceast strategie este cea mai indicat pentru programele de aplicaie pe care
le scriei, deoarece putei testa succesul sau eecul interogrii i putei ntreprinde aciuni n consecin. Metoda
nu este deosebit de util ntr-un script de grup pe care l rulai din mysql, deoarece la apariia unei erori nu putei
face nimic altceva dect s terminai programul (sau s ignorai eroarea, dar atunci rularea interogrii nu mai are
nici un sens).
Caracteristici pe care MySQL nu le accept
Aceast seciune descrie caracteristici aflate n alte sisteme de baze de date i pe care MySQL nu le accept.
Seciunea de fa prezint caracteristicile care lipsesc si indic modaliti de a ocoli aceste omisiuni, acolo unde
este posibil, n general, caracteristicile lipsesc din MySQL deoarece au consecine negative asupra
performanelor. Numeroase articole din aceast list se afl pe lista de prioriti a dezvoltatorilor, n vederea
implementrii n msura timpului disponibil si cu presupunerea c pot fi implementate fr sacrificarea scopului
lor iniial, acela de a obine un nivel optim de performan.
Sabselecie. O subselecie este o instruciune SELECT imbricat ntr-o alt instruciune SELECT, cum este
cazul n urmtoarea interogare:
SELECT * FROM puncte
WHERE eveniment_id IN (SELECT eveniment_id FROM eveniment WHERE tip = "T") Subseleciile sunt
programate s apar n MySQL versiunea 3.24, moment n care nu vor mai constitui o omisiune. Pn atunci,
multe interogri care sunt scrise folosind subselecii pot fi redactate alternativ sub form de uniri. Vezi seciunea
Rescrierea subseleciilor sub form de uniri".
Tranzacii i nregistrare-revenire. O tranzacie este un set de instruciuni SQL care sunt executate unitar, f ar
ntrerupere din partea altor clieni. Caracteristica de nregistrare-revenire v permite s declarai c instruciunile
trebuie executate unitar sau deloc. Cu alte cuvinte, dac vreo instruciune din cadrul tranzaciei eueaz, toate
instruciunile executate pn n acel moment sunt anulate.
MySQL execut automat blocarea pentru instruciunile SQL individuale, pentru a preveni interaciunile dintre
clieni. (De exemplu, doi clieni nu pot scrie simultan n acelai tabel.) n plus, putei folosi LOCK TABLES i
UNLOCK TABLES pentru a grupa instruciunile ntr-un tot unitar, ceea ce v permite s efectuai operaii pentru
care controlul con-I curentei pentru o singur instruciune nu este suficient. Problema MySQL legate de
l tranzacii este aceea c sistemul nu va grupa n mod automat instruciunile, iar dum-
neavoastr nu putei efectua anularea (revenirea) instruciunilor dac vreuna eueaz. H Pentru a
vedea n ce mod pot fi utile tranzaciile, s presupunem c activai n dome-
niul vnzrilor de confecii i c actualizai nivelurile de inventar ori de cte ori vre-H unul din
agenii dumneavoastr de vnzri realizeaz o vnzare. Exemplul urmtor
190 Partea l Utilizarea general a sistemului MySQL
ilustreaz tipul de probleme care pot surveni atunci cnd mai muli ageni de vnz actualizeaz simultan baza de
date (presupunnd c inventarul iniial de cmi era i 47 de buci):
t1 Agentul l vinde trei cmi
t2 Agentul l regsete numrul total de cmi (47):
SELECT cantitate FROM inventar WHERE art = "cmaa" t3 Agentul 2 vinde trei cmi
t4 Agentul 2 regsete numrul total de cmi (47):
SELECT cantitate FROM inventar WHERE art = "cmaa" t5 Agentul l calculeaz noul nivel al
inventarului cu expresia 47-3=44 sil
stabilete numrul de cmi la 44:
UPDATE inventar SET cantitate = 44 WHERE art = "cmaa" te Agentul 2 calculeaz noul nivel al
inventarului cu expresia 47-2=45 :
stabilete numrul de cmi la 45:
UPDATE inventar SET cantitate = 45 WHERE art = "cmaa"
La sfritul acestei secvene de evenimente, ai vndut cinci cmi (asta-i bine), dar| inventar scrie 45 de buci,
n loc de 42 (asta nu-i bine). Problema este c, n cazul 1 care cutai valoarea inventarului ntr-o instruciune i
actualizai valoarea ntr-o , instruciune, avei o tranzacie cu instruciuni multiple. Aciunea ntreprins n a <
instruciune depinde de valoarea regsit n prima. Dar, dac se produc tranzacii M parate n intervale de timp
care se suprapun, instruciunile din fiecare tranzacie i ntrees i interfera una cu alta. ntr-o baz de date
tranzacional, instruciui fiecrui agent de vnzri pot fi executate ca o tranzacie, iar instruciunile AgentuW nu
vor executa dect dup finalizarea execuiei instruciunilor Agentului 1. n M) putei obine acelai efect n dou
moduri:
Soluie ocolitoare 1: Executai un grup de instruciuni ca pe un tot ur
Putei grupa instruciuni la un loc i le putei executa ca pe o unitate indivizii! delimitndu-le cu ajutorul
instruciunilor LOCK TABLES si UNLOCK TABLES: bk toate tabelele pe care trebuie s le folosii, emitei
interogrile si anulai bloca Aceast operaie interzice oricui altcuiva s foloseasc tabelele n timp ce ac sunt
blocate. Folosind blocarea tabelelor, situaia inventarului se prezint;
t1 Agentul l vinde trei cmi
t2 Agentul l obine o blocare i regsete numrul curent de cmi l
LOCK TABLES inventar WRITE
SELECT cantitate FROM inventar WHERE art = "cmaa" t3 Agentul 2 vinde dou cmi
t4 Agentul 2 ncearc s obin o blocare; aceast ncercare va eua, deoarece Agentul l deine deja o blocare:
LOCK TABLES inventar WRITE
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 191
t5 Agentul l calculeaz noua valoare a inventarului cu formula 47-3=44, stabilete numrul de cmi la 44 i
anuleaz blocarea:
UPDATE inventar SET cantitate = 44
WHERE art = "cmaa" UNLOCK TABLES t6 Acum, cererea pentru o blocare, formulat de Agentul 2,
reuete.
Agentul 2 regsete numrul total de cmi (44):
SELECT cantitate FROM inventar WHERE art = "cmaa" t7 Agentul 2 calculeaz noua valoare a
inventarului cu formula 44-2=42,
stabilete numrul de cmi la 42 i elibereaz blocarea:
UPDATE inventar SET cantitate = 42
WHERE art = "cmaa" UNLOCK TABLES
Acum, instruciunile din cele dou tranzacii nu se amestec una cu alta i nivelul inventarului este stabilit corect.
Vom folosi aici o blocare WRITE, deoarece este necesar s modificm tabelul inventar. Dac v rezumai la
citirea tabelelor, putei folosi n schimb o blocare READ. Aceasta permite altor clieni s citeasc tabelele n
timp ce dumneavoastr le folosii, dar i mpiedic s scrie n acestea.
n exemplul prezentat anterior, Agentul 2 probabil c nu va sesiza nici o scdere a vitezei, deoarece tranzaciile
sunt scurte i se vor executa rapid. Totui, ca regul general, este de dorit s evitai blocarea tabelelor pentru un
interval lung de timp.
Dac folosii mai multe tabele, trebuie s le blocai pe toate nainte de a executa interogrile grupate. Dac doar
citii dintr-un anumit tabel, totui, avei nevoie numai de o blocare a tabelului de tip citire, nu de una de tip
scriere. S presupunem c avei un set de interogri prin care dorii s facei unele modificri ntr-un tabel
inventar, i de asemenea dorii s citii unele date dintr-un tabel client, n acest caz, avei nevoie de o blocare la
scriere a tabelului inventar, respectiv de o blocare la citire a tabelului client:
LOCK TABLES inventar WRITE, client READ
UNLOCK TABLES
Aceast operaie impune ca dumneavoastr s executai personal blocarea, respectiv deblocarea tabelelor. Un
sistem de baze de date cu suport pentru tranzacii va efectua aceste aciuni n mod automat. Totui, aspectul
privind gruparea instruciunilor ca un tot unitar n vederea execuiei este acelai ca n cazul sistemelor de baze de
date tranzacionale.
i Soluie ocolitoare 2: Folosii actualizri relative, nu absolute. A doua modalitate de a rezolva problema
amestecului instruciunilor provenite din multiple tranzacii este eliminarea dependenei ntre instruciuni. Dei
acest lucru nu este ntotdeauna posibil, vom presupune c este posibil pentru exemplul nostru cu inventarul.
Pentru metoda de actualizare a inventarului folosit n soluia ocolitoare l, tranzacia const din cutarea valorii
curente a inventarului, calculul noii valori n funcie de numrul de cmi vndute i apoi actualizarea cifrei de
192 Partea l Utilizarea general a sistemului MySQL
inventar la noua valoare. Aceast operaie este posibil ntr-o singur etap, pri| simpla actualizare a numrului
de cmi relativ la valoarea sa curent:
11 Agentul l vinde trei cmi
12 Agentul l decrementeaz numrul de cmi cu trei:
UPDATE inventar SET cantitate = cantitate - 3 WHERE art = l "cmaa"
13 Agentul 2 vinde dou cmi
14 Agentul 2 decrementeaz numrul de cmi cu doi:
UPDATE inventar SET cantitate = cantitate - 2 WHERE art = "cmaa"
Dup cum se poate vedea, aceast metod nu necesit sub nici o form tranzac cu mai multe instruciuni si, ca
atare, nu este necesar blocarea tabelelor penal simularea caracteristicilor tranzacionale. Dac tipurile de
tranzacii pe care le-a folosit pn acum sunt similare celui prezentat mai sus, putei rezolva probleia fr a folosi
deloc tranzacii.
Exemplul precedent indic modul de evitare a necesitii" tranzaciilor nt anumit situaie. Aceasta nu
nseamn c nu exist i alte situaii cnd chiar es nevoie de tranzacii. Un exemplu caracteristic n acest sens
implic un transil financiar, cnd banii dintr-un cont sunt plasai ntr-un alt cont. S presupunem,! Marin i scrie
un cec lui Dorin pentru suma de 100 de dolari, iar Dorin Incase cecul. Contul lui Marin trebuie decrementat cu
100 de dolari, iar contul lui Dor trebuie incrementat cu aceeai sum:
UPDATE cont SET balana = balana - 100 WHERE nume = "Mrii UPDATE cont SET balana = balana +
100 WHERE nume = "Dorit! Dac se produce o cdere a sistemului ntre cele dou instruciuni, tranzacia <
incomplet. Un sistem de baze de date cu caracteristici autentice de tranzaciei de nregistrare-revenire este
capabil s rezolve aceast problem. (Cel puin i retic. S-ar putea s fii obligat s determinai tranzaciile care nu
au fost introdu! i s le emitei din nou, dar cel puin nu mai avei probleme cu jumtate tranzacii.) n MySQL,
putei determina starea tranzaciei la momentul c prin examinarea jurnalului de actualizare, dei acest lucru
impune o oa examinare manual a jurnalului.
Chei externe i integritate referenial. O cheie extern v permite s declarai i cheie dintr-un tabel este
corelat cu o cheie dintr-un alt tabel, iar integritatea refe ial v permite s impunei restricii n ceea ce privete
aciunile care pot fi efec n tabelul care conine cheia extern. De exemplu, tabelul puncte din baza noastrS| date
demonstrativ samp_db conine o coloan elev_id, pe care o folosim pent corela nregistrrile privind
punctajele cu elevii din tabelul elev. Colc puncte. elev_id ar fi declarat cheie extern, n sistemele de baze
de date care ace acest concept, si asupra acesteia s-ar impune restricia conform creia nu este per introducerea
unei nregistrri cu punctajul unui elev care nu exist n tabelul elevJ plus, se permite tergerea n cascad, n
sensul c, dac un elev ar fi ters din tat
Capitolul 3 Sintaxa i utilizarea SQL n MySQL 193
elev, toate nregistrrile cu punctajele obinute de elevul respectiv vor fi terse automat din tabelul puncte.
Cheile externe contribuie la pstrarea consecvenei datelor dumneavoastr si asigur o oarecare comoditate.
Motivele pentru care aceste chei nu sunt acceptate de MySQL se datoreaz cu precdere unor anumite efecte
negative ale cheilor externe asupra performanelor i a ntreinerii bazelor de date. (Manualul de referin
MySQL conine o list ntreag cu asemenea motive.) Reinei c acest punct de vedere n ceea ce privete cheile
externe este oarecum diferit de ceea ce vei gsi n literatura de specialitate din domeniul bazelor de date, unde
cheile externe sunt descrise folosind termeni precum esenial". Dezvoltatorii sistemului MySQL nu subscriu la
acest punct de vedere. Dac dumneavoastr o facei, cel mai bine este s avei n vedere alte sisteme de baze de
date n vederea furnizrii suportului pentru cheile externe. De exemplu, dac ntre datele dumneavoastr exist
relaii deosebit de complexe, nu dorii s fii responsabil cu implementarea acestor dependene n aplicaiile
dumneavoastr (chiar dac, aa cum se ntmpl frecvent, este vorba de ceva doar cu puin mai mult dect
adugarea de instruciuni DELETE suplimentare).
MySQL nu accept cheile externe, n afara situaiei cnd analizeaz clauzele FOREIGN KEY n instruciunile
CREATE TABLE. (Astfel, devine mai simpl portarea programelor SQL din alte sisteme de baze de date n
MySQL.) MySQL nu impune cheile externe ca pe o restricie i nici nu furnizeaz caracteristica de tergere n
cascad.
n mod frecvent, restriciile pentru a cror aplicare sunt folosite cheile externe nu sunt att de dificil de
implementat prin intermediul logicii de aplicaie. Uneori, nu este altceva dect o chestiune de abordare a
procesului de introducere a datelor. De exemplu, pentru a introduce nregistrri noi n tabelul nostru puncte, este
improbabil inseria unor punctaje obinute de elevi inexisteni. Evident, modul de inserie a unui set de punctaje
const n a ncepe cu o list de elevi din tabelul elev si apoi, pentru fiecare elev n parte, de a lua punctajul i de a
folosi numrul de identificare al elevului pentru a genera o nou nregistrare n tabelul puncte. Cu aceast
procedur, nu exist nici o posibilitate de a insera o nregistrare pentru un elev care nu exist. Nu vei inventa" o
nregistrare cu punctaje pentru a o insera n tabelul puncte.
Pentru a realiza efectul tergerilor n cascad, trebuie s le implementai cu propria dumneavoastr logic de
aplicaie. S presupunem c dorii s tergei elevul nr. 13. Aceasta mai nseamn c dorii s tergei toate
nregistrrile cu punctajele obinute de elevul respectiv, ntr-un sistem de baze de date care accept tergerile n
cascad, ai terge nregistrarea din tabelul elev i toate nregistrrile din tabelul puncte cu urmtoarea
instruciune:
DELETE FROM elev WHERE elev_id = 13
nregistrrile din tabelul puncte pentru elevul nr. 13 vor fi terse automat, n MySQL, efectuai personal tergerea
secundar, cu o instruciune DELETE explicit:
DELETE FROM elev WHERE elev_id = 13
DELETE FROM puncte WHERE elev_id = 13
* Proceduri stocate si declanatori. O procedur stocat este un program SQL care este compilat si stocat n
server. La acest program se poate face referire ulterior, fr a mai
194 Partea l Utilizarea general a sistemului MySQL
fi necesar ca programul s fie trimis de client i analizat din nou. De asemenea, nt procedur putei face
modificri care vor afecta orice aplicaie client care o folose Declanatorul permite activarea unei proceduri
stocate la producerea unui anur eveniment, cum ar fi tergerea unei nregistrri dintr-un tabel. De exemplu, put
recurge la aceast metod dac dorii s regenerai un sumar de natur complex care fcea parte nregistrarea,
pentru a pstra sumarul n stare actualizat. Un limt care s accepte proceduri stocate se afl pe lista de prioriti
a dezvoltatorilor MySQl
Vederi. O vedere este o entitate logic, entitate care se comport ca un tabel, dar : este tabel. Vederea asigur o
modalitate de a examina coloanele din tabele diferite cum toate acele coloane ar face parte din acelai tabel.
Uneori, vederile se nume tabele virtuale. i vederile se afl pe lista de prioriti a dezvoltatorilor sistemv
MySQL.
Privilegii i blocare Ia nivel de nregistrare. MySQL accept diferite nivele de prttj legii, de la privilegii globale
si pn la privilegii la nivel de baz de date, tabel i colc na. Totui, MySQL nu accept privilegii la nivel de
nregistrare. Totui, putei fol funciile GET_LOCK() si RELEASE_LOCK() n aplicaiile dumneavoastr
pentru a impl menta blocrile cooperative la nivel de nregistrare. Procedura de aplicare a ace metode este
descris n rubrica aferent funciei GET_LOCK() din Anexa C, Refer de operatori i funcii".
Utilizarea caracterului - - ca i comentariu. Acest stil de comentariu nu este ace tat, deoarece reprezint o
construcie ambigu, dei, ncepnd cu MySQL 3.23.3, j comentariu care ncepe cu dou liniue si un spaiu este
acceptat. Vezi seciv Scrierea comentariilor" pentru mai multe informaii.
CAPITOLUL 4
Optimizarea interogrilor
Lumea teoriei bazelor de date relaionale este o lume dominat de tabele i seturi, precum i de operaii cu tabele
i seturi. O baz de date este un set de tabele, iar un tabel este un set de rnduri i coloane. Cnd emitei o
interogare SELECT pentru a regsi rnduri dintr-un tabel, obinei un alt set de rnduri i de coloane. Acestea
sunt noiuni abstracte, care nu fac nici un fel de referire la reprezentarea fundamental pe care o folosete un
sistem de baze de date pentru a opera cu datele din tabelele dumneavoastr. O alt abstractizare este aceea c
operaiile dintr-un tabel se produc toate simultan; interogrile sunt conceptualizate ca fiind operaii cu seturi, iar
n teoria seturilor nu exist conceptul de timp.
Lumea real, evident, este total diferit. Sistemele de gestiune a bazelor de date implementeaz concepte
abstracte, dar implementarea se produce folosind componente hardware reale, limitate de restricii autentice de
natur fizic, n consecin, interogrile necesit timp -uneori un timp agasant de lung. Iar nou, creaturi
nerbdtoare, nu ne place s ateptm, deci lsm n pace lumea abstract a operaiilor matematice instantanee
cu seturi i cutm modaliti de a mri viteza interogrilor. Din fericire, exist numeroase tehnici n acest sens.
Indexm tabelele pentru a permite serverului de baze de date s caute rndurile mai rapid. Concepem interogrile
de aa manier nct s beneficiem la maximum de aceste indexuri. Scriem interogri care s influeneze
mecanismul de planificare al serverului astfel nct interogrile care sosesc de la mai muli clieni s coopereze
mai bine. Ne gndim la ceea ee se ntmpl cu acele componente hardware de baz i la modul n care putem
ocoli restriciile fizice impuse acestora n vederea mbuntirii performanelor.
Acestea sunt categoriile de probleme asupra crora se va concentra capitolul de fa, cu scopul de a v asista la
optimizarea performanei sistemului dumneavoastr de baze de date astfel nct acesta s v prelucreze
interogrile ct mai rapid posibil. MySQL este deja foarte rapid, dar chiar i cel mai rapid sistem de baze de date
poate rula interogrile mai rapid dac l ajutai.
Utilizarea indexrii
\
Vom ncepe cu indexarea, deoarece este cel mai important instrument pe care-1 avei la dispoziie pentru
accelerarea interogrilor dumneavoastr. Avei la dispoziie i alte tehnici, dar, n general, elementul care va
determina cea mai semnificativ diferen l constituie utilizarea adecvat a indexurilor, n lista de coresponden
MySQL, oamenii cer adesea ajutor pentru a determina o interogare s ruleze mai rapid, ntr-un numr sur-
196 Partea l Utilizarea general a sistemului MySQL
prinztor de mare de cazuri, tabelele n chestiune nu conin nici un fel de indexuri, ia adugarea indexurilor duce
deseori la rezolvarea imediat a problemei. Aceast metc nu funcioneaz ntotdeauna, deoarece optimizarea nu
este ntotdeauna un proces ir piu. Totui, dac nu folosii indexuri, n multe situaii v pierdei vremea ncercnd
mbuntii performanele prin alte mijloace. Utilizai mai nti indexarea, pentnl obine cel mai mare salt de
performan, dup care ncercai s vedei care dintre cete lalte tehnici ar putea fi util.
Aceast seciune descrie noiunea de index, modul n care acesta mbuntete performant interogrilor,
situaiile n care indexurile pot afecta n mod negativ performanele, precum \ modul de alegere a indexurilor
pentru tabelele dumneavoastr, n seciunea urmtoare, vc discuta despre utilitarul MySQL de optimizare a
interogrilor. Pe lng cunoaterea modi de creare a indexurilor, este bine s nelegei ntr-o oarecare msur
noiunile privind utili tarul de optimizare, deoarece atunci vei putea beneficia mai bine de indexurile pe carej|
creai. Unele moduri de scriere a interogrilor anihileaz utilitatea indexurilor si, n gene dorii s evitai aceste
situaii. (Nu ntotdeauna, ns. Uneori vei dori s ignorai compor utilitarului de optimizare. Vom discuta i
despre unele din aceste situaii.)
Avantajele indexrii
S vedem cum funcioneaz un index pornind de la un tabel care nu are indexuri, tabel fr indexuri este pur i
simplu o colecie dezordonat de rnduri. De exempli figura 4.1 prezint tabelul reclama pe care 1-am vzut
anterior n capitolul l, Introdij cere n MySQL si SQL". Acest tabel nu conine indexuri, deci, n cazul n care
caut rndurile aferente unei anumite companii, trebuie s examinm fiecare rnd din tat pentru a vedea dac
rndul respectiv conine valoarea dorit. Aceasta implic o balei* complet a tabelului, ceea ce reprezint o
operaie lent si nfiortor de ineficient da tabelul conine numai cteva nregistrri care corespund criteriilor de
cutare.
Figura 4.2 prezint acelai tabel, la care s-a adugat un index pentru coloana num_ce panie din tabelul reclama.
Indexul conine o intrare pentru fiecare rnd din tabel reclama, dar intrrile indexului sunt sortate n funcie de
valoarea din coloana num_c6JI panie. Acum, n loc s cutm rnd cu rnd pentru a gsi articolele care
corespund < teriilor de cutare, putem folosi indexul. S presupunem c am cuta toate rndul aferente
companiei 13. ncepem s cutm n index i gsim trei rnduri aferente cot, panici respective. Apoi, ajungem la
rndul aferent companiei 14, valoare mai mare de cea pe care o cutm. Valorile indexului sunt sonate, deci,
atunci cnd citim o nref trare care conine numrul 14, nu vom mai gsi echivalene cu criteriile de cutar putem
sista cutarea. Dac am fi cutat o valoare care nu apare dect undeva pe mijlocul tabelului indexat, exist
algoritmi de poziionare care gsesc prima intrare^ index care corespunde criteriilor de cutare fr a executa o
baiv^re liniar a tabelt (de exemplu o cutare binar). Astfel, ne putem poziiona rapid pe prima valoare
corespunde criteriilor de cutare si putem economisi foarte mult timp de caut Sistemele de baze de date folosesc
diverse tehnici de poziionare pentru indexarea rap a valorilor, dar deocamdat nu ne intereseaz tehnicile
respective. Este important i funcioneaz i c indexarea este un lucru bun.
Capitolul 4 Optimizarea interogrilor 197
Poate v ntrebai: de ce nu se sorteaz fiierul de date, dup care se terge fiierul de index? Nu s-ar produce
aceeai mbuntire a vitezei de cutare? Avei dreptate, s-ar produce - dac ai fi avut un singur index. Dar
putei dori un al doilea index i nu putei sorta fiierul de date n dou moduri diferite simultan. (De exemplu,
dorii un index dup numele clienilor i un alt index dup numerele de identificare sau numerele de telefon ale
acestora.) Utilizarea indexurilor ca entiti separate de fiierul de date rezolv problema i permite crearea mai
multor indexuri. De asemenea, rndurile din index sunt, n general, mai scurte dect rndurile de date. Cnd
inserai sau tergei valori noi, este mai uor s mutai valori scurte din index pentru a pstra ordinea de sortare
dect s v deplasai n rndurile de date mai lungi.
tabelul reclama
num_companie num reclama taxa deschidere
14 48 0.01
23 49 0.02
17 52 0.01
13 55 0.03
23 62 0.02
23 63 0.01
23 64 0.02
13 77 0.03
23 99 0.03
14 101 0.01
13 102 0.01
17 119 0.02
Figura 4.1 Tabelul reclama fr index.
num_companie num_reclama taxa_deschidere
14 48 0.01
23 49 0.02
17 52 0.01
13 55 0.03
23 62 0.02
23 63 0.01
23 64 0.02
13 77 0.03
23 99 0.03
14 101 0.01
13 102 0.01
17 119 0.02
Figura 4.2 Tabelul reclama indexat.
Exemplul corespunde modului de indexare a tabelelor n MySQL. Rndurile de date ale unui tabel sunt pstrate
"ntr-un fiier cu date, iar valorile din index sunt pstrate ntr-un fiier index. Putei avea mai multe indexuri ntr-
un tabel; n acest caz, toate indexurile sunt stocate n acelai fiier index. Fiecare index din fiierul index const
dintr-un tablou sortat cu nregistrri cheie care sunt folosite pentru un acces rapid la fiierul de date.
198 Partea l Utilizarea general a sistemului MySQL
Expunerea anterioar a prezentat avantajele unui index n contextul interogrilor ntr-u] singur tabel, acolo unde
utilizarea unui index mrete semnificativ viteza de caut prin eliminarea necesitii de baleiere complet a
tabelului. Totui, indexurile sunt si i valoroase atunci cnd rulai interogri care implic uniri pe tabele multiple.
Intr interogare cu un singur tabel, numrul de valori pe care trebuie s le examinai n fie coloan este egal cu
numrul de nregistrri din tabel, ntr-o interogare pe tabele multa ple, numrul combinaiilor posibile creste
ameitor, deoarece este egal cu produs numerelor de rnduri ale tabelelor.
S presupunem c avei trei tabele fr index, si anume t1, t2 si t3, coninnd respec coloanele c1, c2 i c3 i cte
1000 de rnduri care conin numerele cuprinse ntre l i 1C (Exemplul este exagerat, desigur. Nu-1 folosim dect
pentru a trage o concluzie; cu toaf acestea, problemele pe care le vom ilustra sunt reale.) O interogare pentru
regsirea tutur combinaiilor ntre acele rnduri ale tabelelor care conin valori egale arat astfel:
SELECT C1, c2, C3
FROM t1, t2, t3
WHERE c1 = c2 AND c1 = C3 Rezultatul acestei interogri trebuie s fie compus din 1000 de rnduri, fiecare
rar coninnd trei valori egale. Dac prelucrm interogarea n absena indexurilor, nu vor avea nici o idee cu
privire la valorile incluse n fiecare rnd. n consecin, trebuie ncercm toate combinaiile pentru a le gsi pe
cele care corespund criteriilor din clau WHERE. Numrul de combinaii posibile este 1000 x 1000 x 1000 (l
miliard!), adic de i milion de ori mai mare dect numrul rndurilor care corespund criteriilor de cuta Asta
nseamn un volum extrem de mare de efort irosit si probabil c aceast interoga va fi foarte lent, chiar si pentru
un sistem de baze de date precum MySQL, care es foarte rapid. Iar asta se ntmpl pentru un tabel cu numai
1000 de rnduri. Ce ne face n situaiile cnd avei tabele cu milioane de rnduri? Putei vedea c astfel se ajungfl
foarte rapid la performane extrem de reduse. Dac indexm fiecare tabel, putem m considerabil viteza de
prelucrare a interogrilor, deoarece indexarea permite prelucrare interogrii n acest mod:
1. Selecteaz primul rnd din tabelul t1 i citete valoarea pe care o conine rndul.
2. Folosind indexul din tabelul t2, se deplaseaz direct la rndul care corespunde valor din tabelul t1. Similar,
folosind indexul din tabelul t3, se deplaseaz direct la rndii care corespunde valorii din tabelul t1.
3. Trece la urmtorul rnd din tabelul t1 i repet procedura anterioar pn cnd es mineaz toate rndurile din
tabelul t1.
n acest caz, se execut totui o parcurgere complet a tabelului 11, dar putem execut cutri indexate n tabelele
t2 i t3 pentru a extrage direct rndurile din aceste tabele, f acest mod, interogarea ruleaz efectiv de un milion
de ori mai repede.
MySQL folosete indexurile aa cum s-a artat mai sus, pentru a mri viteza de caut a rndurilor care satisfac
criteriile unei clauze WHERE, respectiv a rndurilor care core pund rndurilor din alte tabele, atunci cnd se
efectueaz uniri. De asemenea, MySC folosete indexuri i pentru a mbunti performanele altor tipuri de
operaii:
Capitolul 4 Optimizarea interogrilor 199
Valoarea cea mai mic sau cea mai mare a unei coloane indexate se poate gsi rapid, fr a se examina fiecare
rnd atunci cnd folosii funciile MIN ( ) sau MAX( ) .
MySQL poate folosi frecvent indexuri pentru a efectua rapid operaii de sortare pentru clauzele ORDER BY.
Uneori, MySQL poate evita complet citirea fiierului de date. S presupunem c selectai valori dintr-o coloan
numeric indexat si c nu selectai alte coloane din tabel. n acest caz, prin citirea unei valori din index, ai
obinut deja valoarea care ar fi rezultat din citirea fiierului de date. Nu are nici un sens s citii valorile de dou
ori, deci nu este necesar nici mcar consultarea fiierului de date.
Dezavantajele indexrii
n general, dac MySQL poate determina modul de utilizare a unui index pentru a prelucra o interogare mai
rapid, o va face. Aceasta nseamn c, n majoritatea cazurilor, dac nu v indexai tabelele, ieii n pierdere. Ai
vzut c am zugrvit o imagine roz a avantajelor indexrii. Exist i dezavantaje? Da, exist, n practic, aceste
neajunsuri tind s fie contrabalansate de avantaje, dar trebuie s le cunoatei i pe acestea.
Mai nti, fiierul index ocup spaiu pe disc. Dac avei numeroase indexuri, fiierul index poate ajunge la
dimensiunea maxim mai rapid dect fiierul de date. n al doilea rnd, indexurile mresc viteza operaiilor de
regsire, dar o reduc pe aceea a operaiilor de inserie si tergere, precum i viteza operaiilor de actualizare a
valorilor din coloanele indexate (adic majoritatea operaiilor care implic scriere), deoarece o scriere afecteaz
nu numai rndul de date, dar i indexurile, n majoritatea cazurilor. Cu ct un tabel are un numr mai mare de
indexuri, cu att nivelul mediu de degradare a performanelor pentru operaiile de scriere este mai mare. n
seciunea ncrcarea eficient a datelor" vom aborda mai detaliat aceast problem de performan i
modalitile de rezolvare.
Alegerea indexurilor
Sintaxa de creare a indexurilor a fost prezentat n seciunea Crearea si tergerea indexurilor" din capitolul 3,
Sintaxa i utilizarea SQL n MySQL". Voi presupune c ai citit seciunea respectiv. Dar simpla cunoatere a
sintaxei nu v ajut s determinai modul n care trebuie indexate tabelele dumneavoastr. Acesta impune o
gndire a modului n care v vei folosi tabelele. Aceast seciune ofer unele indicaii n ceea ce privete
identificarea i selectarea coloanelor adecvate pentru indexare:
Indexai coloanele pe care le cutai, nu coloanele pe care le selectai. Cu alte cuvinte, coloanele cele mai
potrivite pentru indexare sunt coloanele care apar n clauza WHERE, respectiv coloanele specificate n clauzele
de unire, nu coloanele care apar n lista de selecie imediat urmtoare cuvntului cheie SELECT:
SELECT
col_a FROM
tabell LEFT JOIN tabe!2
ON tabell.col b = tabe!2.col c
coloana nu este adecvat
coloane adecvate
f-c-.X
^Av

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