25
Adatbázisrendszerek gyakorlati segédlet gazdasági informatikusok számára Szeghalmy Szilvia Debreceni Egyetem Tartalomjegyzék Adatbázisrendszerek gyakorlati segédlet ............................................................................................ 1 1. Bevezetés......................................................................................................................................... 2 1.1. A jegyzetben használt jelölések............................................................................................... 2 1.2. Környezet................................................................................................................................. 2 2. SQL Oracle környezetben ................................................................................................................ 2 2.1. Néhány beépített típus............................................................................................................ 2 2.2. Operátorok .............................................................................................................................. 3 2.3. Data Definition Language (DDL) .............................................................................................. 4 2.3.1. Tábla létrehozása............................................................................................................. 4 2.4. DQL: Adatok lekérdezése ........................................................................................................ 6 2.4.1. Egy táblára vonatkozó egyszerű lekérdezések ................................................................ 7 2.4.2. Rendezés.......................................................................................................................... 8 2.4.3. Sorok leválogatása ........................................................................................................... 9 2.4.4. Csoportok képzése (GROUP BY, HAVING) ..................................................................... 10 2.4.5. Táblák összekapcsolása ................................................................................................. 12 2.4.6. Beágyazott lekérdezések ............................................................................................... 15 2.4.7. Első n sor lekérdezése ................................................................................................... 18 2.4.8. Összetett lekérdezések .................................................................................................. 19 3. Függelék......................................................................................................................................... 23 3.1. Boltocska kezdetleges cikk nyilvántartó rendszere ............................................................... 23 3.2. Leegyszerűsített bűnügyi nyilvántartó rendszer ................................................................... 24

Adatbázisrendszerek gyakorlati segédlet gazdasági ... · NUMBER[(p [, s])]: Ahol p megadja hány jegyen történik az ábrázolás, s pedig megadja ebből mennyi lesz a tört rész

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

Adatbázisrendszerek gyakorlati segédlet gazdasági informatikusok számára

Szeghalmy Szilvia

Debreceni Egyetem

Tartalomjegyzék

Adatbázisrendszerek gyakorlati segédlet ............................................................................................ 1

1. Bevezetés ......................................................................................................................................... 2

1.1. A jegyzetben használt jelölések ............................................................................................... 2

1.2. Környezet ................................................................................................................................. 2

2. SQL Oracle környezetben ................................................................................................................ 2

2.1. Néhány beépített típus ............................................................................................................ 2

2.2. Operátorok .............................................................................................................................. 3

2.3. Data Definition Language (DDL) .............................................................................................. 4

2.3.1. Tábla létrehozása............................................................................................................. 4

2.4. DQL: Adatok lekérdezése ........................................................................................................ 6

2.4.1. Egy táblára vonatkozó egyszerű lekérdezések ................................................................ 7

2.4.2. Rendezés.......................................................................................................................... 8

2.4.3. Sorok leválogatása ........................................................................................................... 9

2.4.4. Csoportok képzése (GROUP BY, HAVING) ..................................................................... 10

2.4.5. Táblák összekapcsolása ................................................................................................. 12

2.4.6. Beágyazott lekérdezések ............................................................................................... 15

2.4.7. Első n sor lekérdezése ................................................................................................... 18

2.4.8. Összetett lekérdezések .................................................................................................. 19

3. Függelék......................................................................................................................................... 23

3.1. Boltocska kezdetleges cikk nyilvántartó rendszere ............................................................... 23

3.2. Leegyszerűsített bűnügyi nyilvántartó rendszer ................................................................... 24

1. Bevezetés

A segédanyag nem lektorált, ezért tartalmazhat, és minden bizonnyal tartalmaz is hibákat. Használata

csak kellő körültekintéssel javasolt.

1.1. A jegyzetben használt jelölések

Az SQL utasítások pontos szintaktikája az adatbázis-kezelő rendszer referencia könyvében keresendő,

a jegyzetben csak egyszerűsített változatok szerepelnek.

A jegyzetben használt jelölések:

[ ] Opcionális (nem kötelező a zárójelek közti rész szerepeltetése)

{a|b} Kizáró vagy: a vagy b, de csak az egyik

… Ismétlődés

<leírás> A leírás alapján helyettesítendő

kód A kódrészletek betűtípusa Courier, a sorok számozása sosem része a kódnak!

1.2. Környezet

A gyakorlaton Oracle adatbázis-kezelő rendszert fogunk használni, Oracle SQL Developer kliensen

keresztül, mely a Campuson kívülről is elérhető a tárgyra járó hallgatók számára. Az SQL

Developerben az adatbázis-szerverhez való kapcsolódáshoz a következő adatokat kell megadni:

User: <U_neptunkód>

Password: <gyakorlaton megbeszéltek szerint>

Hostname: codd.inf.unideb.hu

Port: 1521

SID: ora12c

2. SQL Oracle környezetben

2.1. Néhány beépített típus

A Oracle beépített típusai közül a gyakorlaton az alábbiakat fogjuk használni:

CHAR[(hossz)]: Fix hosszon tárolt karaktersorozat. Az alapértelmezett hossz 1. Ha az oszlopba

hosszabb szöveget próbálunk beszúrni hiba lép fel. Jellemzően akkor használjuk, ha a táblázat

minden sorában azonos hosszúságú érték fog állni. Például: személyi igazolvány szám, termék kódok

tárolására.

VARCHAR2[(hossz)]: Változó hosszon tárolt karaktersorozat.

DATE: dátumtípus

NUMBER[(p [, s])]: Ahol p megadja hány jegyen történik az ábrázolás, s pedig megadja ebből mennyi

lesz a tört rész tárolására felhasználva. Ha a táblázatba szúrandó adat tizedespont utáni része s-nél

több jegyből áll kerekítés történik.

2.2. Operátorok

Aritmetikai operátorok

Rendre: pozitív, negatív előjel, összeadás, kivonás, (valós)osztás, szorzás

+(unáris) -(unáris) + - / *

Megj.: A maradékos osztás a Mod(osztandó, osztó) függvénnyel valósítható meg. Kerekítést a

Round(szám [,jegy]) függvénnyel végezhetünk, ahol a jegy azt adja meg hány tizedesjegyre történjen

a kerekítés. A tizedesjegyek levágására Floor( szám [, jegy]) függvén használható.

Karakteres operátor

Karaktersorozatok összefűzése (bináris).

||

Logikai operátorok

Rendre és, vagy, tagadás.

And Or Not

Hasonlító operátorok

Rendre: kisebb, kisebb vagy egyenlő, nagyobb, nagyobb vagy egyenlő, egyenlő, nem egyenlő.

< <= > >= = <>

null érték vizsgálat

kifejezés IS [NOT] NULL

Mintaillesztést a LIKE operátor segítségével végezhetünk.

kifejezés LIKE minta

A kifejezés igaz, ha a bal oldali operandus illeszkedik a jobb oldalon megadott mintára. A mintában

szerepelhet aláhúzás jel (_), mely egyetlen tetszőleges karaktert helyettesít vagy százalék jel (%)

melyre tetszőleges karaktersorozat illeszkedik.

kifejezés [NOT] BETWEEN érték1 AND érték2

Később tárgyaljuk (a beágyazott lekérdezéseknél): IN, ALL, ANY, EXISTS

Halmazoperátorok

Unió, kivonás, metszet:

Union [All] Minus Intersect [All]

Az All használatával az azonos sorok is megmaradnak (multihalmaz)

2.3. Data Definition Language (DDL)

Az SQL nyelv adatdefiníciós utasításai segítségével alakíthatjuk ki az adatok tárolására szolgáló sémát:

többek között táblákat, táblák közti kapcsolatokat, indexeket, megszorításokat hozhatunk létre,

módosíthatunk, vagy törölhetünk.

2.3.1. Tábla létrehozása

Az adatbázisokban az összefüggő adatok egy, vagy több táblában tárolódnak. A táblában az azonos

jellemzőkkel rendelkező objektumok (Piroska nénitől kezdve a csokoládén át a banki tranzakciókig

bármi objektumnak számíthat) tulajdonságainak tárolására lesz lehetőségünk. A táblákat olyan

táblázatként képzelhetjük el, melynek fejlécében az oszlopnevek állnak, soraiban pedig egy-egy

