< Agregace pokraèování | SQL postupnì | Dotazy na to co není >
SQL kód nìjakého dotazu mù¾eme uzavøít do závorek a pak zakomponovat do dal¹ího dotazu. Ten vnitøní, zakomponovaný, dotaz je pak poddotazem vnìj¹ího dotazu. Takový kód se interpretuje tak, ¾e výsledek poddotazu stojí na místì, kde je poddotaz ve vnìj¹ím dotazu. Èasto pou¾itím poddotazu ztí¾íme nebo naru¹íme práci optimalizátoru, nìkdy v¹ak poddotaz skuteènì potøebujeme.
Vìt¹inou se jedná o dosti slo¾ité úlohy:
Pøíklad: Pro ka¾dého zákazníka vypi¹te datum a èástku jeho poslední objednávky.
select LOG, DAT, sum(VCEN) as CASTKA
from ZAK left join OBJ o1 on (ZAK.LOG=o1.ZAK) left join POLOZ using (CISO)
where DAT=(select max(DAT) from OBJ o2 where o2.ZAK=ZAK.LOG)
or DAT is null
group by LOG, DAT
order by 1; |
Poddotaz select max(DAT) from OBJ o2 where o2.ZAK=ZAK.LOG najde poslední datum objednávy konkrétního zákazníka. Je to tzv. korelovaný poddotaz, proto¾e ZAK.LOG odkazuje do vnìj¹ího dotazu. Následující formulace v¹ak mù¾e být lépe optimalizována: |
select LOG, MAXDAT, sum(VCEN) as CASTKA
from (select ZAK,max(DAT) as MAXDAT from OBJ group by ZAK ) MAXY right join ZAK on (MAXY.ZAK=ZAK.LOG) left join OBJ on
(ZAK.LOG=OBJ.ZAK and MAXY.MAXDAT=OBJ.DAT) left join POLOZ using (CISO)
group by LOG, MAXDAT
order by 1; |
Poddotaz select ZAK,max(DAT) as MAXDAT from OBJ group by ZAK vypoèítává poslední datum objednávky pro ka¾dého zákazníka. (Proto¾e se potøebujeme na výsledek tohoto poddotazu odkazovat v podmínce propojení, musíme ho nìjak pojmenovat – jako v tomto pøípadì MAXY.) Zde ji¾ nemáme korelovaný poddotaz, tak¾e nenutíme databázový engine provádìt operace v urèitém poøadí, ale volbu necháme na nìm. |
Pøíklad: Pro ka¾dé zbo¾í vypoèítejme jeho podíl na celkové tr¾bì v jeho kategorii.
select KAT, KOD, NAZ, 100*sum(VCEN)/KAT_TRZB as PROCENTNI_PODIL
from ZBOZ left join POLOZ using(KOD) left join
(select KAT,sum(VCEN) as KAT_TRZB from ZBOZ left join POLOZ using(KOD) group by KAT) using (KAT)
group by KAT,KOD,NAZ,KAT_TRZB
order by 1,4 DESC; |
Poddotaz select KAT,sum(VCEN) as KAT_TRZB from ZBOZ left join POLOZ using(KOD) group by KAT nejprve pro ka¾dou kategorii, ve které máme nìjaké zbo¾í, vypoèítá celkovou tr¾bu. (Podle synatxe Oracle jsou v¹echna pole v GROUP BY klauzuli takto nutná.) |
Pøíklad: Pro ka¾dého zákazníka porovnejte jeho nákup za roky 2008 a 2009.
select LOG, R2008, R2009, 100*R2008/R2009 as PROCENTNI_PODIL
from
(select ZAK, sum(VCEN) as R2008
from OBJ join POLOZ using (CISO) where extract(year from DAT)=2008 group by ZAK) R08
right join ZAK on (R08.ZAK=ZAK.LOG)
left join
(select ZAK, sum(VCEN) as R2009
from OBJ join POLOZ using (CISO) where extract(year from DAT)=2009 group by ZAK) R09 on (R09.ZAK=ZAK.LOG); |
| Kdy¾ potøebujeme porovnat dvì agregace poèítané podle rùzných podmínek, je univerzálním øe¹ením propojení dvou poddotazù. |
 | Bì¾né úlohy lze vìt¹inou øe¹it bez poddotazù. V nìkterých pøípadech se mù¾e zdát formulace s poddotazem pøíjemnìj¹í, ne v¾dy je v¹ak vhodná: |
Pøíklad: Vypi¹te názvy zbo¾í z kategorie, v jejím¾ popisu se vyskytuje "minerální".
select NAZ
from ZBOZ
where KAT=(select KAT from KAT where POPK like '%minerální%'); |
| Tento kód je sice ekvivalentní s |
select NAZ
from ZBOZ join KAT using (KAT)
where POPK like '%minerální%'; |
| ale mnohému se mù¾e zdát první verze pøirozenìj¹í. |
V pøedchozím pøíkladu se vyu¾ilo, ¾e pøíslu¹ná kategorie je jen jedna. Pozor v¹ak na následující
Pøíklad: Vypi¹te e-maily zákazníkù, kteøí si nechávají dovézt objednávky rozvozem (DOPR=2) .
select distinct EMAIL
from ZAK
where LOG in (select ZAK from OBJ where DOPR=2); |
| Toto není nejlep¹í formulace, v závislsti na pou¾itém optimalizátoru (v systému jiném ne¾ Oracle) mù¾e být znaènì pomalej¹í ne¾: |
select distinct EMAIL
from ZAK join OBJ on (LOG=ZAK)
where DOPR=2; |
Zvlá¹tní kapitolu vìnujeme dotazùm, ve kterých hledáme objekty, o kterých v databázi není ¾ádný záznam urèitých vlastností. O tom viz následující>.
< Agregace pokraèování | SQL postupnì | Dotazy na to co není >