DAY 3
Instructor: Sanda Popescu
SECTIUNE 1/ DATABASE PROGRAMMING
INTRODUCTION TO FUNCTION SINGLE ROW FUNCTION
Exista 2 tipuri de functii:
• SINGLE ROW FUNCTION – care returneaza un singur rezultat pe
linie
• MULTIPLE ROW FUNCTION – care returneaza un singur rezultat pe un
anumit grup de linii
Posibilitati de transformare a datelor pentru a se potrivi unor situatii particulare
Single-row functions
Multiple-row functions:
Se afiseaza cel mai
mare salariu, cel
mai mic salariu si
media salariilor
angajatilor.
Exemple:
Se foloseste atunci cand avem de
efectuat calcule care nu sunt
legate de un tabel al bazei de date
Are o singura coloana numita
DUMMY si o singura linie cu
valoarea X
Exemplu de utilizare a
operatorului de
concatenare || cu functia
INITCAP
SUBSTR(sir_sursa,poz_inc,nr_car)
Ex. : SUBSTR(‘Test extragere’,2,3)=> va returna “est”
SUBSTR(‘Test extragere’,-5,4)=> va returna “ager” de la sf.catre inceput
CONCAT(sir1,sir) / unde sir1, sir2 pot fi si nume de coloane
CONCAT(‘Test’,’concatenare’ => Test concatenare
LPAD- completeaza in partea stanga cu un caracter specificat
RPAD- completeaza in partea dreapta cu un caracter specificat
Both -implicit
INSTR(sir_sursa,caracter,poz_de_unde_incep_cautarea,a_cata_aparitie_o_caut)
Returneaza pozitia unui caracter intr-un sir
INSTR(‘Mississippi’,’i’,1,3) =>8
INSTR(‘Mississippi’,’s’,8,3) =>0
REPLACE (string1,string_to_replace,[replacement_string])
select replace('Oracle Internet Academy','Oracle','Test') as test
from dual =>
select replace('Oracle Internet Academy','Oracle') as
test
from dual =>
TRY IT / SOLVE IT
TRY IT / SOLVE IT
ROUND(45.926,2) => 45.93
ROUND(45.926,-1) => 50
round(45.35,-3) => 0
round(65.35,-3) => 0
round(45.35,4) => 45.35
Observatie: ROUND
SI TRUNC pot fi
utilizate si pe tipul de
data calendaristica
select trunc(45.35,-3) test
from dual => 0
3. select trunc(45.35,1) test
from dual => 45.3
1. select trunc(45.35,3) test
from dual => 45.35
2. Implicit 0 zecimale
select trunc(45.35,-1) test
from dual => 40
TRY IT / SOLVE IT
DATE CALENDARISTICE ( DATE)
secolul curent este selectat in
functie de data serverului bazei
de date
Intern, anul dintr-o data
calendaristica este memorata
pe 4 cifre : 2 cifre pentru secol
si 2 cifre pentru an
Observatie : numai functia Months_Between returneaza un
numar, restul functiilor returneaza date calendaristice
select add_months(sysdate,6) test
from dualSYSDATE= ’21-03-07’
select TRUNC(sysdate,'YEAR') test
from dual
select TRUNC(sysdate,‘MONTH') test
from dual
Observatii: TRUNC si ROUND se
pot aplica datelor calendaristice
select TRUNC(sysdate,‘DAY') test
from dual =>
Observatie: anumite sisteme de
calcule recunoasc numele lunilor
(sau a zilelor sapatamanii numai in
lb.romana)
select round(sysdate,'YEAR') TEST
from dual
SYSDATE= ’21-03-07’
select round(sysdate,‘MONTH') TEST
from dual => Se analizeaza ziua (21 >15) si
se rotunjeste luna
select round(TO_DATE('21-08-2007','DD-MM-RRRR'),'YEAR') TEST
from dual se analizeaza luna si se rotunjeste anul
select trunc(TO_DATE('21-08-2007','DD-MM-RRRR'),'YEAR') TEST
from dual
select trunc(TO_DATE('21-08-2007','DD-MM-RRRR'),‘MONTH') TEST
from dual
select round(TO_DATE('21-08-2007','DD-MM-RRRR'),‘MONTH') TEST
from dual se analizeaza ziua si se rotunjeste luna
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
SECTIUNE 2
OBSERVATII
Exista in jur de 14 tipuri de date
VARCHAR2 – lungine vb.maxim 4000 de caractere
CHAR – lungime fica maxim 2000 de caractere
NUMBER- nr.reale, cu precizie 38 de cifre zecimale
DATE – data calendaristica ,format DD-MON-RR (YY)
CONVERSII EXPLICITE
• formatul model tb. sa fie inclus in ‘ ‘ si este case-sensitive
• valorile de date din formatul model tb sa fie separate prin virgula
• orice format de date valid poate fi inclus
• utilizeaza un element fm pentru a ignora blank-urile sau a zerourile din fata numarului
• utilizeaza un element sp pentru a scrie un numar asa cum se citeste
• utilizeaza un element th pentru a specifica un numar ordinal (specific lb. engleze)
• utilizeaza “ “ pentru a adauga un string in formatul model
select TO_CHAR(sysdate,'"ziua"dd,"luna",month,"anul",year') TEST
from dual
select TO_CHAR(sysdate,'"ziua "ddsp "luna" mm "anul" yyyy') TEST
from dual
select TO_CHAR(sysdate,'dd-mon-yy') TEST
from dual
NOTA: daca doresc sa introduc un
comentariu (un sir…) atunci folosesc “ ”
select TO_CHAR(4352.53,'99.9eeee') TEST
from dual
select TO_CHAR(4352.53,'09999.9999') TEST
from dual
select TO_CHAR(-4352.53,'9999.999PR') TEST
from dual
select TO_CHAR(-4352.53,'9999.999MI') TEST
from dual
select TO_NUMBER(TO_CHAR(sysdate,'DDMMYY')) test
from dual
SYSDATE =22.03.2007
OBS.: daca formatul ar fi fost fmddmmyy =>2237 s-ar fi
ignorat zerourile din fata fiecarei componente(zi,luna,an)
SELECT TO_NUMBER('453.88') TEST
from dual
SELECT TO_NUMBER('453') TEST
from dual => formatul standard poate lipsi daca
numarul nu are zecimale
Oracle afiseaza # (??) in locul intregului numar ale carui cifre
depasesc numarul total de cifre furnizat in formatul model si
rotunjeste numerele la un anumit nr. de zecimale ca in formatul
model
SELECT TO_NUMBER('45000','99') TEST
from dual
select TO_DATE('22Mai 2007','fxDDMonth RRRR') test
from dual
select TO_DATE('22-MaR-2007','DD-Mon-RR') test
from dual
select TO_DATE('22,MaRtie,2007','fxDD,Month,rrrr') test
from dual
select TO_DATE('22032007','fxDDMMRRRR') test
from dual
select TO_CHAR(TO_DATE('22032007','fxDDMMRRRR'),'Month ddsp year') test
from dual
select TO_CHAR(TO_DATE('22032007','fxDDMMRRRR'),'Month ddth year') test
from dual
SELECT TO_CHAR(SYSDATE,'Month') test
from dual
SELECT TO_CHAR(SYSDATE,‘yyyy') test
from dual
SELECT TO_CHAR(SYSDATE,‘DD') test
from dual
Extrage luna,an, zi dintro
data calendaristica
SELECT TO_CHAR(SYSDATE,‘year') test
from dual
OBSERVATII OPERATII DATE CALENDARISTICE
SYSDATE =22.03.2007
select (sysdate+60) test
from dual
select TO_DATE('31-12-07','fmdd-mm-yy')-sysdate test
from dual
select (TO_DATE('31-12-07','fmdd-mm-yy')-sysdate)/7 test
from dual
select TO_DATE('31-12-07','fmdd-mm-yy')+sysdate test
from dual
RECAPITULARE FUNCTII
Formatele pentru an RR si YY
Tabelul ilustreaza
formatul RR sau
RRRR
Format YY
sau YYYY –
acelasi secol al
anului curent
retine
Daca formatul de date
specificat este YYYY,
secolul pentru valoarea
returnata va corespunde
cu secolul anului curent.
Deci, daca anul este 1995
si tu folosesti formatul YY
sau YYYY iar anul curent
este 2007, atunci se va
afisa 2095, iar pe formatul
este RRRR atunci va afisa
1995
Example of RR Date Format
To find employees hired prior to 1990, use the RR
format, which produces the same results whether the
command is run in 1999 or now:
SELECT last_name, TO_CHAR(hire_date, ’DD-Mon-YYYY’)
FROM employees
WHERE hire_date < TO_DATE(’01-Jan-90’, ’DD-Mon-RR’);
The following command, on the other hand, results in no rows being
selected because the YY format
interprets the year portion of the date in the current century (2090).
SELECT last_name, TO_CHAR(hire_date, ’DD-Mon-yyyy’)
FROM employees
WHERE TO_DATE(hire_date, ’DD-Mon-yy’) < ’01-Jan-1990
TRY IT / SOLVE IT
TRY IT / SOLVE IT
FUNCTII GENERALE
Functii care permit conversia
valorilor Null
These functions work with any data type and pertain
to using nulls.
• NVL (expr1, expr2)
• NVL2 (expr1, expr2, expr3)
• NULLIF (expr1, expr2)
• COALESCE (expr1, expr2, ..., exprn
ATENTIE: la tipul de date
Trebuie sa fie tipuri compatibile
de date
NVL – poate fi utilizata
pentru conversia unei
valori NULL intr-un
numar inainte de a intra in
calculul expresiei.
Daca un operator din
cadrul expresiei este
NULL atunci rezultatul va
fi NULL
NVL2(EXP1,EXP2,EXP3)
Daca exp1 IS NOT NULL atunci functia returneaza EXP2
altfel returneaza EXP 3
EXP1 poate fi orice tip de date
EXP2 si EXP3 pot fi orice tip de date cu exceptia lui LONG
OBS: tipul de date returnat este intotdeauna la fel cu tipul de
date al EXP2, mai putin cazul in care returneaza VARCHAR2
SELECT last_name, salary, commission_pct,
NVL2(commission_pct,salary+(salary*commission_pct),salary) income
FROM copy_employees
UPDATE copy_employees
SET commission_pct=0.3
where lower(last_name)='king'
Daca exp1 IS NOT NULL atunci functia returneaza EXP2
altfel returneaza EXP 3
NVL2(EXP1,EXP2,EXP3)
Daca exp1=exp2 atunci returneaza NULL
altfel returneaza exp1
O extensie a functiei NVL cu diferenta ca pot exista mai multe valori
Daca prima expresie IS NOT NULL atunci functia va returna prima expresie
altfel cauta prima valoare diferita de NULL
SELECT last_name, salary, commission_pct,
COALESCE(commission_pct,salary+(salary*commission_pct),10) test
FROM employees
SELECT last_name, salary, commission_pct,
COALESCE(to_char(commission_pct),NULL,'Atentie la compatibilitatea de tip') test
FROM employees
TRY IT / SOLVE IT
TRY IT / SOLVE IT
Conditional Expressions• Provide the use of IF-THEN-ELSE logic within a SQL statement
Use two methods:
– CASE expression
–DECODE functionConditional Expressions
Two methods used to implement conditional processing (IF-THEN-ELSE logic)
within a SQL statement are the CASE expression and the DECODE function.
Note: The CASE expression is new in the Oracle9i Server release.
The CASE expression complies with ANSI SQL; DECODE is
specific to Oracle syntax
Atentie la compatibilitatea de tip
DECODE este proprietate ORACLE
CASE –standard ANSI SQL
Using the CASE Expression
Facilitates conditional inquiries by doing the work of
an IF-THEN-ELSE statement:
SELECT last_name, job_id, salary,
CASE job_id WHEN ’IT_PROG’ THEN 1.10*salary
WHEN ’ST_CLERK’ THEN 1.15*salary
WHEN ’SA_REP’ THEN 1.20*salary
ELSE salary END "REVISED_SALARY"
FROM employees;
The DECODE FunctionThe DECODE function decodes an expression in a way similar to the IF-THEN-ELSE
logic used in various languages. The DECODE function decodes expression after
comparing it to each search value. If the expression is the same as search, result is
returned.
SELECT last_name, job_id, salary,
DECODE(job_id, ’IT_PROG’, 1.10*salary,
’ST_CLERK’, 1.15*salary,
’SA_REP’, 1.20*salary,
salary) /* salary valoare implicita
REVISED_SALARY /* alias
FROM employees;
Using the DECODE Function
In the preceding SQL statement, the value of JOB_ID is tested. If JOB_ID is IT_PROG,
the salary increase is 10%; if JOB_ID is ST_CLERK, the salary increase is 15%; if
JOB_ID is SA_REP, the salary increase is 20%. For all other job roles, there is no
increase in salary.
The same statement can be expressed in pseudocode as an IF-THEN-ELSE statement:
IF job_id = ’IT_PROG’ THEN salary = salary*1.10
IF job_id = ’ST_CLERK’ THEN salary = salary*1.15
IF job_id = ’SA_REP’ THEN salary = salary*1.20
ELSE salary = salary
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
SECTIUNILE 3 - 4
JOIN(JONCTIUNE)
REALIZAREA RAPOARTELOR UTILIZAND
DATE DIN TABELE DIFERITE
Oracle Proprietary
• Equijoin
• Non-equijoin
• Outer join
• Self joinSQL: 1999
• Cross joins
• Natural joins
• Using clause
• Full or two sided outer joins
Pentru a conecta impreuna datele
din mai multe tabele, poti folosi 2
seturi de comenzi sau sintaxe:
In interogarea datelor din mai mult decat o tabela folosind
sintaxele proprietate ORACLE foloseste o conditie de join in
clauza WHERE
Formatul de baza al unei declaratii de join
Pentru claritate se recomanda prefixarea coloanelor cu numele tabelei.
Combinatia dintre numele tabelei si numele coloanei elimina ambiguitatile
de nume. Ce se intimpla daca 2 tabele au acelasi nume de coloana?
(Ex.#id)
Use a join to query data from more than one table.
• Write the join condition in the WHERE clause.
• Prefix the column name with the table name when
the same column name appears in more than one table.
To join n tables together, you need a minimum of n-1
join conditions. For example, to join three tables, a
minimum of two joins is required.
EMPLOYEES
DEPARTMENTS
Conditia de join se va bazaintotdeauna pe o coloanacu aceleasi tipuri de date sicu aceeasi semnificatie, deobicei pe o FK provenitadintro relatie intre 2 tabele
Department_id este FK inemployees si a provenit dinrelatia M:1 cu departments
Manager_id este FK provenit din relatia recursiva
Combina liniile care au valori echivalente pentru coloanele specificate
operatorul =
• Use table prefixes to qualify column names that
are in multiple tables.
• Improve performance by using table prefixes.
• Distinguish columns that have identical names but
reside in different tables by using column aliases.
• Simplify queries by using table aliases.
SELECT e.employee_id, e.last_name, e.department_id, d.department_id, d.location_id
FROM employees e , departments d
WHERE e.department_id = d.department_id;
Guidelines
• Table aliases can be up to 30 characters in length, but shorter is better.
• If a table alias is used for a particular table name in the FROM clause, then that table alias
must be substituted for the table name throughout the SELECT statement.
• Table aliases should be meaningful.
• The table alias is valid only for the current SELECT statement.
select first_name,last_name,department_namefrom employees e, departments dwhere e.department_id=d.department_id
ATENTIE!
Se poate si asa, dar nu se recomanda
• Foloseste prefixarea pentruetichetarea numelor de coloanecare sunt in tabele multiple
• Imbunatateste performanta
• Coloane distincte care au numeidentice dar apartin unor tabelediferite
select first_name,last_name,department_namefrom employees , departments where employees.department_id=departments.department_id
select employees.first_name,employees.last_name,departments.department_namefrom employees , departments where employees.department_id=departments.department_id
1. Sa se afiseze numele angajatilor si departamentele unde lucreaza fiecare angajat
Sau fara prefixarea coloanelor in clauza SELECT
2. Sa se afiseze numele angajatilor care lucreaza in departamentul 90
Conditie suplimentara de restrictionare a liniilor afisate
Join cu 3 tabele
Daca in clauza Where conditia este invalida(saulipseste WHERE) atunci serverul Oracle returneazaprodusul cartezian al celor 2 tabele
Pentru a evita produsul cartezian, includeintotdeauna o conditie valida in clauza WHERE
Nr.linii returnate =
nr.linii tabela 1*nr.linii tabela 2
d_songs
d_themes
Produs cartezian
Obs.: Where p.id IN(47,48) arestrictionat numarul de linii la 16, altfelnumarul de linii afisate ar fi fost 8*6=48
TRY IT / SOLVE IT
TRY IT / SOLVE IT
Se utilizeaza atunci cand datele dintro tabela nu corespund exact cu datele
din alta tabela.(se gasesc intre niste limite de valori din cealalta tabela)
Ex: O companie isi plateste angajatii in functie de timpul
lucrat masurat in ore si minute, incrementand la fiecare 15
minute.
O tabela memoreaza orele si minutele lucrate, iar intro alta
tabela avem modul de plata in functie de timpul lucrat.
Daca un angajat lucreaza 40 de minute, atunci va fi platit cu
45 de centi (intervalul [31,45] )
De vreme ce nu exista o potrivire
exacta intre cele 2 coloane atunci
operatorul = nu poate fi folosit.
Desi pot fi folositi operatorii <= si
>=, se recomanda operatorul
BETWEEN..AND
select p.first_name,p.salary,t.grade_levelfrom employees p,job_grades twhere p.salary between t.lowest_sal and t.highest_sal
Sunt mai mult de 10 linii care ar trebui afisate.
sau
TRY IT / SOLVE IT
Un Outer Join este folosit
pentru a afisa atat liniile care
au valori corespondente in
alta tabela (valori
echivalente) plus liniile care
nu au valori corespondente
in alta tabela. Mentioneaza ce
tabela poate avea date lipsa
cu un semn (+) dupa numele
tabelei careia ii lipsesc date.
Se vor afisa departamente cu sau fara angajati
Semnul (+) la angajati =>
lipsesc date din angajati
Se vor afisa angajati cu sau fara departamente
Semnul (+) la departamente => lipsesc date din departamente
Atentie in Order By => NULL este primul la ordonarea descrescatoare
TRY IT / SOLVE IT
TRY IT / SOLVE IT
select worker.last_name||' workes for '||manager.last_name AS " SELF JOIN"from EMPLOYEES worker, employees managerWHERE worker.manager_id=manager.employee_idorder by worker.last_name
TRY IT / SOLVE IT
TRY IT / SOLVE IT
Joining Tables Using SQL: 1999 Syntax
SELECT column1,column2,……
FROM table1 NATURAL JOIN table2
SELECT table1.column, table2.column
FROM table1 CROSS JOIN table2
TRY IT / SOLVE IT
NATURAL JOIN cauta toate coloanele cu acelasi nume si returneaza liniilecare au valori echivalente. Ce se intimpla daca exista 2 coloane cu acelasinume dar au tipuri de date diferite? Acest lucru va returna o EROARE.Pentru a evita aceasta situatie clauza join poate fi modificata cu clauzaUSING, care va specifica care coloana este folosita pentru equijoin.
ATENTIE: se pot folosi alias-uri de tabele la USING sipot fi prefixate si coloanele, dar NU aveti voie saprefixati coloana din USING
o interogare care va returna numele si id_ultimelor joburi pentru acei
angajati care au avut inainte un rol in companie
Job_history
employeesATENTIE
Toate coloanele au fost
prefixate cu exceptia coloanei
employee_id
Atunci cand coloanele au nume diferite, sau daca trebuie sa se
foloseasca alt operator decat =, cum ar fi operatori de comparatie < , > ,
Between ..And (non-equijoin), sau trebuie SELF JOIN (aceeasi tabela
este referita de 2 ori si trebuie sa facem prefixare)
Write a query that will return the names and salary grades for employees.
Coloanele care intra in join OBLIGATORIU trebuie sa fie de acelasitip (valori echivalente), prin USING definim coloana care stim sigurca indeplineste aceasta conditie. (Natural Join le ia pe toate care auacelasi nume, dar nu verifica tipul datelor si va rezulta eroare)
TRY IT / SOLVE IT
TRY IT / SOLVE IT
In ANSI 99 SQL , un join intre 2 sau mai multe tabele care returneaza
doar liniile care au corespondenta se numeste un “inner join”
Cand un join returneaza atat liniile care au corespondenta cat si liniile care
nu au corespondenta => outer join
Atentie: termenii LEFT, RIGHT, FULL sunt asociati cu
numele tabelei din declaratie in clauza FROM si SELECT
Se vor afisa angajati cu sau fara departamente
employees e LEFT OUTER JOIN departments d=>
lipsesc date din departmentsSintaxa ORACLE
Se vor afisa departamente cu sau fara angajati
employees e RIGHT OUTER JOIN departments d=>
lipsesc date din employeesSintaxa ORACLE
1. Departamentele fara angajati
1. OUTER JOIN (Oracle) - se pune plus pe tabela deficitara adica EMPLOYEES)
SELECT e.last_name, d.department_id, d.department_name
FROM employees e, departments d
WHERE e.department_id(+)=d.department_id
2. LEFT OUTER JOIN (SQL) - Ultima tabela este deficitara
SELECT e.last_name,d.department_id,d.department_name
FROM departments d
LEFT OUTER JOIN employees e
ON (e.department_id=d.department_id)
3. RIGHT OUTER JOIN (SQL) - Prima tabela este deficitara
SELECT e.last_name,d.department_id,d.department_name
FROM employees e
RIGHT OUTER JOIN departments d
ON (e.department_id=d.department_id)
2. Angatii fara departamente
1. OUTER JOIN (Oracle) - se pune plus pe tabela DEPARTMENTS
SELECT e.last_name,d.department_id,d.department_name
FROM employees e,departments d
WHERE e.department_id=d.department_id(+)
2. LEFT OUTER JOIN (SQL) - Tabela de la sfarsit este deficitara
SELECT e.last_name,d.department_id,d.department_name
FROM employees e
LEFT OUTER JOIN departments d
ON (e.department_id=d.department_id)
3. RIGHT OUTER JOIN (SQL) - Prima tabela este deficitara
SELECT e.last_name,d.department_id,d.department_name
FROM departments d
RIGHT OUTER JOIN employees e
ON (e.department_id=d.department_id)
TRY IT / SOLVE IT
RECAPITULARE
JOIN
Equijoin (Oracle)SELECT event_id, p.song_id, t.cd_number
FROM d_play_list_items p, d_track_listings t
WHERE p.song_id = t.song_id;
Natural Join (ANSI)SELECT event_id, song_id , cd_number
FROM d_play_list_items NATURAL JOIN d_track_listings
Natural Join este un equijoin care leaga cele doua tabele pe toate coloanele cu nume comun din cele doua tabele. Coloanele comune celor doua tabele trebuie sa aiba acelasi tip altfel rezulta eroare
Nu e nevoie sa se foloseasca alias pt. tabele…
Equijoin (Oracle) / Natural Join (ANSI)
Equijoin (Oracle) / Join…USING (ANSI)
Equijoin (Oracle)SELECT event_id, p.song_id, t.cd_number
FROM d_play_list_items p, d_track_listings t
WHERE p.song_id = t.song_id;
Join cu clauza USING (ANSI)SELECT event_id, song_id , cd_number
FROM d_play_list_items JOIN d_track_listings
USING (song_id)
In clauza USING se trec coloanele pe care se face join-ul. Este
utila atunci cand tabelele au mai multe coloane cu nume
comun dar nu dorim in conditia de join sa folosim decat o
parte din aceste coloane.
Equijoin (Oracle) / Join…ON (ANSI)
Equijoin (Oracle)SELECT event_id, p.song_id, t.cd_number
FROM d_play_list_items p, d_track_listings t
WHERE p.song_id = t.song_id;
Join cu clauza ON (ANSI)SELECT event_id, song_id , cd_number
FROM d_play_list_items p JOIN d_track_listings t
ON (p.song_id=t.song_id);
In clauza ON se pot specifica orice fel de conditii. Se pot lega
tabele care nu au coloane cu acelasi nume
Cartesian Product (Oracle) /
Cross Join (ANSI)
Cartesian Product (Oracle) – e ca un equijoin la care s-
a omis conditia de joinSELECT first_name, last_name, department_name
FROM employees, departments;
Cross join (ANSI) – are acelasi efect ca si Cartesian
Product, adica "leaga" fiecare inregistrare din prima
tabela cu fiecare inregistrare din a doua tabelaSELECT first_name, last_name, department_name
FROM employees CROSS JOIN departments;
Nonequijoin (Oracle) / Join…ON (ANSI)
Equijoin (Oracle)SELECT e.last_name, e.salary, j.grade_level
FROM employees e, job_grades j
WHERE e.salary
BETWEEN j.lowest_sal AND j.highest_sal
Join cu clauza ON (ANSI)SELECT e.last_name, e.salary, j.grade_level
FROM employees e JOIN job_grades j
ON (e.salary BETWEEN j.lowest_sal AND j.highest_sal)
Self Join (Oracle) / Join…ON (ANSI)
Equijoin (Oracle)SELECT e.last_name||' '||e.first_name AS "Angajat",
m.kast_name||' '||m.first_name AS "Manager"
FROM employees e, employees m
WHERE e.manager_id=m.employee_id
Join cu clauza ON (ANSI)SELECT e.last_name||' '||e.first_name AS "Angajat",
m.kast_name||' '||m.first_name AS "Manager"
FROM employees e JOIN employees m
ON (e.manager_id=m.employee_id)
LEFT-OUTER JOIN
Oracle Syntax
SELECT e.last_name, e.department_id,
d.department_name
FROM employees e, departments d
WHERE e.department_id = d.department_id (+);
Afiseaza toti angajatii (e…) CU SAU FARA departamente (d…,
plusul e pe partea cu departamentul)
Join cu clauza ON (ANSI)SELECT e.last_name, e.department_id,
d.department_name
FROM employees e LEFT OUTER JOIN departments d
ON (e.department_id=d.department_id);
Afiseaza toate informatiile din tabela din STANGA (employees).
RIGHT-OUTER JOINOracle Syntax
SELECT e.last_name, e.department_id,
d.department_name
FROM employees e, departments d
WHERE e.department_id(+) = d.department_id;
Afiseaza toate departamentele (d…) CU SAU FARA angajati (e…,
plusul e pe partea cu angajatii)
Join cu clauza ON (ANSI)SELECT e.last_name, e.department_id,
d.department_name
FROM employees e RIGHT OUTER JOIN departments d
ON (e.department_id=d.department_id);
Afiseaza toate informatiile din tabela din DREAPTA (departments).
FULL-OUTER JOIN
Oracle Syntax
NU EXISTA FULL OUTER JOIN IN
SINTAXA ORACLE PENTRU CA NU SE
POATE PUNE + PE AMBELE PARTI ALE
SEMNULUI DE EGALITATE
Join cu clauza ON (ANSI)SELECT e.last_name, e.department_id, d.department_name
FROM employees e FULL OUTER JOIN departments d
ON (e.department_id=d.department_id);
Afiseaza toate informatiile din ambele tabele.
Q1: Evaluate this SQL statement:
SELECT e.employee_id, e.last_name, e.first_name, d.department_name FROM employees e, departments d WHERE e.department_id = d.department_id AND employees.department_id > 5000 ORDER BY 4; Which clause contains a syntax error?
A: AND employees.department_id > 5000
Q2: Which of the following best describes a natural join?
A: A join between two tables that includes columns that share the same name, datatypes
and lengths
Q3: Which SELECT clause creates an equijoin by specifying a column name common to both tables?
A: USING clause
Q4 : Which of the following statements is the simplest description of a nonequijoin?
A: A join condition containing something other than an equality operator
Q5: Which query will retrieve all the rows in the EMPLOYEES table, even if there is no match in the DEPARTMENTS table?
A: SELECT e.last_name, e.department_id, d.department_name FROM employees eLEFT OUTER JOIN departments d ON (e.department_id = d.department_id);
Q6: Evaluate this SELECT statement: SELECT p.player_id, m.last_name, m.first_name, t.team_name FROM player p LEFT OUTER JOIN player m ON (p.manager_id = m.player_id) LEFT OUTER JOIN team t ON (p.team_id = t.team_id);
Which join is evaluated first? A: the self-join of the player table (*)
Q7: The EMPLOYEE_ID column in the EMPLOYEE table corresponds to the EMPLOYEE_ID column of the ORDER table. The EMPLOYEE_ID column in the ORDER table contains null values for rows that you need to display. Which type of join should you use to display the data?
A: outer join (*)
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
Raspandirea datelor
SELECT column,group_function(column),……….. FROM table WHERE condition GROUP BY column ORDER BY column
OBS.: toate functiile grup ignora valorile NULL
SELECT AVG(salary), MAX(salary),MIN(salary),
SUM(salary)
FROM employees
WHERE job_id LIKE '%PROG%';AVG(SALARY) MAX(SALARY) MIN(SALARY)
6400 9000 4200
FIRST_NAME LAST_NAME SALARY HIRE_DATE JOB_ID
DEPART
MENT_ID
Steven King 24000 17-Jun-87 AD_PRES 90
Lex De Haan 17000 13-Jan-93 AD_VP 90
Alexander Hunold 9000 03-Jan-90 IT_PROG 60
Bruce Ernst 6000 21-May-91 IT_PROG 60
Diana Lorentz 4200 07-Feb-99 IT_PROG 60
Kevin Mourgos 5800 16-Nov-99 ST_MAN 50
Randall Matos 2600 15-Mar-98 ST_CLERK 50
Peter Vargas 2500 09-Jul-98 ST_CLERK 50
Eleni Zlotkey 10500 29-Jan-00 SA_MAN 80
Write a query that shows the average, maximum, and minimum salaries for all employees with
jobs in the programming department.
TRY IT / SOLVE IT
TRY IT / SOLVE IT
Vei folosi COUNT(*) atunci cand vrei sa numeri toate liniile , inclusiv acele linii care pot avea NULL in una sau mai multe coloane
Cuvantul cheie DISTINCT este folosit pentru a returna valorile distincte sau combinatiile distincte intro interogare;
Uneori este necesar sa includem in calcule si
valorile NULL dar, toate functiile grup ignora
valorile NULL.
Pentru a putea include in calcule aceste valori
este nevoie ca aceste valori NULL sa fie
inlocuite cu valori compabile cu tipul de date
utilizat.
ATENTIE: la tipul de date
Trebuie sa fie tipuri compatibile de date
NVL cu functiile de grup
0.85:4=0.2125
0.85:20=0.0425
Numai 4 angajati (din
cei 20 inregistrati) au
commision_pct
FIRST_NAME LAST_NAME SALARY HIRE_DATE JOB_ID
DEPART
MENT_ID
Steven King 24000 17-Jun-87 AD_PRES 90
Lex De Haan 17000 13-Jan-93 AD_VP 90
Alexander Hunold 9000 03-Jan-90 IT_PROG 60
Bruce Ernst 6000 21-May-91 IT_PROG 60
Diana Lorentz 4200 07-Feb-99 IT_PROG 60
Kevin Mourgos 5800 16-Nov-99 ST_MAN 50
Randall Matos 2600 15-Mar-98 ST_CLERK 50
Peter Vargas 2500 09-Jul-98 ST_CLERK 50
Eleni Zlotkey 10500 29-Jan-00 SA_MAN 80
What is the oldest hire date, and the most recent hire date
for all employees in the programming department?
SELECT MIN(hire_date), MAX(hire_date)
FROM employees
WHERE job_id like ‘%PROG%’;
MIN(HIRE_DATE) MAX(HIRE_DATE)
03-Jan-90 07-Feb-99
!!!! MAX(hire_date)
afiseaza data ultimului angajat
(cel mai nou angajat)
SELECT COUNT(*)
FROM employees
WHERE department_id = 60;
How many employees are there in department 60?
COUNT(*)
3
FIRST_NAME LAST_NAME SALARY HIRE_DATE JOB_ID
DEPART
MENT_ID
Steven King 24000 17-Jun-87 AD_PRES 90
Lex De Haan 17000 13-Jan-93 AD_VP 90
Alexander Hunold 9000 03-Jan-90 IT_PROG 60
Bruce Ernst 6000 21-May-91 IT_PROG 60
Diana Lorentz 4200 07-Feb-99 IT_PROG 60
Kevin Mourgos 5800 16-Nov-99 ST_MAN 50
Randall Matos 2600 15-Mar-98 ST_CLERK 50
Peter Vargas 2500 09-Jul-98 ST_CLERK 50
Eleni Zlotkey 10500 29-Jan-00 SA_MAN 80
Sa se afiseze numarul departamentelor distincte
SELECT COUNT(DISTINCT department_id)
FROM employees; COUNT(DISTINCTDEPARTMENT_ID)
7
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
Obs: poti folosi clauza GROUP BYpentru a imparti liniile dintro tabela in grupuri mai mici iar functiile grup vor returna informatii pe fiecare grup in parte
Se afiseaza salariul mediu pe fiecare departament in ordine crescataoare a departamentelor (se grupeaza liniile pe departamente si se aplica AVG() )
Sa se afiseze salariul maxim pe fiecare departament
OBSERVATII
1. In GROUP BY poate sa apara o coloana care nu este listata in clauza SELECT
2. Functiile grup necesita ca fiecare coloana listata in clauza SELECT
care nu are functie grup TREBUIE sa fie listata in GROUP BY
Rata de absolvire pe fiecare
oras a studentilor
RETINETI:
Nu se poate
utiliza un
alias de
coloana in
clauza
GROUP BY.
Cateodata, ai nevoie sa imparti grupurile in grupuri mai mici. De exemplu, tu poti grupa angajatii dupa departament si in cadrul fiecarui departament grupezi dupa job.
Criteriile de divizare se iau in ordinea aparitiilor din clauza GROUP BY
select to_char(avg(salary),'99999.99'),department_idfrom employeesgroup by department_id
select max(avg(salary))
from employees
select department_id, max(avg(salary))
from employees
group by department_id
FIRST_NAME LAST_NAME SALARY HIRE_DATE JOB_ID
DEPART
MENT_ID
Steven King 24000 17-Jun-87 AD_PRES 90
Lex De Haan 17000 13-Jan-93 AD_VP 90
Alexander Hunold 9000 03-Jan-90 IT_PROG 60
Bruce Ernst 6000 21-May-91 IT_PROG 60
Diana Lorentz 4200 07-Feb-99 IT_PROG 60
Kevin Mourgos 5800 16-Nov-99 ST_MAN 50
Randall Matos 2600 15-Mar-98 ST_CLERK 50
Peter Vargas 2500 09-Jul-98 ST_CLERK 50
Eleni Zlotkey 10500 29-Jan-00 SA_MAN 80
Sa se afiseze salariul mediu pe fiecare departament
DEPARTMENT_ID AVG(SALARY)
10 4400.00
20 9500.00
50 3500.00
60 6400.00
80 10033.33
90 19333.33
110 10150.00
(null) 7000.00
SELECT department_id,
AVG(salary)
FROM employees
GROUP BY department_id;
FIRST_NAME LAST_NAME SALARY HIRE_DATE JOB_ID
DEPART
MENT_ID
Steven King 24000 17-Jun-87 AD_PRES 90
Lex De Haan 17000 13-Jan-93 AD_VP 90
Alexander Hunold 9000 03-Jan-90 IT_PROG 60
Bruce Ernst 6000 21-May-91 IT_PROG 60
Diana Lorentz 4200 07-Feb-99 IT_PROG 60
Kevin Mourgos 5800 16-Nov-99 ST_MAN 50
Randall Matos 2600 15-Mar-98 ST_CLERK 50
Peter Vargas 2500 09-Jul-98 ST_CLERK 50
Eleni Zlotkey 10500 29-Jan-00 SA_MAN 80
Show the department_id, job_id and the total
salary for each job within the department (using
full table instead of partial table above) .
SELECT department_id,
job_id, SUM(salary)
FROM employees
GROUP BY department_id,
job_id;
DEPART
MENT_ID JOB_ID
SUM
(SALARY)
(null) SA_REP 7000
10 AD_ASST 4400
20 MK_MAN 13000
20 MK_REP 6000
50 ST_MAN 5800
50 ST_CLERK 11700
60 IT_PROG 19200
80 SA_MAN 10500
80 SA_REP 19600
90 AD_VP 34000
90 AD_PRES 24000
110 AC_MGR 12000
110AC_ACCOUNT 8300
Clauza WHERE restrictioneaza liniile selectate
Clauza HAVING restrictioneaza grupurile
Nu ai voie sa folosesti functii grup in WHERE
Daca doriti salariul maxim pe departamente,
dar numai pentru departamentele care au mai
mult de 1 angajat? In clauza WHERE nu ai
voie sa folosesti functiile grup.Pentru a
restrictiona grupurile trebuie sa folosesti
clauza HAVING
Observatii:
OBS
Se recomanda ca ordinea clauzelor intro declaratie sa fie:
CLAUZE
SELECT department_id,
AVG(salary)
FROM employees
WHERE AVG(salary) > 10000
GROUP BY department_id;
This results in an error:
“group function not
allowed here”
SELECT department_id, AVG(salary)
FROM employees
HAVING AVG(salary) > 10000
GROUP BY department_id DEPARTMENT_ID AVG(SALARY)
80 10033.33333
90 19333.33333
110 10150
Show the department_id, and average salary for all departments where the average
salary is greater $10,000. (Use full employees table found in HTML DB)
SELECT department_id, AVG(salary)
FROM employees
GROUP BY department_id
HAVING MAX(salary) > 10000
DEPARTMENT_ID AVG(SALARY)
20 9500
80 10033.33333
90 19333.33333
110 10150
Show the department_id, and average salary for all departments where the maximum salary is
greater $10,000. (Use full employees table found in HTML DB)
SELECT job_id, SUM(salary)
FROM employees
WHERE job_id NOT LIKE '%PROG%'
GROUP BY job_id
HAVING SUM(salary) > 10000
ORDER BY SUM(salary) JOB_ID SUM(SALARY)
SA_MAN 10500
ST_CLERK 11700
AC_MGR 12000
MK_MAN 13000
AD_PRES 24000
SA_REP 26600
AD_VP 34000
Show the job id and the total salary for all jobs
that aren’t in programming where the total
salary is greater than $10,000. Arrange the data
by the total salary in ascending order.
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
Daca ai nevoie intro interogare(cerere) sa compari cu date din aceeasi tabela sau din alta
tabela, atunci folosesti subcererea.
Exemplu: Sa se afiseze toti angajatii care s-au nascut in aceeasi zi cu ”X”. In acest caz
trebuie sa stii in ce zi s-a nascut X si sa restrictionezi liniile in functie de data nasterii a lui
X=> trebuie sa combini 2 interogari(cereri), plasand o cerere in interiorul altei cereri
SUBQUERY=INNER QUERY plasarea unei cereri in interiorul altei cereri
OUTER QUERY = cerere externa care foloseste informatia de care ai nevoie returnata de
cererea interna
WHERE
HAVING
FROM
INSERT
REGULI
1. Subcererea este inclusa in
paranteze
2. Subcererea este plasata in partea
dreapta a operatorului de
comparare
3. Cererea externa si interna pot cauta
date din diferite tabele
4. O singura clauza ORDER BY poate
fi utilizata intro declaratie si trebuie
sa fie ultima.O subcerere nu poate
avea o proprie clauza ORDER BY
5. Numarul de subcereri depinde de
dimensiunea bufferului cererii
folosite (atentie aceste reguli le veti
gasi in quizz-uri)
ATENTIE !
la numarul liniilor returnate de subcerere si la operator
Daca o subcerere va returna NULL sau nicio linie, cererea externa va
considera rezultatul NULL si va folosi acest rezultat in clauza WHERE
Atunci cererea externa nu va
returna nicio linie
Rezultatul subcererii
este NULL, pt ca
Grant nu are
departament.
REGULI
1. Returneaza doar O SINGURA LINIE
2. Subcererea este inclusa in
paranteze
3. Subcererea este plasata in partea
dreapta a operatorului de
comparare
4. Cererea externa si interna pot cauta
date din diferite tabele
5. O singura clauza ORDER BY poate
fi utilizata intro declaratie si trebuie
sa fie ultima.O subcerere nu poate
avea o proprie clauza ORDER BY
6. Numarul de subcereri depinde de
dimensiunea bufferului cererii
folosite (atentie aceste reguli le veti
gasi in quizz-uri)
Sa se afiseze toti angajatii care lucreaza in departamentul “Marketing”
Se poate utiliza mai mult decat o subcerere pentru
a returna informatii cererii externe
Subcereri in clauza HAVING
Care departamente au salariul minim mai mare decat cel mai
mic salariu din departamentul 50?
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
1997
2000
2002
1999
2000
2001
1998
2004
Restrictioneaza liniile bazate pe lista
de valori returnate de la subcerere ANY
ANY CEL PUTIN UNA
< MAX
Compara o valoare cu fiecare valoare returnata de subcerere
(> ALL => mai mare decat toate ) >MAX
Pentru a evita erorile, cand exista o sansa ca valoarea NULL sa fie returnata de o cerere interna,
foloseste IN (=ANY). Aceasta este o alegere sigura, deoarece daca nu exista o valoare in setul de
rezultate, atunci cu siguranta nu sunt valori care sa satisfaca clauza WHERE
EVITA ASTFEL DE SITUATII NOT IN (100,101,NULL) => foloseste in subcerere IS NOT NULL
ECHIVALENTE
1. = ANY IN
2. < ANY < MAX (DACA EXISTA CEL PUTIN UNA MAI MICA DECAT MAX )
3. > ANY > MIN (DACA EXISTA CEL PUTIN UNA MAI MARE DECAT MIN )
4. < ALL < MIN ( MAI MICA DECAT TOATE)
5. > ALL > MAX
6. NOT IN <> ALL
Exemplu de subcerere multiple-row cu operatorul ANY (oricare)
Se returneaza CD-urile al
caror an este mai mic decat
cel putin un an al CD-
urilor produse de “The
Music Man”.
<ANY <MAXIM
>ANY >MINIM
=ANY IN (exemplificare pe slide-ul
urmator)
Exemplu de cerere multiple-row cu “=ANY”
Rezultatul
subcererii
Cele doua
comenzi
returneaza
acelasi lucru.
Exemplu de subcerere multiple-row cu operatorul ALL
Se vor returna CD-urile al caror
an este mai mare decat toti anii
cd-urilor producatorului “The
Music Man”.
<ALL <MINIM
>ALL >MAXIM
=ALL
ALL compara
valorile cererii
principale cu
fiecare valoare
returnata de
subcerere.
Valorile NULL si subcererile multiple-row cu operator IN
Subcererea returneaza si
valoarea NULL (pentru
angajatul KING, care nu are
manager_id).
Se afiseaza angajatii care
sunt manageri.
Daca utilizam operatorul IN si
subcerea returneaza NULL
cererea principala va returna
acele valori care corespund
valorilor nenule din subcerere.
Valorile NULL si subcererile multiple-row cu operator NOT IN
Daca utilizam operatorul
NOT IN si subcererea
returneaza NULL, atunci nu
vom obtine date, deoarece
NOT IN este echivalent cu
<>ALL.
Valorile NULL si subcererile multiple-row cu operator ANY
Daca utilizam operatorul ANY
si subcerea returneaza NULL
cererea principala va returna
acele valori care corespund
valorilor nenule din subcerere.
Desi subcererea
returneaza si
valoarea NULL
obtinem angajatii
care sunt manageri.
Valorile NULL si subcererile multiple-row cu operator ALL
Daca subcererea
returneaza NULL si
utilizam operatorul ALL,
nu vom obtine rezultate.
< ANY < MAX (DACA EXISTA CEL PUTIN UNA MAI MICA DECAT MAX )
VERIFICA NUMARUL DE LINII RETURNATE DE SUBCERERE
ASIGURA-TE CA OPERATORUL UTILIZAT ESTE CORECT
DACA AI DUBII IN CE PRIVESTE NUMARUL LINIILOR
RETURNATE FOLOSESTE MULTIPLE ROW SUBQUERY
FIRST_NAME LAST_NAME SALARY HIRE_DATE JOB_ID
DEPART
MENT_ID
Steven King 24000 17-Jun-87 AD_PRES 90
Lex De Haan 17000 13-Jan-93 AD_VP 90
Alexander Hunold 9000 03-Jan-90 IT_PROG 60
Bruce Ernst 6000 21-May-91 IT_PROG 60
Diana Lorentz 4200 07-Feb-99 IT_PROG 60
Kevin Mourgos 5800 16-Nov-99 ST_MAN 50
Randall Matos 2600 15-Mar-98 ST_CLERK 50
Peter Vargas 2500 09-Jul-98 ST_CLERK 50
Eleni Zlotkey 10500 29-Jan-00 SA_MAN 80
From
subquery
SELECT last_name
FROM employees
WHERE salary <
(SELECT salary
FROM employees
WHERE last_name =
'Matos');
LAST_NAME
Vargas
Sa se afiseze angajatii care castiga mai putin decat Matos
SELECT job_id, AVG(salary)
FROM employees
GROUP BY job_id
HAVING AVG(salary) = (SELECT
MIN(AVG(salary))
FROM employees
GROUP BY job_id);MIN(AVG(SALARY))
2925
JOB_ID AVG(SALARY)
ST_CLERK 2925
From Subquery
Result of full query
Find the job with the lowest average salary.(Use the full employees table)
This will work:
SELECT employee_id, last_name
FROM employees
WHERE salary IN
(SELECT MIN(salary)
FROM employees
GROUP BY department_id)
Why will the following query not work?
SELECT employee_id, last_name
FROM employees
WHERE salary =
(SELECT MIN(salary)
FROM employees
GROUP BY department_id)
Single row operator
IN, ANY, ALL are
multiple-row
comparison operators
Why does the following query
not work?
SELECT last_name
FROM employees
WHERE employee_id NOT IN
(SELECT manager_id
FROM employees);
Subquery returns
NULL values
This one will work:
SELECT last_name
FROM employees
WHERE employee_id NOT IN
(SELECT manager_id
FROM employees
WHERE manager_id IS NOT NULL);
Sa se afiseze maximul salariului mediu si departamentul unde se castiga
select avg(salary),department_id
from employees
having avg(salary)=(
select max(avg(salary))
from employees
group by department_id)
group by department_id
select department_id, max(avg(salary))
from employees
group by department_id
FORMA CORECTA
Q: Below find the structure of the CUSTOMERS and SALES_ORDER tables:
CUSTOMERSCUSTOMER_ID NUMBER NOT NULL, Primary KeyCUSTOMER_NAME VARCHAR2 (30) CONTACT_NAME VARCHAR2 (30)CONTACT_TITLE VARCHAR2 (20)ADDRESS VARCHAR2 (30)CITY VARCHAR2 (25)REGION VARCHAR2 (10)POSTAL_CODE VARCHAR2 (20)COUNTRY_ID NUMBER Foreign key to COUNTRY_ID column of the COUNTRY table PHONE VARCHAR2 (20)FAX VARCHAR2 (20) CREDIT_LIMIT NUMBER(7,2)
SALES_ORDERORDER_ID NUMBER NOT NULL, Primary KeyCUSTOMER_ID NUMBER Foreign key to CUSTOMER_ID column of the CUSTOMER tableORDER_DT DATE ORDER_AMT NUMBER (7,2) SHIP_METHOD VARCHAR2 (5)
You need to create a report that displays customers without a sales order.
A: SELECT c.customer_name FROM customers c WHERE c.customer_id not in (SELECT s.customer_id FROM sales_order s);
SELECT id_number, name, department_id, SUM(salary)
FROM employees
WHERE salary > 25000
GROUP BY department_id, id_number, name
ORDER BY hire_date;
Why will this statement cause an error?
The HAVING clause is missing.
The WHERE clause contains a syntax error.
The SALARY column is NOT included in the GROUP BY clause.
The HIRE_DATE column is NOT included in the GROUP BY clause. (*)
OBSERVATIE
ORDER BY cu GROUP BY
SELECT employee_id,department_id, SUM(salary)
FROM employees
WHERE salary>10000
GROUP BY employee_id,department_id,hire_date
ORDER BY hire_date;
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT
TRY IT / SOLVE IT