konkrét objektumhoz tartozó értékek szerepelnek.

Neptunkód Név Született

XYABDF Kis Ilona 1980.01.24.

RGHHJR Piroska néni 1989.04.24.

Egy tábla létrehozásának általános alakja:

CREATE TABLE táblanév(

oszlopdefiníció

[,oszlopdefiníció]…

[táblaszintű megszorítás]…

);

Oszlopdefiníció:

oszlopnév típus [oszlopszintű_megszorítások]

Oszlop szintű megszorítások:

Egyetlen oszlopra vonatkoznak. Ezeket az oszlop után írva adhatjuk meg.

oszlopnév [CONSTRAINT nev] megszorítás [megszorítás]...

Táblaszintű megszorítások:

Több oszlopra is vonatkoznak A create table parancsban az oszlopdefiníciók

után áll.

[CONSTRAINT nev] megszorítás ( oszlopnév [, oszlopnév]...)

Megszorítások:

Elsődleges kulcs megszorítás (Primary Key): Minden táblának egy elsődleges kulcsa lehet, ami lehet

összetett is (több attribútumból álló). Az elsődleges kulcsot alkotó attribútumokban nem állhat null

érték, és nem szerepelhet két olyan sor a táblában, melyek értéke az elsődleges kulcsot alkotó

attribútumokon megegyezik. (Összetett kulcs esetében egy-egy attribútumot tekintve lehet

azonosság, az a lényeg, hogy együtt nézve az értékeket egyediek legyenek.)

Egyediség megszorítás (Unique): Több ilyen megszorítás is szerepelhet egy táblára vonatkozóan.

Hasonlóan az elsődleges kulcshoz elvárjuk hogy az értékek egyediek legyenek, de null érték

szerepelhet.

[NOT] null megszorítás: Minden típus tartományába beletartozik egy speciális érték a null. Ezzel az

értékkel jelezhetjük, hogy az adott érték nincs értelmezve, vagy nem létezik, esetleg csak nem

ismerjük. A null megszorítás megengedi, hogy az oszlopban null értékek szerepeljenek, a NOT null

tiltja. Mivel a null az alapértelmezett, csak a NOT null megszorítást szokás kiírni. Ez a megszorítás csak

egy oszlopra vonatkozóan állhat, a táblaszintű megszorítások közt nem is szerepelhet.

Külső kulcs megszorítás: Két tábla közti kapcsolat szabályozására szolgál. Biztosítja, hogy a külső

kulcsot tartalmazó tábla külső kulcsot alkotó attribútumaiban csak null érték vagy olyan értékek

állhatnak, mely a hivatkozott tábla (amelyhez ez a tábla kapcsolódik) hivatkozott oszlopaiban

ténylegesen szerepel. Formája kicsit eltér az általános megszorítás alakjától, hiszen a hivatkozott

táblát is meg kell adnunk. Állhat oszlop után írva oszlopmegszorításként:

[CONSTRAINT megszorításnév] REFERENCES hivatkozott_tábla (oszlopnév)

vagy az oszlopdefiníciók után táblaszintű megszorítás formájában:

[CONSTRAINT megszorításnév] FOREIGN KEY (oszlopnév [, oszlopnév]...)

REFERENCES hivatkozott_tábla (oszlopnév [,oszlopnév]...)

Általános megszorítás: Ezzel biztosíthatjuk egy adott oszlopba csak egy feltételnek eleget tevő érték

kerüljön be. A feltétel akár több oszlopra is vonatkozhat, ekkor táblaszintű megszorításként kell

megadnunk.

[CONSTRAINT megszorításnév] CHECK (feltétel)

Példa:

create table cikk(

cikk_kod CHAR(3) PRIMARY KEY,

cikknev VARCHAR2(40),

gyarto CHAR(2),

beszerar NUMERIC(6) CONSTRAINT jajj NOT null,

eladar NUMERIC(6),

CHECK (beszerar < eladar),

CONSTRAINT jajj2 UNIQUE (cikknev, gyarto)

);

A példában lévő táblában termékeket tárolunk. A tábla elsődleges kulcsa a cikk_kod, tehát minden

cikk egyedi kóddal rendelkezik, amelyet kötelező megadni. Biztosak lehetünk abban is, hogy egy

gyártótól nem szerepel kétszer ugyan az a cikk a táblában, hiszen a gyártó és cikknév együttesen

egyedi kell, hogy legyen. Ha ezt a megszorítást később esetleg törölnénk, akkor a jajj2 néven érhetjük

el. A beszerzési árat kötelező megadni. Ezt a megszorítást is elneveztük: jajj-ra. Ezen kívül van egy

általános megszorításunk is (check), ami biztosítja, hogy egyetlen termék eladási ára se legyen kisebb,

mint amennyiért beszereztük azt.

Néhány példa arra nézve milyen adatok szúrhatók be a táblába, és milyenek nem:

insert into cikk values('1BB', 'Izo Tej','00', 100, 200); ’beszúrja

insert into cikk(gyarto, beszerar) values('AA', 4); ’hiba: PK nem lehet null.

insert into cikk values('1BB', 'Kifli','01', 100, 200); ’hiba: PK már szerepel

insert into cikk values('1BD', 'Vaj','2', 300, 200); ’hiba: beszerar > eladar

insert into cikk values('1BE', 'Vaj','2', 100, 300); ’beszúrja

insert into cikk values( 512, 'Keksz','4', 10, 20); ’beszúrja (konverzió)

insert into cikk values('1BE', 'Vaj','2', 100, 200); ’hiba: szerepel a Vaj, 2

insert into cikk values('2BB', 'Vaj','4', 100, 200); ’beszúrja

insert into cikk values('5BB', 'Tej','01', null, 200); ’hiba: not null

insert into cikk values('ADD', 'Ropi','4', '15', 80); ’beszúrja (konverzió)

insert into cikk values('X2', 'Íz','01', 'ten', 80); ’hiba: nem konvertálható

Feladat 1: Hozzunk létre egy gyártók táblát, melyben a gyártó kódját és nevét tároljuk, és alakítsuk

úgy a fenti cikk tábla létrehozására szolgáló kódot, hogy az a gyarto oszlopon keresztül kapcsolódjon

a ehhez a táblához. A gyártónevek egyediek, és kötelező a megadásuk.

create table gyartok(

gyartokod CHAR(2) PRIMARY KEY,

nev VARCHAR2(40) NOT null UNIQUE

);

create table cikk(

cikk_kod CHAR(3) PRIMARY KEY,

cikknev VARCHAR2(40),

gyarto CHAR(2) REFERENCES gyartok( gyartokod) ,

beszerar NUMERIC(6) CONSTRAINT jajj NOT null,

eladar NUMERIC(6),

CHECK (beszerar < eladar),

CONSTRAINT jajj2 UNIQUE (cikknev, gyarto)

);

Feladat 2: Mely sorok végrehajtása során kapunk hibaüzenetet az alábbi sorok futtatása során,

feltételezve hogy az előbb létrejött táblákkal dolgozunk és mindkét tábla üres kezdetben?

1. insert into gyartok values('000', 'Lipo');

2. insert into gyartok values('01', 'Bali');

3. insert into gyartok( gyartokod) values('12');

4. insert into gyartok values('2', 'Jodo');

5. insert into gyartok( nev, gyartokod) values( 'Kincs', '05');

6. insert into cikk values('A', 'Tészta','01', 100, 200);

7. insert into cikk values('X', 'Tészta','09', 100, 200);

8. insert into cikk(cikk_kod, gyarto, beszerar) values('B', 2, 10);

9. insert into cikk values('C', 'Kifli','02', 100, 200);

10. insert into cikk values('E', 'Vaj','2 ', 500, 400);

11. insert into cikk values('F', 'Méz','01', 34, null);

Megoldás

1. sor: Túl hosszú a gyártókódhoz adott érték. (2 karakter van csak a tárolására)

3. sor: A gyártónév nem lehet null ezért kötelező megadni

7. sor: Külső kulcs hiba, mert 09-es gyártó nem létezik.

9. sor: Külső kulcs hiba, mert 02-es gyártó nincs, csak '2 '-es

10. sor: beszerzési ár nem lehet nagyobb az eladási árnál. (A külső kulcs jó.)

2.4. DQL: Adatok lekérdezése

Az adatok lekérdezésének az általános (de egyszerűsített) alakja a következő:

SELECT [{ALL|DISTINCT}] mezőkifejezés [álnév] [,mezőkifejezés [álnév]]...

FROM táblakifejezés [álnév]

[WHERE feltétel ]

[GROUP BY csoportosítómező [, csoportosítómező ]...]

[HAVING feltétel ]

[ORDER BY mezőkifejzés [, mezőkifejezés]... ]

A mezőkifejezés általában a FROM kulcsszó utáni táblakifejezés egy attribútumát jelenti, de ahogy a

későbbiekben látni fogjuk tényleges kifejezések is szerepelhetnek ott. Ezen túl egy speciális jel is

állhat az attribútum nevek helyett, a *, mely a FROM kulcsszó után álló táblakifejezés összes

mezőjének kiírását helyettesíti (ezért mellette mezőnév már nem állhat). A mezők minősíthetők azzal

a táblanévvel, amelyből származnak. A minősítés alakja táblanév.mezőnév. A * jelet is minősíthetjük

táblanévvel, ekkor az adott tábla összes mezőjét helyettesíti. Lehetőségünk van az

mezőkifejezésekhez és a táblához álnevet rendelni, amivel a későbbi műveletek során hivatkozhatunk

rájuk. Táblakifejezés alatt konkrét táblát, vagy olyan műveletet értünk, mely táblát ad eredményül.

A SELECT után megadhatjuk, hogy teljesen azonos sorok esetén mi a teendő. A relációalgebrai

megközelítéstől eltérően itt az alapértelmezett az azonos sorok megtartása (ALL). Ha csak az egyedi

sorok érdekelnek bennünket, akkor a DISTINCT kulcsszót kell kiírnunk.

Látható, hogy számos opcionálisan megadható része lehet a szelekt utasításnak. Ezek a jegyzet

további részében kerülnek bemutatásra, itt csak 1-1 mondat erejéig kerülnek bemutatásra:

WHERE: Az utána álló feltételnek megfelelő sorok leválogatása.

GROUP BY: Az utána álló mezőkifejezések alapján csoportosítja az adatokat.

HAVING: Feltételnek megfelelő sorok leválogatása a csoportosítás után.

ORDER BY: Sorok rendezése a megadott mezők alapján.

2.4.1. Egy táblára vonatkozó egyszerű lekérdezések

A lekérdezés legegyszerűbb formája, amikor egy tábla egész tartalmát szeretnénk, esetleg bizonyos

oszlopainak tartalmára vagyunk kíváncsiak.

Példa: Kérdezzük le az összes gyártó összes adatát!

SELECT gyartokod, nev FROM gyartok;

SELECT * FROM gyartok; 'Ez is ugyan azt csinálja.

Példa: Kérdezzük le a cikkek kódját és nevét!

SELECT cikk_kod, cikknev FROM cikk;

Korábban említésre került, hogy az oszlopokat át is nevezhetjük, vagy kifejezéseket is

szerepeltethetünk a SELECT utáni részben. A kifejezés jelenthet egy vagy több attribútummal,

konstanssal végzett aritmetikai műveletet, de akár függvényhívást is. Az eredmény relációban a

kifejezés új attribútumként jelenik meg. Nézzünk erre is néhány példát.

Példa: Kérdezzük le a cikkek kódját és nevét! A cikk_kod mezőt nevezzük át kódra!

SELECT cikk_kod kód, cikknev FROM cikk;

Példa: Jelenítsük meg mennyi árrés van az egyes termékeknél!

SELECT cikk_kod, cikknev, eladar-beszerar Árrés FROM cikk;

Példa: Jelenítsük meg a cikknevet, és a cikkkód első karakterét!

SELECT cikknev, substr(cikknev, 1, 1) FROM cikk;

Feladat 3: Kérdezzük le a cikkek összes adatát!

Feladat 4: Kérdezzük le az összes cikk nevét, és gyártókódját! A cikknév névként jelenjen meg!

Feladat 5: Kérdezzük le a különböző gyártókódokat a cikkek táblából! (Distinct)

2.4.2. Rendezés

Általános alak:

SELECT ... FROM... ORDER BY mezőkifejezés [{ASC|DESC}][,mezőkifejezés

[{ASC|DESC}]]...

A megadott mezőkifejezések alapján rendezve jeleníti meg a sorokat. Az ASC növekvő rendezettséget

jelent, ez az alapértelmezett, ezért nem kötelező kiírni. A DESC csökkenő sorrendben rendezi a

sorokat. Több kifejezés alapján is lehet rendezni. Ilyenkor a felírás sorrendjében legelső kifejezés

alapján kerülnek rendezésre a sorok, majd az adott kifejezésen belül egyező értékek a következő

kifejezés alapján rendeződnek, stb.

Példa: Kérdezzük le a cikk tábla összes sorát, gyártó szerint növekvő sorrendben. Az azonos gyártóhoz

tartozó termékek neve csökkenő sorrendben jelenjen meg!

SELECT * FROM cikk ORDER BY gyarto ASC, cikknev DESC;

Hatására a sorok az olyan rendezettséget mutatnak, mint ami az alábbi táblában látható:

cikk_kod cikknev gyarto beszerar eladar

AAG Tej 1 100 200

AAF Málnás joghurt 1 30 50

AAC Banásnos joghurt 1 40 60

AAB Sóspálcika 2 20 30

AAE Kakaós keksz 2 30 50

AAA Kakaópor 3 150 280

AAD Majonéz 4 500 1000

Feladat 6: Kérdezd le a bűnözők összes adatát név szerint növekvő sorrendben!

Feladat 7: Írasd ki a bűnözők adatait úgy, hogy a nők jelenjenek meg előbb.

A nevek legyenek növekvő sorrendben!

Feladat 8: Jelenítsük meg a Lecsukva tábla tartalmát, szig és tol szerint csökkenőleg rendezve!

2.4.3. Sorok leválogatása

A WHERE záradék megadásával csak azok a sorok kerülnek leválogatásra, melyek a WHERE után álló

logikai kifejezésnek eleget tesznek. A logikai kifejezés természetesen több részfeltételből is állhat,

melyeket logikai operátorokkal (AND, OR, NOT) kapcsolhatunk össze. A részfeltételek a FROM után

álló táblák bármelyik attribútumát, konstanst, függvényhívást, halmazt, vagy konstanst illetve

halmazt tartalmazhat a típusoknak megfelelő operátorokkal összekapcsolva.

Példa: Jelenítsük meg a 100 Forintnál drágábban árult termékeket név szerint rendezve!

SELECT * FROM cikk WHERE eladar > 100 ORDER BY cikknev;

Példa: Jelenítsük meg az 50 Ft-nál drágábban árult, de 40 Ft-nál olcsóbban vett termékeket!

SELECT * FROM cikk WHERE eladar > 50 AND beszerar < 40;

Példa: Jelenítsük meg azon cikkeket, ahol a gyártó szerepel a '00', '01', '05' halmazban.

SELECT * FROM cikk WHERE gyarto in ('00', '01', '05');

SELECT * FROM cikk WHERE gyarto = '00' OR gyarto = '01' OR gyarto = '05';

Feladat 9: Jelenítsük meg azon börtönöket, ahol több mint 800 rab fér el!

Feladat 10: Írasd ki a férfi bűnözőket!

Feladat 11: Jelenítsük meg a koedukált börtönök nevét kapacitás szerint csökkenőleg rendezve!

Feladat 12: Jelenítsük meg azon budapesti börtönöket, ahol fiatalkorúakat tartanak fogva!

Feladat 13: Jelenítsd meg a tisztán női, és tisztán férfi börtönöket!

Feladat 14: Írasd ki azokat a börtönöket, ahol 500-nál több rab fér el, és nőket is fogadnak.

Null érték kezelése

A null érték vizsgálatára külön kulcsszó áll rendelkezésre, az IS [NOT]. Amennyiben két érték

összehasonlításánál az egyik operandus null érték, az eredmény is null értéket hordoz majd (pl: a >

null, a <> null). Egy null értéket tartalmazó logikai kifejezés eredménye viszont csak abban az esetben

lesz null, amennyiben a kifejezés értéke függne attól, hogy a null érték helyén igaz, vagy hamis érték

szerepelne-e. A szelekciós feltétel null értéke esetén a sorok nem kerülnek leválogatásra.

Példák:

null IS null 'igaz

1 = 0 AND null 'hamis (a kifejezés értéke nem függ a 2. tagtól)

1 = 0 OR null 'null (a kifejezés értéke függ a 2. tagtól)

'' IS null 'igaz

1 = null Is null 'igaz, mert 1 = null eredménye null

Feladat 15: Mely lekérdezések adnak vissza sort az alábbiak közül?

1. SELECT 'True' FROM dual where null = null;

2. SELECT 'True' FROM dual where null < 0;

3. SELECT 'True' FROM dual where null = 0;

4. SELECT 'True' FROM dual where 1 = null or 1 = 1;

5. SELECT 'True' FROM dual where 1 = null and 1 = 1;

6. SELECT 'True' FROM dual where not 1 = null;

7. SELECT 'True' FROM dual where null is null;

8. SELECT 'True' FROM dual where 1 is not null;

9. SELECT 'True' FROM dual where '' is null;

10. SELECT 'True' FROM dual where 'a' is null;

A null érték kezelésére használható az Nvl függvény, mely első paraméterként egy attribútumnevet

vár, második paraméterként pedig azt az értéket, melyet vissza akarunk kapni, ha az 1. paraméter az

éppen vizsgált cellában null értéket vesz fel.

Példa: Jelenítsük meg a cikk kódokat és neveket. Ahol nincs megadva név ott az 'ismeretlen' szó

szerepeljen!

select cikk_kod, nvl(cikknev, 'ismeretlen') from cikk;

Feladat 16: Jelenítsd meg az eladási árakat. Ahol nincs megadva ott beszerzési ár 120%-a álljon!

Feladat 17: Írasd ki azokat a bűnözőket, akiknél nincs megadva, milyen betegségben szenvednek!

2.4.4. Csoportok képzése (GROUP BY, HAVING)

SELECT … FROM …

[GROUP BY csoportosítókifejezés1 [, csoportosítókifejezés2]… ]

[HAVING feltétel]

Az SQL lehetővé teszi, hogy a sorokat bizonyos tulajdonság alapján csoportosítsuk, és az egyes

csoportokon számításokat végezzünk. Amennyiben nincs GROUP BY záradék, akkor az összes sor

egyetlen csoportnak lesz tekintve. Egyébként a GROUP BY után álló kifejezések alapján történik a

csoportképzés. Több csoportosító kifejezés esetén a legelső szerint történik első körben a

csoportosítás, majd az egyes csoportokon belüli történik újabb csoportosítás a következő kifejezés

alapján. A HAVING megadása esetén a csoportosítás után előállt sorok közül csak a feltételnek

megfelelő sorok kerülnek az eredményhalmazba.

Az attribútumlistában a csoportosítás alapján képező kifejezések, konstantkifejzések valamint

összesítőfüggvények vagy azokkal alkotott kifejezések szerepelhetnek. Olyan attribútum azonban

nem szerepelhet csoportosító függvényen kívül, mely a csoportosításban nem vesz részt.

Összesítő függvények:

avg(kifejezés): A csoport összes sorára kiértékeli a kifejezést, és ezek átlagát adja vissza.

min(kifejezés): A csoport összes sorára kiértékeli a kifejezést, és ezek minimumát adja vissza.

max(kifejezés): A csoport összes sorára kiértékeli a kifejezést, és ezek maximumát adja vissza.

sum(kifejezés): A csoport összes sorára kiértékeli a kifejezést, és ezek összegét adja vissza.

count({attribútumsorszám|attrinév}): Megszámolja a csoportban szereplő nem null

értékeket. Gyakran használjuk count(distinct attributum) formában, mely a különböző

értékek számát adja vissza.

count(*): Visszaadja a csoportban szereplő sorok számát.

Az avg, min, max, sum a null értékeket figyelmen kívül hagyják.

Példa: Határozzuk meg a termékek átlagárát!

select avg(eladar) from cikk;

Példa: Mennyibe kerül a boltban a legdrágább termék?

select max(eladar) as Legdrágább from cikk;

Példa: Mennyi az egyes gyártóktól rendelt termékek átlagos beszerzési ára?

select nvl(gyarto, 'ismeretlen') , avg(beszerar) from cikk

group by gyarto;

Példa: Írassuk ki gyártónkénti bontásban a maximális árat, ha az meghaladja a 100 Ft-ot!

select nvl(gyarto,'ismeretlen') , max(beszerar) from cikk

group by gyarto having max(beszerar) > 100;

Példa: Hány terméket rendelünk a „00” kódú gyártótól?

select count(cikk_kod) from cikk where gyarto = '00';

Példa: Készítsünk kimutatást korosztály (10-20, 20-30,...) és nem szerinti bontásban a bűnözők

számáról!

select CONCAT(

CONCAT(TO_CHAR(round( (sysdate - szuldatum) / 3650 )*10), '-'),

TO_CHAR(round( (sysdate - szuldatum) / 3650 )*10+10) ) as Korosztály,

nem, count(1) Fő from bunozok

group by round( (sysdate - szuldatum ) /3650) , nem

order by Korosztály, nem;

Az alábbi táblázat a parancs kimenetének első pár sorát mutatja. A táblázatból leolvasható, hogy a

10-20 éves korosztályban egyetlen férfi bűnöző volt, női bűnöző ebben a korosztályban nincs

nyilvántartva. A 20-30 éves korosztálynál már férfi, és női bűnözőket is találunk, csak úgy, mint a 30-

40 illetve a 40-50 évesek között.

Korosztály Nem Fő

10-20 F 1

20-30 F 6

20-30 N 4

30-40 F 3

30-40 N 5

40-50 F 1

40-50 N 1

Feladat 18: Hány éves a legidősebb nyilvántartott bűnöző?

Feladat 19: Írasd ki a maximális óradíjat a munkák táblából!

Feladat 20: Hányféle külső illetve belső munkát végezhetnek a rabok?

Feladat 21: Hány bűnöző neve kezdődik K betűvel?

Feladat 22: Mennyi a rabok átlagos életkora?

Feladat 23: Hány gyártótól származnak a boltban lévő cikkek? (Csak az ismert gyártókat számold)!

Feladat 24: Hány cikkhez nincs megadva gyártó? (null érték szerepel)

2.4.5. Táblák összekapcsolása

Korábban már volt arról szó, hogy az összetartozó adatok, nem feltétlenül egy táblában vannak

tárolva az adatbázisban. Azt is tudjuk már, hogy a táblákban lehet külső kulcs, melynek az értékei egy

másik táblabeli kulcsértékeknek felelnek meg, így a külső kulcs alapján egyértelműen kiderül, mely

sorok tartoznak össze a két táblából.

Direkt szorzat + where feltétel

A kereszt szorzat létrehozása a táblakifejezések közé írt vesszővel, vagy a CROSS JOIN kulcsszóval

lehetséges.

SELECT ... FROM táblakifejezés { , |CROSS JOIN} táblakifejezés }

Hatására egy olyan eredménytábla jön létre, melyben szerepel a bal oldalon álló tábla összes

attribútuma, majd a jobb oldalon álló tábla összes attribútuma. Ha az attribútumok között

névegyezőség volt, akkor a bal oldali tábla attribútumnevei kerülnek megváltoztatásra. Az

eredménytáblában a két tábla sorainak összes lehetséges kombinációja pontosan egyszer jelenik

meg.

A fenti szintaktikát WHERE záradékkal kiegészítve gondoskodhatunk arról, hogy a halmazból csak a

számunkra szükséges sorok maradjanak meg. Összekapcsolás esetében ez azt jelenti, hogy a külső

kulcs attribútuma és a kapcsolódó tábla hivatkozott oszlopának (általában az elsődleges kulcs)

megfelelő relációját írjuk elő. (Megj.: az rendszer nem fogja előállítani az összes kombinációt, ha nem

kell.)

Példa: Jelenítsük meg a cikkek és gyártók sorainak összes lehetséges kombinációját!

SELECT * FROM cikk CROSS JOIN gyartok;

Példa: Jelenítsük meg a cikkek és a cikkek gyártójának neveit!

SELECT cikknev, gyartok.nev FROM cikk CROSS JOIN gyartok

WHERE gyarto = gyartokod;

Belső összekapcsolás

SELECT ... FROM táblakifejezés INNER JOIN táblakifejezés ON feltétel

Az eredményét tekintve a belső szorzat megegyezik az alábbi direkt szorzatos változattal, de nem állít

elő direkt szorzatot. Ha :

SELECT ... FROM táblakifejezés, táblakifejezés WHERE feltétel

A feltétel csak úgy, mint a WHERE záradékban tetszőleges logikai kifejezés lehet, használható

konstans, függvényhívás, attribútumnév, akár algebrai műveletekkel együtt is. De az ON után

lehetőleg csak olyan feltételt írjunk, mely a két tábla összekapcsolásához valóban szükséges. (A

feltételben mindkét tábla attribútumai szerepeljenek valamilyen operátorral összekapcsolva.)

Példa: A boltban új nyilvántartási rendszer bevezetésére készülnek, melyhez ellenőriznünk kell, hogy

a cikk kódok hosszabbak legyenek minden gyártókódnál. Jelenítsük meg azon termékek nevét, ahol a

kódot ki kell cserélni? (A hosszba a jobb oldali szóközök ne számítsanak bele.)

SELECT DISTINCT * FROM cikk INNER JOIN gyartok ON

length ( rtrim(cikk_kod) ) <= length ( rtrim(gyartok.kod) );

ROSSZ Példa, ne legyen ragadós: Kapcsoljuk össze a cikk és gyártók tábla azon sorait, ahol a

gyártókód nullával kezdődik!

SELECT cikknev, gyartokod, gyartok.nev FROM cikk JOIN gyartok

ON substr(gyartokod, 1, 1) = '0';

Helyette javasolt olyan megoldást használni, ahol első ránézésre is látszik, hogy a feltétel csak az

egyik táblára vonatkozik, és itt valójában direktszorzatról van szó. Ehhez előbb lekérdezzük azon

sorokat a gyártók táblából, ahol a gyártókód nullával indul:

select * from gyartok where substr(gyartokod, 1, 1) = '0'

Majd ezt táblaként használva előállítjuk a direkt szorzatot:

SELECT cikknev, gyartokod, nev FROM cikk, (select * from gyartok where

substr(gyartokod, 1, 1) = '0');

Külső összekapcsolás

Láthattuk, hogy a belső összekapcsolás esetén csak azok a sorok jelennek meg az eredmény táblában,

melyekhez van kapcsolódó sor a másik táblából. Ez viszont információvesztést eredményezhet.

Tegyük fel, hogy van egy Rendelesek( rendelesId, ugyfelId, cikk_kod, mennyiseg, datum) táblánk,

melyből az egyes termékek iránti keresletet az elmúlt időszakra meghatározhatjuk. Jelenítsük meg a

azt a három terméket, melyből a legkevesebb fogyott. Bár a lekérdezést a mostani tudásunkkal még

nem tudjuk megoldani, azt tudjuk, hogy a két táblát inner joinnal összekapcsolva, azok a termékek

nem is jelennének meg az eredménytáblában, amit senki sem rendelt az elmúlt időszakban, pedig

pont ezeket a termékeket lenne értelme lecserélni.

Ahhoz, hogy azok a sorok is megjelenjenek, melyhez nincs kapcsolódó sor a táblából külső

összekapcsolást kell végeznünk. Általános alakja:

SELECT ... FROM táblakifejezés {LEFT|RIGHT|FULL} OUTER JOIN táblakifejezés

ON feltétel

Baloldali külső összekapcsolás (LEFT OUTER JOIN)

A bal oldalon álló tábla minden sora bekerül az eredménytáblába a jobb oldali tábla összes olyan

sorával, mely a feltételnek eleget tesz. Ha nincs kapcsolódó sor a jobb oldali táblából, akkor a sor úgy

kerül be az eredménytáblába, hogy a jobb oldali táblához tartozó attribútumok null értékkel

töltődnek fel.

Jobboldali külső összekapcsolás (RIGHT OUTER JOIN)

Ugyan az, mint a baloldali összekapcsolás, de itt a jobboldali tábla összes sora kerül be az

eredménytáblába, vagy a hozzá kapcsolódó sorral, sorokkal, vagy annak hiányában a baloldali táblát

alkotó attribútumokon null értékekkel.

Kétoldali külső összekacsolás (FULL OUTER JOIN)

Mindkét táblából megjelenik minden sor a kapcsolódó soraikkal, valamint mindkét oldalon

megjelenik az összes kapcsolódó sorral nem rendelkező sor egyszer, melyek a másik tábla

attribútumain null értékekkel töltődnek fel.

Példa: Jelenítsük meg, hogy a gyártók mely termékeit forgalmazza a boltocska. Azok a gyártók is

szerepeljenek, akiktől semmit sem forgalmaz.

SELECT gyartokod, nev, cikk_kod, cikknev FROM gyartok LEFT OUTER JOIN cikk ON

gyarto = gyartokod;

vagy

SELECT gyartokod, nev, cikk_kod, cikknev FROM cikk RIGHT OUTER JOIN gyartok ON

gyarto = gyartokod;

Equi join (Egyenlőségen alapuló összekapcsolás)

A belső összekapcsolás olyan speciális esetének tekinthető, amikor a táblák kapcsolódó

attribútumainak páronkénti egyenlőségét írjuk elő. Természetesen ebben az esetben is használható

az INNER JOIN a megszokott szintaktikával, de ha a kapcsolódó attribútumok nevei megegyeznek,

akkor lehetőségünk van tömörebb forma alkalmazására is. Az Oracle ebben az esetben csak az egyik

táblából hagyja meg a kapcsolódó attribútumot.

SELECT … FROM táblakifejezés INNER JOIN táblakifejezés USING(attribútum)

Példa: Kérdezzük le mely bűnöző mettől meddig volt lecsukva!

SELECT nev, tol, ig FROM bunozok INNER JOIN lecsukva USING(szig);

Natural join (Természetes összekapcsolás)

A természetes összekapcsolás során a két tábla azonos nevű attribútumait tekintjük a kapcsolódó

attribútumoknak, és hasonlóan az Equi joinhoz itt is az attribútumok egyenlőségét írjuk elő. A

kapcsolódó attribútum-párok közül csak az egyik tag jelenik meg az eredménytáblában.

Természetesen ezzel most sem veszítünk információt, hiszen a feltétel alapján ezen attribútumok

neve és tartalma is azonos volt. Csupán a redundanciát szüntettük meg.

Példa: Kérdezzük le mely bűnöző mettől meddig volt lecsukva!

SELECT nev, tol, ig FROM bunozok NATURAL JOIN lecsukva;

Feladat 25: Írasd ki a bűnözők adatait, és börtöneik nevét!

Feladat 26: Írasd ki Kés Elek, és Enyves Béla milyen bűncselekményeket követett el?

Feladat 27: Írasd ki hogy, mely bűnözők vannak jelenleg fogva tartva!

Feladat 28: Enyves Béla melyik börtönben volt fogva tartva 1962.01.01-en?

Feladat 29: Börtönben volt-e Kés Elek 1971-ben? Ha igen írd ki a nevét!

Feladat 30: Írasd ki a rabok magaviseletére kapott pontszámokat! Ügyelj a NULL értékekre!

Feladat 31: Melyik börtönben vannak olyanok, akik hűtlen kezelést követtek el?

Feladat 32: Mi a különbség a két lekérdezés között?

SELECT * FROM Bunozok b inner join mb_kapcsolat mb on b.szig = mb.szig;

SELECT * FROM Bunozok b left outer join mb_kapcsolat mb on b.szig = mb.szig;

Feladat 33: Írasd ki a bűnözők foglalkozását! Ha valaki nem dolgozik ott a „munkanélküli” szó álljon.

2.4.6. Beágyazott lekérdezések

Az SQL nyelv lehetővé teszi a SELECT utasítások egymásba ágyazását, illetve később látni fogjuk, hogy

más utasításokba is ágyazhatunk be SELECT utasításokat. Az egymásba ágyazások maximális száma

255, ez tényleges korlátozást aligha jelent. Az alszelekteknek alapvetően két fajtáját

különböztethetjük meg aszerint, hogy a külső és belső SELECT milyen kapcsolatban áll egymással:

Korrelálatlan (egyszerű) alszelekt

Amennyiben a beágyazott SELECT önmagában is értelmezhető (nem függ a külső SELECT utasítástól),

korrelálatlan alszelektről beszélünk. Ebben az esetben a teljese SELECT utasítás kiértékelése során

először az alszelekt értékelődik ki és az általa előállított értékkel kerül át a külső SELECT utasításhoz,

ami ez után értékelődik ki. Az alszelekt tehát egyetlen egyszer fut le.

Korrelált alszelekt

A beágyazott SELECT önmagában nem értékelhető ki, mert hivatkozik valamely külső SELECT

utasításban szereplő attribútumra (kifejezésre). Korrelált vagy más néven kapcsolt alszelekt esetén a

külső selectnél kezdődik a kiértékelés, átadja a hivatkozott értéket a belső selectnek mely előállítja az

értékekhez tartozó eredményt. Ezután a belső select által előállított értékkel folytatódik a külső

select kiértékelése. Az alszelekt tehát újra, és újra lefut, minden átadott értéknél. Ha a külső és a

belső select azonos táblára vonatkozik akkor az egyik táblát át kell nevezni, hogy a minősített nevek

különbözzenek egymástól.

Alselectek kezelése

Az alszelektet mindig zárójelek közt kell szerepeltetni. A lekérdezések során minden alszelektet

eredményét kezelhetjük táblaként, vagyis bárhol szerepelhet, ahol korábban a táblakifejezés szót

láthattuk a szintaktikában.

Példa: Kérdezzük le azon gyártók kódját, akiktől rendelt (boltban forgalmazott) termékek átlagára

100Ft-nál nagyobb! (táblaként kezelt alszelekt, from kulcsszó után)

select * from

(select gyarto, avg(beszerar) atlagar from cikk group by gyarto )

where atlagar > 100;

Példa: Kérdezzük le azon cikkek nevét, gyártójának nevét ahol az árrés kisebb a beszerzési ár 30

százalékánál! (táblaként kezelt alszelekt egy összakapcsolásban)

select cikknev, gyartok.nev from

(select * from cikk where (eladar-beszerar) < beszerar*0.9) T

inner join

gyartok on T.gyarto = gyartok.gyartokod;

Amennyiben az alszelekt feltételben szerepel, akkor aszerint kell kezelni hány sort illetve oszlopot

adhat vissza az beágyazott lekérdezés.

Egy sort (értéket) visszaadó alszelekt

Ha a beágyazott SELECT egyetlen értéket (skalár értéket: 1 oszlop, 1 sor) állít elő – figyeljünk rá, hogy

minden körülmények közt 1 értéket kell visszakapnunk a tábla tartalmától függetlenül, különben hiba

léphet fel –, akkor úgy kezelhetjük, mintha a visszaadott érték típusának megfelelő konstanssal

dolgoznánk. Ez azt jelenti, hogy szerepeltethetjük az attribútumlistán vagy szelekciós feltételben,

szerepelhet például algebrai kifejezésekben, összehasonlításokban, de még függvények paramétere

is lehet az alszelekt.

Példa: Egy szöveg, ami minden cikk_kod mellett megjelenik:

select cikk_kod, (select 'ez_minden_sorban_megjelenik' from dual) from cikk;

Példa: Oracle alatt függvényekben is szerpelhet alszelekt.

select cikk_kod,

concat( (select 'ossze' from dual) , (select 'is fuzheto' from dual))

from cikk;

Példa: Jelenítsük meg azon termékeket, ahol a beszerzési ár meghaladja az átlagos beszerzési ár

kétszeresét!

select cikknev from cikk where beszerar > 2*(select avg(beszerar) from cikk);

Példa: Jelenítsük meg az összes cikk mellett a minimális beszerzési árat. Mi sem egyszerűbb:

select cikk_kod, cikknev, min(beszerar) from cikk; 'HIBA!!!

Jól néz ki? Talán... mégsem működik. Nem írhatunk olyan attribútumokat a csoportosító függvény

mellé, ami nem szerepel a csoportosításban. Jelenleg semmi nem szerepel, hiszen nincs is GROUP BY

záradék, ami után állhatna. De használhatjuk helyette alszelektet az attribútumlistában:

select beszerar, (select avg(beszerar) from cikk) from cikk;

vagy képezhetjük a cikkek tábla és az átlag (mint egy oszlopból és egy sorból álló tábla)

direktszorzatát:

select beszerar, Atlag from cikk, (select avg(beszerar) Atlag from cikk);

Példa: Jelenítsük meg a cikknevek mellett a termék gyártóját! (korrelált alszelekt)

select cikknev,

(select nev from gyartok where gyartokod = cikk.gyarto) As Gyarto

from cikk;

Figyeljük meg, hogy az aláhúzott rész bal oldali attribútuma a belső, a jobb oldali attribútuma a külső

select utasításban lévő táblában szerepel. Ez okozza, hogy az alszelekt önmagában nem

kiértékelhető, hiszen ha kimásolnánk a zárójelek közti részt, és futtatni próbálnánk, akkor hibajelzést

kapnánk, mivel a cikk.gyarto nem szerepel a gyartok táblában. Azt is megfigyelhetjük, hogy nincs

csoportosító függvény a belső lekérdezésben, szintaktikáját nézve akár több értéket is előállíthatna.

Jelen esetben azonban használhatjuk mivel a relációs séma alapján tudjuk, hogy minden cikk

maximum egy gyártóval rendelkezhet. (Ha nem rendelkezik gyártóval, akkor null érték kerül a

táblába. )

Halmazt visszaadó alszelekt

Amennyiben a select utasítás 0, 1 vagy több sort is visszaadhat, az eredményt használhatjuk azt

táblaként (a legutolsó példában láttuk, hogy ezt a skalárt visszaadó alszelektekkel is megtehettük),

vagy ha feltételben szerepel alszelekt, akkor a következő halmazoperátorok segítségével kezelhetjük:

ALL: Ezzel a kulcsszóval felírt feltétel akkor teljesül, ha az alszelekt által visszaadott összes sorra

teljesül a kifejezés operátor kifejezés_2 feltétel.

… kifejezés operátor ALL (select kifejezés_2 from …)

ANY: Ezzel a kulcsszóval feltétel akkor teljesül, ha az alszelekt által visszaadott sorok közül legalább

egyre teljesül a kifejezés operátor kifejezés_2 feltétel.

… kifejezés operátor ANY (select kifejezés_2 from …)

IN: Ezzel a kulcsszóval felírt feltétel akkor teljesül, ha az IN előtt álló kifejezés, vagy zárójelbe tett

kifejezések szerepelnek az alszelekt által visszaadott sorok közt.

… kifejezés1 … IN (select kifejezés2… from …)

… (kifejezés_1, … , kifejezés_n) … IN (select kifejezés_1…kifejezés_n from …)

EXISTS: Ezzel a kulcsszóval felírt feltétel akkor teljesül, ha az utána álló alszelekt legalább 1 sort

visszaad.

… EXISTS(select kifejezés2… from …)

A NOT kulcsszót az IN és az EXISTS előtt használhatjuk közvetlenül: NOT IN, NOT EXISTS. A többi

esetben csak az egész kifejezést tudjuk tagadni a NOT szóval.

… kifejezés operátor NOT IN (select kifejezés_2 from …)

… NOT ( kifejezés operátor ANY (select kifejezés_2 from …) )

Természetesen minden operátornál elvárás, hogy az összehasonlítandó értékek típusa és száma

egymásnak megfelelő legyen!

Példa: Jelenítsük meg azon cikkeket, amelyhez tartozik gyártó!

select * from cikk where gyarto in (select DISTINCT gyartokod from gyartok);

Ugyan az korrelált alszelekttel:

select * from cikk where exists (select gyartokod from gyartok where

cikk.gyarto = gyartok.gyartokod);

Példa: Jelenítsük meg azokat a „tejitalok”-at, melyeket többért szerzünk be, mint valamelyik normális

„tej”-et. (A Lower függvény kisbetűssé alakítja a paraméterét)

select * from cikk

where LOWER(cikknev) LIKE '%tejital%' and beszerar > ANY

(select beszerar from cikk where LOWER(cikknev) LIKE '%tej%');

Példa: A boltocskába minden termék kódjának első karaktere a termék típusát írja le (pl.: axx-tej, A-

joghurt, bxx-sajt, Bxx-vaj, stb, ahol xx tetszőleges karakter). A kimutatásban minden terméknél látni

akarjuk, hogy mennyivel kerül többe a beszerzése, mintha az azonos típusú legolcsóbb terméket

vásárolnánk.

select cikk_kod, cikknev, beszerar - (select min(beszerar) from cikk

where substr(cikk_kod, 1, 1)=substr(c.cikk_kod, 1, 1)) from cikk c;

vagy:

select cikk_kod, cikknev, beszerar - minar from cikk inner join

( select substr(cikk_kod, 1, 1) as tipus, min(beszerar) as minar from

cikk group by substr(cikk_kod, 1, 1) )

on substr(cikk_kod, 1, 1) = tipus;

Az első megoldás korrelált eset. Minden egyes termékre külön-külön lefut az alszelekt, ami megadja

mennyi a minimális beszerzési ár az adott terméktípusnál. A második megoldásnál előbb minden

terméktípusra kiszámítjuk a minimális értékeket, majd ennek eredményét táblaként kezelve

hozzákapcsoljuk a cikkek táblához az első karakter alapján.

Beágyazott lekérdezéssel oldjuk meg a következő feladatokat!

Feladat 34: Mely „tejitalok”-at szerezzük be drágábban, mint az összes „tej”-et!

Feladat 35: Írassuk ki azon bűnözőket, akik még sosem kerültek börtönbe!

Feladat 36: Mely férfi bűnözők voltak külső munkán 1980.01.01 után? (TO_DATE)

Feladat 37: Kik követtek el gyilkosságot?

Feladat 38: Írasd ki azokat a bűnözőket, akik magaviseletre kaptak pontot.

Feladat 39: Kik vannak szabadlábon a bűnözők közül? (Nincs börtönben, sem előzetesben.)

Feladat 40: Írasd ki „EXISTS”-el azokat a bűnözőket, akik börtönhöz vannak rendelve!

2.4.7. Első n sor lekérdezése

A ROWNUM egy pszeudo-oszlop, mely azt adja meg hányadikként olvasta ki az Oracle a táblából vagy

a halmazból az adott sort. Olyankor használható, amikor egy táblának, vagy halmaznak a legelső

valahány sorára van szükségünk. A peszudo-oszlop azt takarja, hogy az oszlop fizikailag nincs tárolva,

de úgy kezelhetjük mint, minden más attribútumot. A számozás 1-től indul, és egyesével növekszik.

Példa: Jelenítsük meg a cikkek tábla adatait sorszámmal ellátva a sorokat.

select ROWNUM, cikk.* from cikk;

A ROWNUM használatának leginkább rendezett adatoknál van értelme, ezért gyakran egy olyan

select where feltételeként jelenik meg, mely egy alszelektet tartalmaz az adatok rendezésére.

Példa: Jelenítsük meg a maximális eladási áru cikket! (Egyezés esetén a kod szerint kisebbet.)

select * from

(select cikk.* from cikk order by nvl(eladar,0) DESC, cikk_kod)

where rownum <= 1;

2.4.8. Összetett lekérdezések

Példa: Írjuk ki azon gyártó(k) nevét, mely(ek)nek a legtöbb termékét forgalmazza a boltocska (az

ismeretlen gyártók nem érdekesek).

Az összetettebb feladatokat érdemes részfeladatokra bontani. Attól a résztől kell kiindulni, mely

önmagában is meghatározható. Ebben a példában az első lépés a gyártók által forgalmazott

termékek darabszámának meghatározása:

select count (*) from cikk

where gyarto is not null -- csak az ismert gyártójú cikkeket számolja

group by gyarto -- gyartonkent szamol

Vagy kihasználhatjuk azt, hogy a count függvény a null értékeket kihagyja a számításból, ha nem *-ot

írunk a paraméter helyére. Ekkor a gyarto attribútumot kell paraméternek beírni, más nem jó!

select count (gyarto) from cikk -- ahol a gyarto null 0-at ad vissza

group by gyarto -- gyartonkent szamol

Ezek után meg kell határoznunk ezek közül a maximálisat. Szerencsére az ORACLE megengedi hogy a

csoportosított oszlopokon maximumot is számoljunk, ezért nem szükséges alszelektet használunk, ha

a csoportosítás utáni eredmények közül kell a maximumot lekérdezni. Egész egyszerűen bővítsük ki a

fentiek közül a szimpatikusabb megoldást egy max függvénnyel:

select max( count(*) ) from cikk

group by gyarto;

Már csak annyi dolgunk maradt, hogy megadjuk melyik gyártóhoz tartozik ez a maximum. Ehhez újra

meghatározzuk azt, hogy melyik gyártótól hány terméket forgalmaz a boltocska - de most

összekapcsoljuk a gyártó táblával is annak érdekében, hogy a gyártó neve is szerepeljen - és egy

HAVING záradék segítségével kiválasztjuk azokat a sorokat, ahol a darabszám egyezik a maximális

számmal.

select gyartokod, nev from gyartok inner join cikk on gyarto = gyartokod

group by gyartokod, nev

having count(gyarto) =

(select max ( count (gyarto)) from cikk

group by gyarto);

Vegyük észre, hogy a gyartokod mellett a gyártók neve is bekerült a csoportosító mezők közé, az a

kérdés, hogy megtehetjük-e ezt, vagy ez megváltoztatja a csoportokat (csoportokon belül több

alcsoport áll majd elő). Tudjuk, hogy az egy csoportba tartozó sorokban a gyartokod azonos, hiszen e

szerint csoportosítottuk a sorokat. Alcsoportok akkor jelennek meg, ha egy csoporton belül a másik

csoportosító mező alapján többféle érték is előfordul, vagyis ha egy gyártó kódjához több gyártónév

is tartozna. Ez viszont nem lehetséges, hiszen a gyartokod az elsődleges kulcs, ami egyértelműen

azonosítja a gyártót. (Általános esetben is igaz, ha egy tábla elsődleges kulcsa alapján csoportosítunk,

akkor a tábla tetszőleges attribútuma felvehető a csoportosító kifejezések közé az elsődleges kulcs

után, anélkül, hogy az a csoportosítás eredményét befolyásolná. Az elsődleges kulcs szerinti

csoportosításnak akkor van értelme, ha korábban összekapcsoltuk más táblával.)

Példa: Mely bűnöző(k) voltak legtöbbször lecsukva?

Hasonlóan az előző példához most is a számlálással kezdünk, vagyis meghatározzuk ki hányszor volt

lecsukva:

select szig, count(1) from Lecsukva

group by szig;

Válasszuk ki ebből a maximumot! Itt fájó szívvel elbúcsúzunk attól az információtól kikhez tartozik a

maximum, hiszen a max függvény a számlálás utáni összes soron hajtódik végre (nincs csoportosítás),

ezért nem írható mellé a személyi igazolvány számokat tartalmazó oszlop.

select max ( count(1) ) Lecsukva

group by szig;

És most visszaszerezzük azt az információt, melyet az előbb elvesztettünk. Ehhez újból csoportosítjuk

a lecsukva tábla sorait a személyi igazolványszám alapján, és leválogatjuk azokat a csoportokat, ahol

a maximummal egyező a sorok száma:

select szig from Lecsukva

group by szig

having count(1) = (select max( count(1)) from Lecsukva

group by szig);

Már csak azt kell kiderítenünk kihez tartozik ez a szig. szám. Ehhez vagy az előbbihez hasonlóan

összekapcsoljuk a táblákat, vagy alszelekttel oldjuk meg a feladatot:

select * from bunozok where szig in (

select szig from Lecsukva

group by szig

having count(1) = (select max( count(1)) from Lecsukva

group by szig)

);

A maximum kiválasztás helyett használhatjuk a következő halmaz operátort is:

select * from bunozok where szig in (

select szig from Lecsukva

group by szig

having count(1) >= ALL (select count(1) from Lecsukva

group by szig)

);

Példa: Az öt legolcsóbb (beszerzési ár) termék közül hányat gyárt a Bali?

Első lépésként rendezzük a beszerzési árakat növekvő sorrendben:

select beszerar from cikk order by beszerar;

Válasszuk ki az első 5 beszerzési árat (elég csak a különbözőket megtartani, de az ismétlődés se

gond):

select distinct beszerar from

(select * from cikk order by beszerar)

where rownum <= 5;

Most nézzük meg, hány olyan Bali termék van, aminek a beszerzési ára benne van az előbb előállított

halmazban:

select * from cikk inner join gyartok on gyarto=gyartokod

where nev = 'Bali' and beszerar in

( select distinct beszerar from

(select * from cikk order by beszerar)

where rownum <= 5 ) ;

Példa: Jelenítsük meg melyik típusú terméknél mennyi eltérés van a legjobb és a legrosszabb

beszerzési ár közt. (Emlékeztetőül: a termék típusát a cikk kódjának első karaktere hordozza (kis és

nagybetű eltérő))

select max(beszerar)-min(beszerar) , from cikk

group by substr( cikk_kod, 1, 1);

Példa: Jelenítsük meg egy termék típuson belül melyik(ek) a legolcsóbb, és melyik(ek) a legdrágább

cikk(ek).

Határozzuk meg az előzőhöz hasonlóan a legrosszabb beszerzési árakat minden típushoz:

select substr(cikk_kod, 1, 1) T, max (beszerar) Ar from cikk

group by substr(cikk_kod, 1, 1);

Kapcsoljuk hozzá a legjobb beszerzési árakat is:

select substr(cikk_kod, 1, 1) T, max (beszerar) Ar from cikk

group by substr(cikk_kod, 1, 1);

union all

select substr(cikk_kod, 1, 1) T, min (beszerar) Ar from cikk

group by substr(cikk_kod, 1, 1);

Most már nincs más dolgunk, csak összekapcsolni a cikkek táblával a kapott halmazt, hogy megtudjuk

melyik cikkhez tartozik a típus, és a beszerzési ár páros. A jobb átláthatóság miatt egyúttal rendezzük

is a sorokat:

select T, cikk_kod, nvl(cikknev, 'nevtelen'), beszerar from

cikk

inner join

(select substr(cikk_kod, 1, 1) T, max (beszerar) Ar from cikk

group by substr(cikk_kod, 1, 1)

union all

select substr(cikk_kod, 1, 1) T, min (beszerar) Ar from cikk

group by substr(cikk_kod, 1, 1) )

on substr(cikk_kod, 1, 1) = T and beszerar = Ar

order by T, beszerar;

Természetesen előfordulhat, az is, hogy ugyan azok a termékek a legolcsóbbak és a legdrágábbak is

egyben. Az összekacsolás helyett szintén alkalmazhatjuk az in operátort is, hiszen érték n-esek

tartalmazását is vizsgálhatjuk vele. A különbség annyi lesz, hogy úgy egy cikk csak egyszer kerül be a

táblába.

select substr(cikk_kod, 1, 1) T, cikk_kod, nvl(cikknev, 'nevtelen'), beszerar

from cikk

where ( substr(cikk_kod, 1, 1), beszerar ) in

(select substr(cikk_kod, 1, 1), max (beszerar) from cikk

group by substr(cikk_kod, 1, 1)

union all

select substr(cikk_kod, 1, 1), min (beszerar) from cikk

group by substr(cikk_kod, 1, 1) )

order by T, beszerar;

Feladat 41: Hány bűnöző volt több alkalommal lecsukva? Névsor szerint rendezve írasd ki!

Feladat 42: Kik voltak többször is lecsukva? Lecsukás és névsor szerint rendezve írasd ki!

Feladat 43: Melyik munkát végezték a legtöbbször a bűnözők?

Feladat 44: Melyik munkát végezték a legtöbben a bűnözők közül?

Feladat 45: Ki a legidősebb bűnöző? (elég egyet megjeleníteni)

Feladat 46: Ki a legidősebb bűnöző? (azonosság esetén minden nevet írjon ki)

Feladat 47: Bedi Lizett mennyit keresett összesen a börtönévei alatt végzett munkával?

Feladat 48: Melyik börtönben lehet az átlagosnál több rabot fogva tartani?

Feladat 49: Mit követett el az a bűnöző, aki a leghosszabb börtönbüntetést kapta?

Feladat 50: Ki volt leghosszabb ideig börtönben, ha az összesen hűvösön töltött éveket tekintjük?

3. Függelék

3.1. Boltocska kezdetleges cikk nyilvántartó rendszere

Cikkek:

cikk_kod: A termékek egyeni azonosító száma. Első karaktere típusmegjelölésként használt.

gyarto: Külső kulcs. Meghatározza melyik terméket melyik gyártótól rendeli a bolt. A nyilvántartás nem teljes, ezért még előfordulnak null értékek.

beszerar: A termék beszerzési ára

eladar: A termék eladási ára. Még nincs mindenhol feltöltve, ezért itt is vigyázni kell a null értékek kezelésére!

A beszerzési ár mindig kisebb vagy egyenlő, mint az eladási ár. Valamint nem szerepelhet ugyanattól a gyártótól két egyforma nevű termék.

Cikk

Cikk_kod Char(3)

Cikknev Varchar2(40)

Gyarto Char(2)

Beszerar Numeric(6) NOT NULL

Eladar Numeric(6)

Gyartok

Gyartokod Char(2)

Gyartonev Varchar2(40) NOT NULL

3.2. Fiktív bűnügyi nyilvántartó rendszer séma

A táblákat, és a köztük lévő kapcsolatokat az alábbi ábra tartalmazza. A táblázatok fejléce a tábla adatbázisbeli nevét tartalmazza. A sorok a táblában

szereplő mezőket és azok típusát valamint néhány esetben a hozzájuk kötődő megszorításokat írják le. A félkövér mezők a tábla elsődleges kulcsát jelölik.

Bunozok: A nyilvántartásba vett bűnözők adatainak tárolására szolgál.

Szig: személyi igazolvány szám

Borton: A magyarországi büntetés-végrehajtási intézetek adatainak tárolására szolgál.

Kapacitás: a börtönben elhelyezhető rabok száma

Fiatalkorúak: fiatalkorúak számára fenntartott intézmény

Nem: F, N, K, rendre: férfi, női, koedukált börtön

Buntenyek: A bűntények megnevezését, és a bűntények elkövetése esetén kiszabható minimális és maximális büntetés mértékét tartalmazza (években).

Lecsukva: Ez a tábla tartalmazza ki (szig), mettől (tol) meddig(ig), hol (bortonid) volt lecsukva és mit (buntenyid) követett el.

Magaviselet: -1, 0, 1 és null értéket vehet fel, pozitív magaviselet esetén a rabok előbb szabadulhatnak, illetve külső munkavégzésre is beoszthatók.

Munkak: A börtönben illetve a börtönön kívül (külsőmunka = 'I') rabok által végezhető munkák adatai.

Fizetés: az adott munkához kapcsolódó bér. Jelenleg órabérben van megadva.

Munkaidő: napi munkaórák száma.

Dolgozik: Ez a tábla tartalmazza ki (szig), mikortól (tol), meddig(ig), milyen munkát (mit) végzett.

Bunozok

Szig Char(8)

Nev Varchar2(50)

Szuldatum Date

Nem Char(1) (N, F)

Betegseg Varchar2(40)

Elozetes Char(1) (I, N)

Lecsukva

Szig Char(8)

BortonId Number(2)

Buntenyid Number (4)

Tol Date

Ig Date

Magaviselet Number(2) (-1, 0, 1)

Borton

BortonId Number(2)

Nev Varchar2(80)

Varos Varchar(40)

Kapacitas Number(4)

Fiatalkoruak Char(1) (I ,N)

Nem Char(1) (F, N, K)

Munkak

Munkaid Number(4)

Megnevezes Varchar2(50)

Kulsomunka Char(1) (I, N)

Fizetes Number(5)

Munkaido Number(2)

Dolgozik

Szig Char(8)

Tol Date

Ig Date

Mit Number(4)

Buntenyek

Buntenyid Number (4)

Megnevezes Varchar2(80)

MinBuntetes Number(2)

MaxBuntetes Number(3)