You are on page 1of 180

Joe Celko

SQL-fejtrk

Aki

ebbl

l,

vegye

meg!

A kiadvny a kvetkez angol eredeti alapjn kszlt:


Joe Celko: Joe Celko's SQL Puzzles & Answers
Copyright 1997 by Elsevier Inc. All rights reserved!
Translation Copyright 2003 by Kiskapu Ltd. All rights reserved!
No part of this book, including interior desing, cover design, and icons, may be reproduced
or transmitted in any form, by any means (electronic, photocopying, recording, or otherwise)
without the prior written permission of the publisher.
Trademarked names appear throughout this book. Rather than list the names and entities that
own the trademarks or insert a trademark symbol with each mention of the trademarked
name, the publisher states that it is using the names for editorial purposes only and to the
benefit of the trademark owner, with no intention of infringing upon that trademark.
A szerzk s a kiad a lehet legnagyobb krltekintssel jrt el e kiadvny elksztsekor.
Sem a szerz, sem a kiad nem vllal semminem felelssget vagy garancit a knyv
tartalmval, teljessgvel kapcsolatban. Sem a szerz, sem a kiad nem vonhat felelssgre
brmilyen baleset vagy kresemny miatt, mely kzvetve vagy kzvetlenl kapcsolatba
hozhat e kiadvnnyal.
Magyar vltozat 2003 Kiskapu Kft. Minden jog fenntartva!
Felels szerkeszt: Szy Gyrgy
Fordts: Tth Lszl
Lektor: Rzmves

Lszl

Mszaki szerkeszt: Csutak Hoffmann


Trdels: Csutak Hoffmann

Leixmte

Levente

Felels kiad a Kiskapu Kft. gyvezet igazgatja


Fordts 2003 Kiskapu Kft. Minden jog fenntartva!
1081 Budapest, Npsznhz u. 29.
Telefon: (+36-1) 303-9119, 477-0443
Fax: (+36-1) 303-1619
http://www. kiskapu. hu/
e-mail: kiskapu@kiskapu.hu
ISBN: 963 9301 53 1

Kszlt a debreceni Kinizsi Nyomdban


Felels vezet: Brds Jnos

ttekints

Elsz
1. fejezet: Adatmeghatrozs

xiii
1

2. fejezet: Adatformzs

33

3. fejezet: Adatkivlaszts

49

4. fejezet: Szmtsok

83

5. fejezet: Adatok csoportostsa

109

Trgymutat

153

Tartalomjegyz

1. fejezet:

Adatmeghatrozs
Denormalizlt adatbzisok
Rossz kdolsi rendszerek
1. feladvny - Tblk ltrehozsa
A megolds
2. feladvny - A munkahelyi tvollt kezelse
1. megolds
2. megolds
3. feladvny - rzstelents
Megolds
4. feladvny - Biztonsgi azonostk
Megolds
5. feladvny - Az adatok formzsa
Megolds
6. feladvny - Szllodai szobafoglals
Megolds
7. feladvny - Iratok
Megolds

1
2
3
3
5
6
7
10
13
15
15
17
17
18
18
19
20

vi

SQL-fejtrk

8. feladvny - Nyomtatk idbeosztsa


Megolds
9. feladvny - Szabad helyek
1. megolds
2. megolds
3. megolds
10. feladvny - A munka jutalma
1. megolds
2. megolds
11. feladvny - Munkarend
Megolds

2. fejezet:

Adatformzs
12. feladvny - Alperesek, llapotok
1. megolds
2. megolds
3. megolds
13. feladvny - Oktatk
1. megolds
2. megolds
14. feladvny - Telefon
Megolds
15. feladvny - A kt legutbbi alapbr
1. megolds
2. megolds
3. megolds
4. megolds
5. megolds

3. fejezet:

24
25
26
27
27
27
28
29
30
31
32

34
36
36
37
38
38
39
40
41
43
44
45
46
47
47

Adatkivlaszts
16. feladvny - Folyamatok
1. megolds
2. megolds
17. feladvny - Munkakzvett iroda
1. megolds
2. megolds

49
50
52
54
55
56

Tartalomjegyzk

3. megolds
18. feladvny - Reklmlevl
1. megolds
2. megolds
19. feladvny - A legjobb rtkestk
Megolds
20. feladvny - Teszteredmnyek
1. megolds
2. megolds
21. feladvny - Replgpek s piltk
1. megolds
2. megolds
22. feladvny - Az dltulajdonos
Megolds
23- feladvny - Folyiratok eladsa
1. megolds
2. megolds
24. feladvny - Tzbl egy
1. megolds
2. megolds
3.megolds
4. megolds
25. feladvny - Mrfldkvek
1. megolds
2. megolds
3. megolds
26. feladvny - Folyamatbrk
1. megolds
2. megolds
3. megolds
27. feladvny - Egyenl halmazok megkeresse
1. megolds
2. megolds
3.megolds
4. megolds

58
58
59
59
60
61
63
63
63
64
64
64
65
66
66
67
68
69
70
70
71
72
72
73
74
74
75
76
77
77
78
79
79
80
81

SQL-fejtrk

4. fejezet:

Szmtsok
28. feladvny - A szinusz fggvny kiszmtsa
1. megolds
2. megolds
29. feladvny - Keressk meg a mduszt!
1. megolds
2. megolds
3. megolds
30. feladvny - tlagos vsrlsi srsg
1. megolds
2. megolds
31. feladvny - Az sszes termk megvsrlsa
1. megolds
2. megolds
32. feladvny - Adszmts
Megolds
33. feladvny - rtkcskkens
Megolds
34. feladvny - Tancsadi djazs
1. megolds
2. megolds
35. feladvny - Ignylsek
1. megolds
2. megolds
36. feladvny - Ktszeres illetk
1. megolds . . .
2. megolds
37. feladvny - Mozg tlag
1. megolds
2. megolds
3. megolds

5. fejezet:

84
84
84
86
86
87
87
88
89
90
90
91
92
92
94
96
97
99
100
101
102
103
104
104
106
106
107
107
108
108

Adatok csoportostsa
38. feladvny - Kltsgvetsi jelents
Megolds
39. feladvny - Halszmlls
1. megolds

110
111
112
113

Tartalomjegyzk

2. megolds
3. megolds
40. feladvny - Diplomaszerzs
41. feladvny - Modellprok
1. megolds
2. megolds
3. megolds
42.feladvny - Pepperoni
1. megolds
2. megolds
43. feladvny - ruhzi akcik
1. megolds
2. megolds
44. feladvny - lhelyszakaszok
1. megolds
2. megolds
45. feladvny - Csoportok felbontsa
1. megolds
2. megolds
46. feladvny - Eszkzgyr
Megolds
47. feladvny - Hrombl kett
1. megolds
2. megolds
3. megolds
48. feladvny - Becslt s tnyleges kltsgek
Megolds
49. feladvny - Szemlyzeti krds
Megolds
50. feladvny - Lovi
1. megolds
2. megolds
51. feladvny - Szllodai szobk
1. megolds
2. megolds
Trgymutat

114
114
115
118
120
121
121
121
122
123
123
125
126
128
128
129
129
130
134
136
137
139
139
140
140
141
143
144
145
147
147
148
148
149
151
153

Eloszo
l

Michael-nek

- most mr van egy meggyz rvem


szmodra a szolipszizmussal
szemben.

Az elzmnyek
Tbb mint egy vtizeden t rtam cikkeket szmtstechnikai folyiratokba, de az
olvask csak azokra emlkeznek, amelyek az adatbziskezels s az SQL tmjval
foglalkoztak. Az vek sorn lelkes szszlja lettem az ANSI/ISO szabvnyoknak
s adatbzis-programozsi mdszereknek, s idkzben vilgszerte elismert adat
bzis-felhasznlv vltam. Vagy legalbbis szeretem ezt hinni.
Hrnevemet a Miller Freeman-fle Database Programming & Design folyirat 1990 ja
nuri szmban indul s 1992-ig megjelen Celko on SQL (Celko az SQL-rl) cm
rovattal kezdtem megalapozni. Nhny cikkem mr korbban is megjelent a maga
zinban, ezek biztostottk szmomra a kezdeti figyelmet. Egy rovat esetben a leg
jobb fogs az olvasi visszajelzsek fogadsa - az kevs, ha az olvask ismerik az
embert, valahogy be kell vonni ket a tmba. Valamilyen trkkt kell alkalmazni.

xiv

SQL-fejtrk

Nhny rovat kitallt szereplket sorakoztat fel ebbl a clbl, s egy kis folytat
sos szappanopert hoz gy ltre; msok zleti pletykkkal prblkoznak. Megfon
toltam ezek lehetsgt is, de rjttem, hogy nem tudok sem prbeszdeket, sem
regnyt rni. Ehelyett azt a cselt alkalmaztam, amit mr a korbbi vekben kzlt
rovataimnl is: minden cikkemet egy programozsi feladattal zrtam, aminek meg
oldst az olvasra bztam. A megolds a kvetkez szmban jelent meg, a javasla
tokhoz rt megjegyzsekkel egytt. Az olvask visszajelzsei pozitvnak bizonyul
tak, aminek az oka nyilvnval: a programozk szeretnek problmkat megoldani
- s szeretik a nevket nyomtatsban ltni.
A DBMS magazin (M&T Publishing, amg Miller Freeman meg nem vsrolta) teljes
munkaidre alkalmazott, gy felhagytam a Database Programmng & Desgn-nzk
szabadszknt rt cikkeimmel. 1992 mjusban SQL Explorer cmmel indtottam el
a rovatomat a DBMS-ben. 1996 prilisban a rovat cme SQL for Smarties-ra vlto
zott s a mai napig mkdik. A cikkek vgn lv feladvnyokat megtartottam, de
a szerkeszt kvnsga az volt, hogy a megolds ugyanabban a szmban jelenjen
meg, mint a feladat.
Mialatt a DBMS-n\ dolgoztam, a berlini fal leomlott, Nmetorszg jraegyeslt,
a Deutsche Bank pedig behajtott egy ktelezvnyt az M&T nmetorszgi anyavlla
latval szemben. Hirtelen jra a rgi szerkesztim s bartaim vettek krl. Term
szetesen azonnal felmondtak nekem; vgl is a 80-as veket rtuk, karcsstani, b
vteni vagy racionalizlni kellett mindenkppen. De a rovatomat megtartottam s
tovbb rhattam SQL-feladvnyaimat a cikkekhez.
Ltrehoztam emellett egy msik, SQL-feladvnyokat megjelentet rovatot a Boxes
and Arrows cm, kis pldnyszm szakmai folyiratban, amely az IDMS-szel s
egyb nagygpes adatbziskezel rendszerekkel dolgoz adatbzisfelgyelk,
rendszerelemzk szmra jelent meg. Itt 1989 oktbertl a folyirat 1994 decem
berben trtnt megsznsig jelentek meg a cikkeim.

Elsz

Mirt vlasztottam a feladvnyok formjt?


Legtbbnk eljrskzpont (procedurlis") nyelveken ntt fel s nem kis erfe
sztsnkbe kerlt, hogy a nem eljrskzpont SQL nyelv hasznlatt elsajttsuk.
Senki nem tantott meg minket erre a gondolkodsmdra. A tancsadsbl szrma
z bevteleim nem kis rsze mg manapsg is olyan rendszerek tisztba tevsbl
szrmazik, amelyekben az SQL-tblkat csak szerkezet nlkli llomnyokknt
hasznljk, a programot pedig a kioldkban (trigger") s trolt eljrsokban elrej
tett eljrskzpont programkd helyettesti. Artemus Ward szavaival lve: Nem az
rjt meg, amit nem tudsz, hanem amirl tudod, hogy nem igaz."
A feladvnyok itt olvashat gyjtemnye nem pusztn a magazinokban megjelent
anyag jrakzlse. A megoldsok magyarzatait - st gyakran magukat a feladato
kat - a rendelkezsre ll hely korltozottsga miatt nem minden esetben rszle
tezhettem olyan mrtkben, amennyire kvnatos lett volna. Sokszor tbb lehets
ges megolds is ltezik, amelyek egy rsze az Olvasi levelek (Letters to the Editor)
rovatban sszefoglalva hnapokkal ksbb megjelent, de az is elfordult, hogy
egyltaln nem kerlt sor kzlskre. Ez a knyv most lehetsget teremt szmom
ra mind a feladatok, mind pedig a lehetsges megoldsok bvebb magyarzatra.
Ugyanakkor mdomban ll bemutatni az SQL-programozk helyes gondolkods
mdjt. vtizedekkel ezeltt, Fortran-programozknt nem kis bszkesggel
mondtuk magunkrl, hogy brmit meg tudunk rni Fortran nyelven. gy szlettek
a kereskedelmi matematikai programcsomagok, amelyek Fortran tmbkkel ut
noztk a Cobolt, s a LISP mutatit is ezekkel a Fortran tmbkkel hamistottuk, s
gy tovbb.
A buta programozi fogsok" e nemes hagyomnyt folytatva magam is ltrehozja
voltam olyan problmknak, amiknek az SQL-ben nem kellett volna felbukkaniuk, s
rszletesen kidolgoztam ezeket a pldkat - nem azrt, hogy megmutassam, gy is le
hetsges, hanem az SQL irnybl val krds-megkzelts mdjt bemutatand.
Ma a Vilghl kort ljk, gy a feladvnyok megoldsi mdjai llandan bvl
nek. Lehet, hogy a rlam kialakult kp veszt a csillogsbl, mgis el kell ismer
nem, hogy az vek sorn az eredeti megoldsok kzl sokat sikerlt az olvasknak
tlszrnyalni.

XV

xvi

SQL-fejtrk

Nem prbltam a feladvnyokat sem idrendi, sem bonyolultsgi sorrendbe llta


ni. Nem volt a problmk megjelensben semmilyen szablyszersg, s arra sem
tudok biztos mdszert, hogy az egyes pldk bonyolultsgt ssze lehessen hason
ltani. Ehelyett egy kevsb formlis csoportostsi mdszert vlasztottam.
A krdsek megoldsainl prbltam az rintett szemlyekrl emltst tenni; ha va
lakirl megfeledkeztem, ezton krem elnzst.

A tmakrk
Prbltam fejezeteket kialaktani, hogy a knyv ne pusztn egyms utni feladat
halmazok listjbl lljon. Minden fejezet olyan problmkat tartalmaz, amelyek
megoldsai egy kzs rendezelv kr csoportosthatk. Nmileg nknyesen az
albbi t osztlyt hoztam ltre:
1. Adatmeghatrozs
2. Adatformzs
3. Adatok kivlasztsa
4. Szmtsok vgzse
5. Adatok csoportostsa
E rendszerezs gyengesge, hogy egy feladvny egyes megoldsai klnbz cso
portokba tartozhatnak. Mg rosszabb esetben akr egy megolds is osztlyozhat
tbbflekppen, ha tbbfle fogst alkalmaz. Minden fejezet elejn megprblom
meghatrozni azokat a kzs jellemzket, amelyek meghatrozzk az adott csopor
tot, de mg ez is csak nmileg segt eligazodni. gy csak azt krhetem az Olvastl,
hogy legyen elnz velem szemben.

Elsz

Hibajavtsok s ksbbi kiadsok


Szvesen fogadok minden hibajavtst, j fogst, trkkt, egyb javaslatot a knyv
jvbeli kiadsaival kapcsolatban. Az tleteket az albbi cmre vrom:
Joe Celko
235 Carter Avenue
Atlanta, GA 30317
e-mail: 71062.1056@compuserve.com

A kiadmon, a Morgan Kaufmannon keresztl is kapcsolatba lphet velem brki.


rdemes, hiszen nyomtatsban lthatja a nevt az Olvas!

Akiket ksznet illet


Ksznetet szeretnk mondani Diane Cerranak a Morgan Kauffmantl, Dvid
Klmnnak s Maurice Frank-nek a DBMS magazintl, Dvid Stoddernek,
a Database Programming & Design, Phil Chapnik-nek, a Miller Freeman, s Frank
Sweet-nek, a Boxes and arrows munkatrsnak. Ksznm a Smith Barney alkal
mazsban ll Richrd Romley-nak a mg jobb feladatmegoldsokat, s ksznet
mindazoknak, akik az vek sorn levelekkel segtettk a munkmat.

xvii

N ehany szo a szerzrl


ft

irt

Joe Celko az Atlantban mkd Northern Lights Software Ltd. tancsadja. 1987tl tagja az ANSI X3H2 adatbzisszabvnyokkal foglalkoz bizottsgnak (ANSI
X3H2 Database Standard Committee), rszt vett az ANSI/ISO SQL-89 s SQL-92
szabvnyok kidolgozsban.
Celko az elmlt 11 vben rendszeresen jelentetett meg cikkeket a szmtstechnikai
magazinok havi vagy ktheti rovataiban. Jelenleg a kvetkez magazinokban van
rovata: DBMS magazin (Miller Freeman) SQL Explorer", Powerbuilder
Developers'
Journal (SysCon) WATCOM SQL Corner", Computing (VNC Publications, UK)
Celko on Software".
Legfrissebb cikkei: Celko on SQL" {Database Programming & Design, Miller
Freeman), SQL Puzzle" {Boxes and Arrows, Frank Sweet Publishing),
DBMS/Report" {System Integration, Cahner-Ziff), Data Desk" {Tech Specialist,
R&D), Data Points" {PC Techniques, Coriolis Group), s a szerkesztje a Puzzles
and Problems" rovatnak is az Abacus cm folyiratban (Springier-Verlag).

XX

SQL-fejtrk

Szerzje kt, az SQL-rl rt knyvnek: SQL for Smarties (Morgan Kaufmann;


a magyar vltozat a Kiskapu Kiadnl jelent meg SQL felsfokon cmmel) s Instant
SQL (Wrox Press). Mindkett 1995-ben jelent meg elszr. Kvetkez knyve
a Morgan Kaufmann gondozsban megjelen knyvsorozat rszeknt lt majd
napvilgot, s az adatbzisok mkdsnek alapelveivel foglalkozik.
Celko rendszeres eladja s gyakorl SQL-oktatja a Digital Consulting Inc,
a Norm DiNardi Enterprises, valamint a Boston University Corporate Education
Center intzmnyeknek s a Miller Freeman-fle szeminriumoknak.

Adatmeghatrozs
Amikor valaki egy SQL-feladvnnyal tallja szemben magt, az els, hogy egy le
krdezst prbl elkpzelni, ami vlaszt ad az adott krdsre. Nagyon gyakran
azonban a gond magukban az adatokban gykerezik, s egy kis vltoztats a tb
ln a bonyolult krdst nagymrtkben leegyszerstheti.

Denormalizlt adatbzisok
Az adatszerkezeti problmknak tbb fajtja ltezik. Tapasztalhatjuk, hogy sokan
a teljestmny javtsa rdekben denormalizljk az adatbzist, de ennek gyakran
ms mdon fizetik meg az rt. Nevezetesen akkor, amikor egy A lekrdezs egy
szerstse cljbl denormalizlt adatbzis a B, c s D lekrdezseket bonyolultt,
megbzhatatlann vagy ppen lehetetlenn teszi. Erre a problmra tbb megolds
is ltezik:
1. Mindig azok legynk, akiknek az A lekrdezst kell megrniuk. Ez sajnos
nem mindig megvalsthat.
2. Hozzunk ltre C H E C K () megszortsokat a denormalizls ltal megsem
mistett kapcsolatok biztostsa cljbl. Ez az SQL-92 szabvny alapjn
mr lehetsges, az albbi kt j jellemznek ksznheten:
Egy tbla C H E C K () megszortsai hivatkozhatnak az adott smban lv
msik tblra. A C H E C K () megszorts tovbbra is egy tblhoz kapcsol
dik s csak akkor kerl sor az ellenrzsre, ha az adott tbla megvltozik.

SQL-fejtrk

Az SQL-92 rendelkezik a C R E A T E A S S E R T I O N deklarcival (bevezetssel)


is, amely egy olyan ellenrzst jelent, ami nem egy bizonyos tblhoz,
hanem az egsz smhoz ktdik. Br ez mg nincs teljesen megvalst
va, kpes olyan dolgokra, amire a C H E C K () megszorts nem.
3. Hasznljuk a C R E A T E V I E W utastst a tbla jranormalizlsra. Az SQL92 jellemzibl kifolylag a V I E W nem is felttlenl szksges: a nzet
tbla ( V I E W ) meghatrozsa mindenhov beszrhat, ahol a nzettbla
neve ll a lekrdezsben.
A gyakorlatban azonban a V I E W sokszor jobb megoldst jelent, knnyeb
ben olvashatv teszi a lekrdezst s a teljestmnyre sincs szmottev
hatsa. Tovbbi elnye, hogy ha az alapjul szolgl tblk megvltoznak,
a szksges mdostsokat a nzettbla tovbbviszi az sszes olyan lekr
dezsbe, ami hasznlja, megkmlve a programozt attl a rmlomtl,
hogy egyenknt kelljen megkeresnie az sszes elfordulst a kdban.
n - ms szerzkkel ellenttben - nem ellenzem a denormalizlst, inkbb abba
a kategriba helyezem, mint egy bonyolultabb agymttet: ha fejfjssal fordulnak
hozznk, nyilvn nem ezzel kezdjk a gygytst.

Rossz kdolsi rendszerek


A rossz kdolsi rendszer (kdolsi sma) az egyik olyan tma, amivel nagyon fel
tudom hzni magam, s az SQL felsfokon cm knyvemben bven volt is monda
nivalm ezzel kapcsolatban.
Hogy rzkeltessem, mi a klnbsg egy jl s egy rosszul megtervezett kdolsi
sma kztt, vessk ssze az arab szmolsi rendszert a rmai szmokkal val m
veletvgzssel. A Dewey-fle katalogizl rendszer eltt nem volt kt knyvtros,
aki ugyanolyan elv szerint rendezte volna el a knyveit; nem lehetett a klnbz
knyvtrakban egyszeren megkeresni a knyveket. Valjban a knyvtros gondo
latmenetnek ismerete nlkl nem lehetett megtallni egy mvet. Csak a jtk ked
vrt prbljunk kitallni egy tucat besorolsi lehetsget egy knyv szmra,
amelynek tmja a kzpkori r templomok ptszete. Manapsg ha egy tmban
az sszes fellelhet knyvet ki akarom keresni, csak a Dewey-kdot kell tudnom, s
mris brmelyik szak-amerikai knyvtrban megtallhatom a keresett knyveket.
Sajnos ritkn vagyunk abban a helyzetben, hogy egy adatbzis rossz kdolsi s
mjt megvltoztathassuk.

1. fejezet Adatmeghatrozs

1. feladvny - Tblk ltrehozsa


rjunk nhny C R E A T E T A B L E utastst a lehet legteljesebb formban. Azrt fontos
ennek a gyakorlsa, mert az SQL deklaratv programozsi nyelv, vagyis meg kell ta
nulnunk a jellemzket az adatbzis szintjn s nem a programkdban meghatrozni.
A tbla az albbi mdon nzzen ki:
CREATE TABLE KvetesiEvTablal
(kvetesiev SMALLINT,
kezdodatum DATE,
vegdatum DATE);
A tbla a kltsgvetsi vek idtartamt tartalmazza, ami alapjn brmely adott d
tumrl eldnthet, hogy melyik kltsgvetsi vhez tartozik. Pldul az amerikai
szvetsgi kormny a kltsgvetsi vet oktber l-jn kezdi, s az a kvetkez v
szeptembernek vgig tart. Ennek az adatnak a kikeresse a tblbl az albbi kis
allekrdezssel lehetsges:
(SELECT FI.kvetesiev
FROM KvetesiEvTablal A S Fl
WHERE dtum BETWEEN Fl.kezdodatum AND Fl.vegdatum)
A feladatunk most olyan megszortsok megadsa, amelyek szerintnk biztostjk
azt, hogy a tblba csak helyes adatok kerlhessenek. Br a klnbz terjesztsek
dtum- s idfggvnyei eltrnek, tegyk fel, hogy csak az SQL-92 lehetsgei ll
nak rendelkezsnkre, illetve az E X T R A C T ([YEAR I M O N T H I D A Y ] F R O M <dtumkifejezs>) fggvny, ami a dtum adott mezjt jelent egsz tpus rtkkel tr
vissza.

A megolds
1. Kezdjk a lnyeggel: adjuk minden oszlophoz a N O T N U L L felttelt, hiszen nincs
semmi okunk megengedni, hogy brmelyik mez N U L L rtkkel szerepeljen.
2. A legtbb SQL-programoz azonnal az elsdleges kulcs hozzadsra gondol,
gy legjobb, ha ltrehozzuk a PRIMARY KEY (kvetesiev, kezdodatum, vegda
tum) megszortst, hiszen a kltsgvetsi v valban csak egy msik elnevezse
a (kezdodatum, vegdatum) prosnak. Ez azonban mg kevs, hiszen nem vd
meg az ilyen hibktl:

SQL-fejtrk

(1995,
(1996,
(1997,
(1998,

'1994-10-01',
'1995-10-01',
'1996-10-01',
'1997-10-01',

'1995-09-30')
'1996-08-3 0') <==hiba!
'1997-09-3 0')
'1998-09-30')

Folytathatnnk a sort a UNIQUE (kvetesiev), UNIQUE (kezdodatum), s UNIQUE


(vegdatum) felttelekkel, hiszen egyik oszlopban sem szeretnnk azonos rtkeket.
3. Az egyik megszorts olyan nyilvnval, hogy szinte mindenki elfelejti:
CHECK (kezdodatum <= vegdatum)
4. Egy jobb megolds a PRIMARY KEY (kvetesiev) hasznlata, mint az elbb, de
mivel a kezd s vgdtumok minden vben megegyeznek, az oszlopok meghat
rozsnl adjuk meg ezeket a feltteleket:
CREATE TABLE KvetesiEvTablal
(kvetesiev SMALLINT NOT NULL PRIMARY KEY,
kezdodatum DATE NOT NULL,
CONSTRAINT kezdodatum_ellenorzes
CHECK ((EXTRACT (YEAR FROM kezdodatum) = kvetesiev-1)
AND (EXTRACT (MONTH FROM kezdodatum) = 10)
AND CHECK (EXTRACT (DAY FROM kezdodatum) = 01)),
vegdatum DATE NOT NULL
CONSTRAINT vegdatum_ellenorzes
CHECK ((EXTRACT (YEAR FROM vegdatum) = kvetesiev)
AND (EXTRACT (MONTH FROM vegdatum) = 09)
AND CHECK (EXTRACT (DAY FROM vegdatum) = 30)));
rvelhetnnk esetleg amellett, hogy mindegyik felttelt kln megszortsba kl
ntsk el, gy rszletesebb hibazenetet kaphatnnk. A kezd- s vgdtum egyedi
sge is garantlt, hiszen a kltsgvetsi vbl szrmaztattuk, ami biztosan egyedi.
5. Sajnos az itt vzolt eljrs nem minden vllalatnl mkdik, mert sok helyen egy bonyolultabb szablyrendszer alapjn - a hetek, htvgk s munkanapok is
kzrejtszanak a szmtsban. Ennek clja lehet pldul, hogy az zleti v ponto
san 360 napbl vagy 52 htbl lljon. A gyakorlatban elterjedt egyik szably szerint
4-4-5 hetes idszakokbl llnak a negyedvek, amit v vgn igaztanak a naptri
vhez, ekkor egy 3-11 napos ht marad az v vgre. A megolds az zleti hnap
tbljnak bevezetse, vgig ugyanazokkal a sorokkal, mint az elbbi zleti vnl.

1. fejezet Adatmeghatrozs

Ebben az esetben a
CHECK ((vegdatum - kezdodatum) = INTERVAL 359 DAYS)
megszorts meglepen jl mkdik.
Ebben a napok szmt a szablyunkhoz kell igaztanunk (pldul 52 ht * 7 nap =
364 nap). Ha a szablyok megengedik az zleti v hossznak bizonyos mrtk el
trst, az egyenlsg helyett hasznljuk a BETWEEN felttelt.
Egy vallomssal azrt mg tartozom. Amikor egy adatbzisba ilyen tblt kell betltenem, akkor elveszem a SuperCalc programot s annak tblzatkezel fggv
nyeit hasznlva hozom ltre a tblt. A tblzatkezelk ugyanis sokkal jobb idke
zel fggvnyekkel rendelkeznek, mint az adatbziskezelk.

2. feladvny - A munkahelyi tvollt kezelse


Ezt a problmt Jim Chupella vetette fel a CompuServe MS-ACCESS frumn. Egy
olyan adatbzist szndkozott ltrehozni, amellyel nyomon kvethet az alkalma
zottak hinyzsainak mrtke. Ehhez a kvetkez tblt fogjuk hasznlni:
CREATE TABLE Tvolltek
(dolgid INTEGER NOT NULL REFERENCES Dolgozok (dolgid),
osztalyid INTEGER NOT NULL REFERENCES Osztlyok (osztalyid),
tavdatum DATE NOT NULL,
tvok CHAR (40) NOT NULL REFERENCES TavolletOkok (tvok),
hibapont INTEGER NOT NULL CHECK (hibapont BETWEEN 1 AND 4 ) ,
PRIMARY KEY (dolgid, osztalyid, tavdatum));
Az alkalmazottak azonostszma s osztlya egyrtelmen azonost egy dolgozt.
A tvollt okt tartalmaz mez egy rvid szveges magyarzatot tartalmaz (pld
ul elttte egy srs kamion" vagy munkaundor", s gy tovbb), amelyet egy t
letes s folyamatosan nvekv listbl vlasztunk ki s a tvollt oknak slyoss
ga alapjn hibapontokat rendelnk az egyes hinyzsokhoz.
Ha egy alkalmazott egy v alatt elri a negyven hinyzsi hibapontot, automatiku
san felmondunk neki. Egy napnl hosszabb tvollt esetn a tvolltet nem kzn-

SQL-fejtrk

sges hinyzsknt, hanem tarts betegsgknt vesszk szmtsba. Az alkalmazott


a tvollt msodik, harmadik s ksbbi napjaira nem kap hibapontokat, ezek a hi
nyzsok nem addnak hozz az sszes tvollthez.
A feladatunk egy olyan SQL program rsa, ami teljesti ezeket a szablyokat. Szk
sg esetn szba jhet a sma megvltoztatsa is.

1. megolds
Az els, az alkalmazottak elbocstsra vonatkoz szablyra pillantva a leggyak
rabban elkvetett tervezsi hiba az, ha megprbljuk kihagyni a tvolltek mso
dik, harmadik s tovbbi napjait a tblbl. Ez a megkzelts sszezavarja azokat
a lekrdezseket, amelyek a betegsgben eltlttt napokat prbljk kivlogatni,
szinte lehetetlenn tve ezen tbbnapos tvolltek megtallst.
A kiskapu az lehet, hogy megengedjk a nulla rtk hibapontot is, gy nyomon
tudjuk majd kvetni a dolgozk hosszabb betegsgeit is a Tvolltek tblban.
Egyszeren cserljk ki a hibapont megadsnl az ellenrzst CHECK (hibapont
BETWEEN 0 AND 4) -re, gy azoknl a tvollteknl, amelyek nem szmtanak bele az
sszegzsbe, nulla rtket is megadhatunk.
UPDATE Tvolltek
SET hibapont = 0,
tvok = 'hosszabb betegsg'
WHERE EXISTS
(SELECT *
FROM Tvolltek AS A2
WHERE Tvolltek.dolgid = A2.dolgid
AND Tvolltek.tavdatum = (A2.tavdatum - INTERVAL 1 DAY));

Amikor j sort vesznk fel a tblba, ez a frisst lekrdezs megvizsglja, hogy


van-e mr tvollt rgztve az elz napra, s ennek megfelelen lltja be a hiba
pontot s a tvollt okt.
Az alkalmazottak elbocstsi szablynak alkalmazshoz mindig rendelkeznnk
kell a dolgozk aktulis hibapontszmainak adatval. Ezt a kvetkezkppen sz
molhatjuk ssze:

1 . fejezet Adatmeghatrozs

SELECT dolgid, SUM(hibapont)


FROM Tvolltek
GROUP BY dolgid;
Ez az alapja annak a bels lekrdezsnek, amelyet a D E L E T E F R O M utastsban
hasznlhatunk. Azok az alkalmazottak, akik 40 hibapontnl kevesebbel rendelkez
nek, N U L L rtket kapnak, gy a felttel rjuk nem teljesl:
DELETE FROM Dolgozok
WHERE dolgid = (SELECT Al dolgid
FROM Tvolltek AS Al
WHERE Al.dolgid = Dolgozok.dolgid
GROUP BY Al.dolgid
HAVING SUM(hibapont) >= 40);
A GROUP BY zradk nem felttlenl szksges az SQL-92-ben, de nhny rgebbi
SQL-megvalsts ignyli.

2. megolds
Bert Scalzo, az ohioi Powellben mkd Oracle Corporation vezet oktatja hvta
fel a figyelmet arra, hogy az elz megoldsnak van kt szpsghibja s a teljest
mnye is nvelhet.
A hibk egyszerek. Elszr is a bels lekrdezs nem ellenrzi, hogy a 40 feletti
pontszmmal rendelkez dolgozk egy ven bell halmoztk-e fel a pontjaikat,
mint ahogy az eredeti feladat-megfogalmazsban szerepelt. Ez egy tovbbi dtum
tartomny-ellenrzst tesz szksgess a WHERE felttelben:
DELETE FROM Dolgozok
WHERE dolgid = (SELECT Al dolgid
FROM Tvolltek AS Al
WHERE Al.dolgid = Dolgozok.dolgid
AND tavdatum
BETWEEN CURRENT_TIMESTAMP
AND CURRENT_TIMESTAMP
- INTERVAL 3 65 DAYS
GROUP BY Al.dolgid
HAVING SUM(hibapont) >= 40);

SQL-fejtrk

Msodszor, a lekrdezs csak a vtkes alkalmazottakat trli, a hinyzsaikat nem.


A kapcsold tvollteket - akr belertett (implicit), akr kifejtett (explicit) mdon
- szintn trlni kell. A fenti trl lekrdezst a Tvolltek tblra is alkalmazhat
nnk, de taln a legjobb megolds, ha egy lpcszetes (kaszkd) trlsi zradkot
adunk a tvolltek tbljnak bevezetshez.CREATE TABLE Tvolltek
(
dolgid
INTEGER NOT NULL
REFERENCES Dolgozok(dolgid)
ON DELETE CASCADE,

A teljestmnynvelsre vonatkoz javaslatok nhny felttelezsen alapulnak.


Amennyiben biztosak lehetnk abban, hogy az U P D A T E rendszeresen lefut, vala
mint az alkalmazottak tvolltk alatt nem vltanak osztlyt, akkor kijavthatjuk az
U P D A T E lekrdezst:
UPDATE Tvolltek AS Al
SET hibapont = 0,
tvok = 'hosszabb betegsg'
WHERE EXISTS
(SELECT *
FROM Tvolltek AS A2
WHERE Al.dolgid = A2.dolgid
AND Al.osztalyid = A2.osztalyid
AND (Al.tavdatum + INTERVAL 1 DAY) = A2.tavdatum);

Az Oracle-ben a csillag helyettesthet egy llandval, aminek hatsra az adatsz


tr figyelmen kvl hagyja a kivlasztott oszlopokat, a fordt megelgszik azzal,
hogy a lekrdezs csak az indexet s a tnyleges adatot ri el. Msrszt ha hozz
adjuk a lekrdezshez az osztalyid-t is, s a tvollt szmtst az ellenkez ol
dalra tesszk t, a futtatskor sorrendi keress helyett egyedi index szerinti keress
alapjn folyik majd a vizsglat.
A csillag helyett egy lland hasznlata a SELECT utastsban j mdszer, de fgg
az adott SQL-tl is. Nhny optimalizl gy fogja tekinteni, mintha egy E X I S T S ()
lltsrl (prediktumrl) lenne sz, ami azt jelenti, hogy a sajt beltsa szerint
fogja a csillagot egy vagy tbb oszloppal helyettesteni. Ezutn megvizsglja, hogy
a W H E R E felttelben szerepl melyik oszlop rendelkezik indexszel, s a feladat
szempontjbl legmegfelelbbet fogja hasznlni.

1 . fejezet Adatmeghatrozs

Van mg egy gond, mgpedig azokkal a hossz tvolltekkel, amelyek tnylnak


egyik htbl a msikba. A jelenlegi vltozatban az a helyzet, hogy ha a htvgt
betegen tltjk, azrt is bntet a vllalat, ilyen helyen pedig nem tl j dolgozni.
Ha egy alkalmazott az els ht pntektl beteget jelent, otthon marad a msodik
hten s mg a harmadik ht htfjn, akkor az U P D A T E csak a msodik ht t nap
jt fogja hossz tvolltnek tekinteni, a pntek s a htf megmarad hibapontos
napnak. Az U P D A T E bels lekrdezse tovbbi mdostst ignyel az ilyen eltvesz
tett napok sszelncolsra.
A htvgkkel kapcsolatos problmkat elre betemezett szabadnapokkal (ide
rtve a htvgket, szabadsgokat, nnepeket s gy tovbb) oldanm meg, ame
lyek nulla hibaponttal rendelkeznnek. Azok a munkahelyek, ahol htvgi mszak
is van, a pontszm persze eltr lehet.
A munkahelyi vezet esetleg kzzel is bellthatja a szombat s vasrnap htvge"
kdjt hossz tvollt"-re, hogy az U P D A T E a lert mdon mkdjn. Ugyanez
a trkk megvhatja a dolgozt attl is, hogy elvesztse az elre tervezett szabadsg
idejt abban az esetben, amikor a dgvsz pp a tengeri krtja eltt kapja el. Az
igazn jszv fnk az elveszett htvgkrt cserbe bellthat a tblban nulla hi
bapontos napokat, vagy ttemezheti a beosztott nyaralst jvbeli tvolltek be
lltsval.
Azt beltom, hogy megfeledkeztem a tvollti dtumok elavulsrl, de vlem
nyem szerint taln jobb lenne egy msik DELETE FROM utasts, amely a tvolltek
tbljbl az egy vnl rgebbi sorokat eltvoltja, s gy a lehet legkisebbre korl
tozza a tbla mrett.
A (BETWEEN CURRENT_TIMESTAMP AND CURRENT_TIMESTAMP - INTERVAL 3 65
DAYS) kifejezs helyett (BETWEEN CURRENT_TIMESTAMP AND CURRENT_TIMESTAMP
- I N T E R V A L 1 Y E A R ) is llhat, gy a rendszer a szkveket is tudja kezelni. Mg
jobb, ha a DB2-hz s mg nhny SQL-hez hasonlan rendelkeznk az
AGE (dtum) fggvnnyel, amely vekben adja meg annak az esemnynek a kort,
ami a paramterknt szerepl napon trtnt. Ebben az esetben szerepelhet az
(AGE (tavdatum) >= 1) kifejezs is.
Ha a dolgid oszlopot U N I Q U E kittellel vezetjk be, akkor a Dolgozok tblban
rendelkezni fog egy indexszel. A Tvolltek tblban az osztalyid oszlopnak
viszont nem ltom sok rtelmt.

10

SQL-fejtrk

3. feladvny - rzstelents
vekkel ezeltt Leonard C. Medl keresett meg ezzel a szellemes kis feladattal.
A krhzakban zajl mttekkor az aneszteziolgus gondoskodik a beteg rzste
lentsrl. Minden rzstelentsi feladatot egy tblban rgztnk.
Folyamatok
feladatjd
10
20
30
40
50
60
70
80

aneszt
'Nyrfs'
'Nyrfs'
'Hartvig'
'Hartvig'
'Hartvig'
'Hartvig'
'Hartvig'
'Hartvig'

kezds
08:00
09:00
09:00
08:00
10:00
12:30
13:30
18:00

befejezs
11:00
13:00
15:30
13:30
11:30
13:30
14:30
19:00

Lthat, hogy az egyes aneszteziolgusok munkaideje kztt tfeds van. Ez nem


hiba, az rzstelentst vgz orvosok - ellenttben a mtorvosokkal - tjrhat
nak az egyik mtszobbl a msikba a mttek alatt, sorban ellenrizhetik a pci
enseket, bellthatjk a megfelel dzist, s utasthatjk a medikusokat vagy az r
zstelent nvreket, hogy folyamatosan ksrjk figyelemmel a beteget.
Az aneszteziolgusok a mttek szma alapjn kapjk a fizetsket, de van egy to
vbbi szably is. Az egyes mttekrt kapott illetmny kiszmtsakor egy fokozati
sklt is alkalmaznak, amelynek alapja az aneszteziolgus ltal az adott feladattal
egyidben vgzett tbbi mtt legnagyobb szma. Minl magasabb ez a szm, an
nl kevesebb fizets jr az adott mttrt.
Pldul a 10-es szm feladat esetben Dr. Nyrfs a feladat minden pillanatra
megszmllja, hny msik mttben volt ppen akkor rintett. A 10-es feladatnl
a legnagyobb rtk 2, gy az egyidejsgi szably alapjn a 10-es mttrt Dr. Nyr
fs a dj 75%-t kapja.
A cl minden feladat esetben eldnteni az orvos ltal a feladattal egyidejleg vg
zett tbbi mtt szmnak legnagyobb rtkt. Hogy jobban megrtsk a probl
mt, a vlaszt elszr grafikus mdszerrel llaptjuk meg.

1 . fejezet Adatmeghatrozs

Az 1. bra kt egymst tfed altatsi feladatot brzol. A fels, Gantt-diagramhoz


hasonl grafikon a kirtkelend mtt eltelt idejt brzolja, s az orvos minden
olyan feladatt, amely ezt idben tfedi. Az als grafikon (A folyamatban lv
sszes altats) minden pillanatra megmutatja, hogy ppen akkor sszesen hny al
tats volt folyamatban. Gondoljunk r gy, mintha egy szlkereszttel haladnnk v
gig balrl jobbra a Gantt-diagramon, mg az als grafikonon minden feladat kezde
tt, illetve vgt lpcsknt jelljk.
A vizsglatbl jl lthat, hogy a legnagyobb rtk 2.

1. bra

Dr. Nyrfs 10-es

feladata.

A 2. bra a feladatoknak egy kicsit sszetettebb csoportjt mutatja, de az elv ugyan


az. A legnagyobb rtk ebben az esetben - ami ktszer is elfordul - a 3.

11

12

SQL-fejtrk

2. bra

Dr. Hartvig 30-as

feladata.

Jl jegyezzk meg, hogy a helyes vlasz nem az egymst tfed feladatok szma,
hanem ezen feladatok legnagyobb szma.
A krds, hogy mikppen hatrozhatnnk meg ezt az rtket az egyes feladatokra
az SQL segtsgvel. Az albbi tblzat a mintaadatokra meghatrozott eredmnye
ket tartalmazza:

1. fejezet Adatmeghatrozs

feladat
10
20
30
40
50
60
70
80

max_egyideju
2
2
3
3
3
3
2
1

Megolds
Az els lps, hogy minden feladatot kt esemnyre - egy kezdet-esemnyre s
egy vg-esemnyre - bontunk, s az eredmnyt egy nzettblba tesszk. A U N I O N
mvelet (opertor) segtsgvel a kezdet- s vg-esemnyek sszefzhetk, a (+1)
jelenti a kezdet-esemnyt, mg a ( - 1 ) a vg-esemnyt.
A WHERE zradkok biztostjk, hogy az egymssal sszevetett feladatok tfedik
egymst, s mindegyik ugyanahhoz az altatorvoshoz tartozik. A N O T felttel figyel
men kvl hagyja azokat a mtteket, amelyek nincsenek tfedsben a vizsglt aita
tasi feladattal.
CREATE VIEW Esemnyek AS
SELECT Pl.feladat_id AS vizsgalt_feladat,
P2.feladat_id AS hasonltott_feladat,
Pl.aneszt,
P2.kezds AS esemeny_idopont,
+1 AS esemeny_tipus
FROM Feladatok AS Pl, Feladatok AS P2
WHERE Pl.aneszt = P2.aneszt
AND NOT (P2.befejezs <= Pl.kezds
OR P2.kezds >= Pl.befejezs)
UNION
SELECT Pl.feladat_id AS vizsgalt_feladat,
P2.feladat_id AS hasonltott_feladat,
Pl.aneszt,
P2.befejezs AS esemeny_idopont,
-1 AS esemeny_tipus
FROM Feladatok AS Pl, Feladatok AS P2

13

14

SQL-fejtrk

WHERE Pl.aneszt = P2.aneszt


AND NOT (P2.befejezs <= Pl.kezds
OR P2.kezds >= Pl.befejezes);
Az eredmny a fenti utastssor ltal ltrehozott nzettbla, amit az tlthatsg r
dekben albb a 10-es feladatra s esemeny_idopont szerint rendeztnk:
Esemnyek
vizsgaltjeladat
10
10
10
10

hasonltottJeladat
10
20
10
20

aneszt
Nyrfs
Nyrfs
Nyrfs
Nyrfs

esemenyjdopont
08:00
09:00
11:00
13:00

esemnyJipus
+1
+1
-1
-1

Most pedig az Esemnyek nzettbla minden azonos vizsgalt_f eladat rtkkel


rendelkez csoportjnak minden egyes esemnyre kiszmolhatjuk az sszes ko
rbbi esemnyhez tartoz esemeny_tipus-ok sszegeit. Ezen sszegek sorozata
adja meg a lpcss grafikon egyes lpcsi ltal megjelentett rtkeket.
SELECT El.vizsgalt_feladat, El.esemeny_tipus,
(SELECT SUM(E2.esemny_tipus)
FROM Esemnyek AS E2
WHERE E2.vizsgalt_feladat = El.vizsgalt_feladat
AND E2.esemeny_idopont < El.esemeny_idopont)
AS pillanatnyi_ertek
FROM Esemnyek AS El
ORDER BY El.vizsgalt_feladat, El.esemeny_idopont;

A lekrdezs eredmnyt az albbi tblzat mutatja a 10-es feladatra:


vizsgaltjeladat
10
10
10
10

pillanatnyiertek
NULL
1
2
1

Ezt a lekrdezst egy Egyidejsg nev nzettblba tehetjk, majd az albbi pa


ranccsal minden vizsglt feladatra lekrdezhetjk ebbl a pillanatnyi rtkek legna
gyobbikt:

1. fejezet Adatmeghatrozs

SELECT vizsgalt_feladat,
MAX(pillanatnyi_ertek) AS max_pill_ert
FROM Egyidejsg
GROUP BY vizsgalt_feladat
ORDER BY vizsgalt_feladat;

A keresett eredmnyt kzvetlenl az Esemnyek nzettblbl is kinyerhetjk, eh


hez a kt SELECT utastst kell egybeolvasztanunk:
SELECT El.vizsgalt_feladat,
MAX((SELECT SUM(E2.esemny_tipus)
FROM Esemnyek AS E2
WHERE E2.vizsgalt_feladat = El.vizsgalt_feladat
AND E2.esemeny_idopont < El.esemeny_idopont))
AS max_egyidejuek_szama
FROM Esemnyek AS El
GROUP BY vizsgalt_feladat
ORDER BY vizsgalt_feladat;

4. feladvny - Biztonsgi azonostk


A vllalatunknl lezajlott hatkonysgnvel intzkedsek kvetkeztben egy sze
mlyben kell elltnunk a biztonsgi vezeti s az adatbzis-felgyeleti feladatokat.
Kszteni szeretnnk egy listt a jelenlegi alkalmazottakrl s azonostszmaikrl.
Egy-egy beosztott tbb azonostval is rendelkezhet, attl fggen, hogy ppen
hol vgzi a munkjt, de adott idben midig csak egy lehet ezek kzl aktv. Alap
rtelmezs szerint ez a legutbb kibocstott azonost. Az azonostszmok a ha
mists elkerlse cljbl vletlenszeren llnak el. A feladat, hogy kirassuk az
sszes alkalmazottat a hozzjuk tartoz aktv azonostszmokkal. Hasznljuk az
' A ' jelet az aktv, s az ' I' -t az inaktv llapot jellsre.

Megolds
A feladatlersbl tudjuk, hogy az alkalmazottak azonosti egy kivtellel inaktv l
lapotban vannak. Ennek a felttelnek clszer az adatbzis szintjn rvnyt szerezni.
CREATE TABLE Alkalmazottak
(alk_azon INTEGER PRIMARY KEY,
alk_nev CHAR(30) NOT NULL ,
.. . ) ;

15

16

SQL-fejtrk

CREATE TABLE Azonostok


(azon_azon INTEGER NOT NULL
alk_azon INTEGER NOT NULL REFERENCES alkalmazottak (alk_azon),
kiad_datum DATE NOT NULL,
llapot CHAR(l) NOT NULL CHECK (llapot IN ('A', 'I')),
CHECK (1 = ALL (SELECT COUNT(allapot)
FROM Azonostok
WHERE llapot = 'A'
GROUP BY alk_azon))
) ;

A sportszersg kedvrt meg kell jegyeznem, hogy sok SQL-nyelvjrs torkn meg
akad az Azonostok tbla utols C H E C K () zradka az utastsban lv krkrs
hivatkozs miatt, de az SQL-92 szerint szablyos ez az alkalmazsi md. Mellzhet
nnk is ezt az ellenrzst s megengedhetnnk a dolgozknak, hogy ne rendelkez
zenek aktv azonostval. Ezt azt is jelenti, hogy szksgnk lenne egy mdszerre az
alkalmazottak legutoljra kibocstott azonostjnak ' A ' -ra lltshoz.
UPDATE Azonostok
SET llapot = 'A'
WHERE ('I' = ALL (SELECT STATUS
FROM Alkalmazottak AS Bl
WHERE alk_azon = Bl.alk_azon))
AND (kiad_datum = (SELECT MAX (kiad_datum)
FROM Alkalmazottak AS B2
WHERE alk_azon = B2.alk_azon));

Itt ismt figyelmeztetnem kell mindenkit arra, hogy sok SQL-megvalsts fennakad
ezen az UPDATE utastson is a tblanevek azonossga miatt. Az SQL-92 szablya
szerint az UPDATE utastsban lv tblanv hatkre az egsz utastsra kiterjed,
mg az aktulis sor a hivatkozott oszloprtkekre vonatkozik, ezrt a tbla maradk
rsznek megtekintshez a kapcsolt (korrellt) nevekre van szksg. Ezzel az ere
deti lekrdezs igazn knnyv vlik:
SELECT Alkalmazottak.alk_azon, alk_nev, azon_azon
FROM Alkalmazottak, Azonostok
WHERE azon_azon = alkalmazott
AND llapot = 'A';

1. fejezet Adatmeghatrozs

5. feladvny - Az adatok formzsa


Hogyan szerezhetnnk rvnyt annak a felttelnek, hogy az egyik oszlop csak
egyetlen bett tartalmazhat? (Vagyis a karakterlncban nem lehetnek szkzk,
szmok, vagy klnleges karakterek.)
A legtbb rgebbi eljrskzpont nyelvben a formtumra vonatkoz megszortsok
kal rendelkez adatmezket a fjldeklarcikban kellett meghatrozni. Erre a Cobol
s a PL/I a kzenfekv plda. Egy msik megolds, hogy az adatbeolvassnl hasz
nlunk valamilyen szrmintt; a Fortran-szer F O R M T utasts j plda erre.
Az SQL nagy slyt helyez arra, hogy az adatok logikai nzett hatrozottan elv
lassza a fizikai brzolstl, ezrt az adatok fizikai szerkezetnek megadsval nem
jutunk kzelebb a megoldshoz. Amikor egy programoz ezzel a problmval ke
resett fel az irodmban, az els, rsz-karakterlncokkal s B E T W E E N lltsokkal te
letzdelt C H E C K () zradkkal val prblkozsaim igazn rosszul sikerltek;
hosszabb lett a vizsglat, mint az egsz sma-bevezets.

Megolds
Ha alkalmam van, mindig felhvom a figyelmet arra, hogy amikor SQL-ben progra
mozunk, teljes szerkezetben kell gondolkodnunk s nem szabad leragadni a me
zk egyenknti feldolgozsnl. Most a megolds kulcsa a teljes karakterlncban s
nem csak egyetlen karakterben val gondolkods. me a feladatra adott vlasz:
CREATE T A B L E Akrmi

csak_betu VARCHAR (6)


CHECK((UPPERCASE(TRIM(csak_betu)) II 'AAAAA')
BETWEEN 'AAAAAA' and 'ZZZZZZ'),
) ;

Elszr is a karakterlnc mindkt vgrl eltvoltjuk a felesleges szkzket, de


a bell lvket benne hagyjuk. A TRIM () az SQL-92 szabvnyos fggvnye a para
mterknt megadott karakterlnc jobb vagy bal feln lv tbbletkaraktereinek el
tvoltsra. Ltni fogjuk, hogy a legtbb SQL-megvalsts rendelkezik ennek egy
vltozatval, amely megfelel a feladvnyhoz.

SQL-fejtrk

A kvetkez lpsben az ' A A A A A ' karakterlncot hozzfzzk (ez egy betvel r


videbb, mint az oszlopmezk szlessge), gy ha az eredeti karakterlnc res, ak
kor ez az j karakterlnc nem teljesti a B E T W E E N felttelt. Ha az res karakterlncot
is meg akarjuk engedni, az ' A ' karakterek lnct az oszlopmez hosszval azonos
hosszsgra kell vlasztani. A harmadik lps a karakterlnc nagybetss alakt
sa, s annak vizsglata, hogy az eredmny benne van-e a betk tartomnyban.
Ez a trkk tovbb ltalnosthat. Pldul ha egy olyan oszlopmezt szeretnnk
meghatrozni, ami hrom betbl s az ezeket kvet hrom szmjegybl ll, ak
kor el kell tvoltanunk az els hrom karaktert s alkalmazhatjuk ugyanezt
a CHECK () zradkot.

6. feladvny - Szllodai szobafoglals


Scott Gammans vetette fel a kvetkez problma egy vltozatt a CompuServe
WATCOM-frumn. Tegyk fel, hogy portsknt dolgozunk az SQL Hotelben, s az
albbi tblval rendelkeznk:
C R E A T E T A B L E Hotel

(szobaszm SMALLINT NOT NULL,


rkezs DATE NOT NULL,
tvozs DATE NOT NULL,
vendg CHAR(30),
P R I M A R Y KEY (szobaszm, rkezs),

CHECK (tvozs >= rkezs));


A CHECK () zradk azonnal ellenrzi az adatok psgnek azt a felttelt, hogy
nem tvozhatunk elbb, mint megrkeztnk volna, de ennl tfogbb ellenrzst
szeretnnk. Hogyan juttathatnnk rvnyre azt a szablyt, hogy ne tudjunk felvenni
egy adott szobra olyan foglalst, amelynek rkezsi dtuma tkzik egy korbbi
foglals tvozsi dtumval?

Megolds
Az egyik megolds olyan SQL-termket ignyel, ami meglehetsen sszetett SQLkifejezst is lehetv tesz a C H E C K () zradkban, ezrt elfordulhat, hogy a meg
valstsok nagy rsze nem fogja tmogatni ezt a mdszert.

1. fejezet Adatmeghatrozs

CREATE

T A B L E Hotel

(szobaszm S M A L L I N T NOT NULL


rkezs D A T E NOT NULL,
tvozs D A T E NOT NULL,
vendg CHAR(30),
P R I M A R Y KEY (szobaszm, rkezs),
CHECK (tvozs >= rkezs))
CHECK (NOT E X I S T S

(SELECT *
FROM Hotel As Hl, Hotel AS H2
WHERE Hl.szobaszm = H2.szobaszm
AND Hl.rkezs
B E T W E E N H2.rkezs AND H2.tvozs))
) ;

A msik megolds a tbla szerkezetnek olyan talaktsval jr, amely minden


szoba minden egyes napjhoz egy sort tartalmaz, az albbi mdon:
C R E A T E T A B L E Hotel

(szobaszm S M A L L I N T NOT NULL,


foglalas_datuma D A T E NOT NULL,
vendg CHAR(30) NOT NULL,
P R I M A R Y KEY (szobaszm, foglalas_datuma));
Ez a mdszer nem ignyli a CHECK () zradkok hasznlatt, viszont sok lemezhe
lyet foglal. Ezt a megoldst vlasztva arra is mdot kell tallnunk az I N S E R T I N T O
utastsokban, hogy hzag nlkl ki tudjuk tlteni a szobk napjait.
Mellesleg a Full SQL-92 szinten ltezik egy O V E R L A P S llts is, annak eldntsre,
hogy kt idtartam tfedi-e egymst, ez a jelenleg az SQL-megvalstsokban meg
lv B E T W E E N llts idre vonatkoz vltozata. Pillanatnyilag nincs olyan SQLtermk, amelyben ezt megvalstottk volna.

7. feladvny - Iratok
Az albbi problmt Steve Tilson kldte el nekem 1995 novemberben:
Van egy feladvnyom a szmodra. Elfordulhat, hogy nem ltom a ftl az erdt,
de szmomra gy tnik, ennek a krdsnek az elegns, krkrs hivatkozsok nl
kli megoldsa igazi kihvs.

20

SQL-fejtrk

Br a felvetett problma teljes rendszernek tnik, n most csak arra lennk kvn
csi, hogy kikszblhetk-e a ltszlagos krkrs hivatkozsok mr a tblaterve
zs szakaszban.
Tegyk fel, hogy egy szervezet iratait kell ksbbi elkeress, jraolvass cljbl
nyilvntartani. Sok klnbz tulajdonsgt troljuk az iratoknak, de a krds
szempontjbl csak nhnynak van jelentsge:
C R E A T E TABLE Iratok

(akta_id INTEGER NOT NULL PRIMARY KEY,


kibocsatas_datuma DATE NOT NULL,
hatalytalanitott_irat INTEGER NOT NULL REFERENCES Iratok.akta_id,
hatalytalanito_irat INTEGER NOT NULL REFERENCES Iratok.akta_id)
A feladatok:

Nyilvn kell tartani, hogy az adott iratot melyik irat hatlytalantotta.


Nyilvn kell tartani, hogy az adott irat melyik iratot hatlytalantotta.
Lehetsget kell nyjtani egy irat jbli hatlyba lptetsre (amelynek
a kvetkezmnye egy irat hatlytalantsa vagy egy olyan iratlnc ltrejt
te, ami krkrs hivatkozst tartalmaz).
A dtumok nyomon kvethetk a kibocsatas_datuma alapjn, de
az jra hatlyba helyezett iratoknl az jabb dtum bonyodalmakat okoz.
Kpesnek kell lenni a legfrissebb irat kivlasztsra, tekintet nlkl
a S E L E C T utastsban szerepl iratra.
Lehetsget kell adni ellenrz lista ltrehozsra a dokumentum
lncokrl."

Megolds
Steve mg mindig eljrsokban s mutatlncokban gondolkodik. Szgyellheti ma
gt! Mi mr tudjuk, hogy a krds a sorszmokkal kapcsolatos, hiszen a feladatle
rsban elbjtatva ott az rulkod kt sz: eld s utd. Alkalmazzuk, amit az egy
msba gyazott halmazokrl (nested sets) tanultunk.

1 . fejezet Adatmeghatrozs

Elszr is hozzunk ltre egy tblt, amiben troljuk egy akta minden adatt:
CREATE TABLE Iratok
(akta_id INTEGER NOT NULL PRIMARY KEY,
egyeb_anyag . . . . ) ;

Ezutn hozzunk ltre egy tblt a dokumentumok sorrendjnek trolsra, kt k


lnleges oszloppal (lanc s kvetkez):
CREATE TABLE Sorrend
(lanc INTEGER NOT NULL,
kvetkez INTEGER NOT NULL CHECK (kvetkez >= 0) DEFAULT 0,
akta_id INTEGER NOT NULL REFERENCES Iratok(akta_id),
sor_datum NOT NULL,
PRIMARY KEY(lanc, kvetkez));
Kpzeljk el, hogy az eredeti dokumentum egy vonal nullpontja. A kvetkez irat,
ami ezt hatlytalantja, egy e pont kr rajzolt kr. A harmadik dokumentum a sor
rendi lncban egy msodik kr, amelyet az els kr rajzolunk, s gy tovbb. Eze
ket az egymsba gyazott csoportokat a kvetkez rtkkel jelljk, a krket egy
nulltl kezdd szmsorr kpezve le.
Ltre kell hoznunk egy j sort az Iratok tblban a dokumentum szmra, majd
a Sorrend tblban is egy megfelel bejegyzst. A kvetkez rtke a Sorrend
tblban eggyel nagyobb, mint a lncban elfordul legnagyobb kvetkez rt
ke. Egymsba gyazott halmazokrl van sz!
me nhny pldaadat, ahol a '22?' s '32?' dokumentumokat a 999 dokumen
tum hatlytalantja:
CREATE TABLE Iratok
(akta_id INTEGER NOT NULL PRIMARY KEY,
anyag CHAR(15) NOT NULL);
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT

INTO
INTO
INTO
INTO
INTO
INTO
INTO

Iratok
Iratok
Iratok
Iratok
Iratok
Iratok
Iratok

VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES

(222,
(223,
(224,
(225,
(322,
(323,
(324,

'anyag');
'rgi anyag');
'j anyag');
'klcsnkrt anyag')
'kk anyag');
' lila anyag');
'piros anyag');

21

22

SQL-fejtrk

INSERT INTO Iratok VALUES (325, 'zld anyag');


INSERT INTO Iratok VALUES (999, 'srga anyag');
CREATE TABLE Sorrend
(lanc INTEGER NOT NULL,
kvetkez INTEGER NOT NULL,
akta_id INTEGER NOT NULL REFERENCES Iratok(akta_id),
sor_datum NOT NULL,
PRIMARY KEY(lanc , kvetkez));
INSERT
INSERT
INSERT
INSERT

INTO
INTO
INTO
INTO

Sorrend
Sorrend
Sorrend
Sorrend

VALUES
VALUES
VALUES
VALUES

(1,
(1,
(1,
(1,

0,
1,
2,
3,

222,
223,
224,
225,

' 1995-11 -01'


'1995- 11 -02 '
' 1995-11 -04 '
'1995- 11 -05 '

INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT

INTO
INTO
INTO
INTO
INTO
INTO
INTO

Sorrend
Sorrend
Sorrend
Sorrend
Sorrend
Sorrend
Sorrend

VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES

(2,
(2,
(2,
(2,
(2,
(2,
(2,

0,
1,
2,
3,
4,
3,
5,

322,
323,
324,
322,
323,
999,
999,

'1995- 11 -01'
'1995- 11 -02 '
'1995- 11 -04 '
' 1995-11 -05 '
' 1995-11 -12 '
' 1995-11 -25 '
' 1995-11 -25 '

A feladat szerint a kvetkezkre van szksg:

Kpesnek kell lenni a legfrissebb irat kivlasztsra, tekintet nlkl


a SELECT utastsban szerepl iratra.
SELECT DISTINCT Pl.akta_id, anyag, sor_datum
FROM Iratok AS Pl, Sorrend AS Sl
WHERE Pl.akta_id = Sl.akta_id
AND kvetkez = (SELECT MAX(kvetkez)
FROM Sorrend AS S2
WHERE Sl.lanc = S2.1anc);

A S E L E C T D I S T I N C T lehetsg arra az esetre szolgl, ha egyetlen irat kett vagy


tbb lncot hatlytalantott.

Lehetsget kell adni ellenrz lista ltrehozsra a dokumentumlncokrl.


SELECT
FROM
WHERE
ORDER

lanc, kvetkez, Pl.akta_id, anyag, sor_datum


Iratok AS Pl, Sorrend AS Sl
Sl.akta_id = Pl.akta_id
BY lanc, kvetkez;

23

1 . fejezet Adatmeghatrozs

Nyilvn kell tartani, hogy az adott iratot melyik irat hatlytalantotta.


SELECT Sl.akta_id, ' hatlytalantotta ',
S2.akta_id. ' ', S2.sor_datum, napon'
FROM Sorrend AS Sl, Sorrend AS S2
WHERE Sl.lanc = S2.1anc
AND Sl.kvetkez = S2.kvetkez + 1
AND Sl.akta_id = :keresett_akta_id;
-- eltvolts minden iratnl
1

Lehetsget kell nyjtani egy irat jbli hatlyba lptetsre, amelynek


a kvetkezmnye egy irat hatlytalantsa vagy egy olyan iratlnc ltrejt
te, ami krkrs hivatkozst tartalmaz.
BEGIN
-- Sor ltrehozsa az j irat szmra
INSERT INTO Iratok VALUES (1000, 'nehzkes anyag');
-- j akta_id ltrehozsa a benne brhol lv
-- :regi_akta_id hozzlncolshoz
INSERT INTO Sorrend (lanc, kvetkez, akta_id, sor_datum)
VALUES ((SELECT DISTINCT lanc
FROM Sorrend AS Sl
WHERE Sl.akta_id = :regi_akta_id),
(SELECT MAX(kvetkez) + 1
FROM Sorrend AS Sl
WHERE Sl.lanc - (SELECT DISTINCT lanc
FROM Sorrend AS S2
WHERE akta_id =
:keresett_akta_id)) ,
:uj_akta_id, :uj_sor_datum);
END;

A gond itt az, hogy megengedtem, hogy egyetlen akta tbb aktt is hatlytalant
son, vagy hogy tbb akta hatlytalanthasson egyetlen iratot. A lncaim nem eg
szen linerisak; a kd elszll, ha a : regi_akta_id tbb lncban is szerepel. A hi
ba kijavthat a lncok szmnak vagy az j akta ltal hatlytalantott irathoz
tartoz akta_id lekrdezsvel, de az SQL-kd elg csnya. Meg lehet prblni
a finomtst!

A dtumok nyomon kvethetk a kibocsatas_datuma alapjn, de az j


ra hatlyba helyezett iratoknl az jabb dtum bonyodalmakat okoz.

24

SQL-fejtrk

A smnk alapjn a megolds nem nehz. Futtassunk egy S E L E C T utastst brme


lyik krdses akta_id szerint s a dtumok s a kvetkez oszlop alapjn meg
kapjuk az esemnylncot. A feladatban nem volt kiktve, hogy a sorrendet tartal
maz tbla dtummezinek is nvekv sorrendben kell lennik a kvetkez
oszlop rtkei mellett. Ha gy van, akkor ezt egy tovbbi C H E C K () zradkkal kell
kezelnnk.

8. feladvny - Nyomtatk idbeosztsa


Yogesh Chacha tkztt egy problmba, amit 1996. szeptember 12-n a CompuServe-n keresztl elkldtt nekem. A felhasznlk az irodjban gyakran rossz
nyomtatt hasznltak az anyagaik kinyomtatsra, gy elhatrozta, hogy egy j tb
lt hoz ltre, amely minden felhasznl nyomtatand anyagt futsidben a j
nyomtatra irnytja. A tbla gy festett:
C R E A T E T A B L E NyomtatoVezerlo

(felhasznalo_id C H A R ( 2 0 ) ,
nyomtato_nev C H A R ( 2 0 ) N O T N U L L ,
leiras C H A R ( 4 0 ) N O T N U L L ) ;

A mkdsi szablyok az albbiak:


1. Amennyiben ltezik a tblban a felhasznlhoz tartoz bejegyzs,
a megfelel nyomtato_nev rendeldik hozz.
2. Ha a felhasznl nem szerepel a tblban, az egyik olyan kzs nyomta
tt kell hasznlnia, amelyikhez N U L L rtk f elhasznalo_id tartozik.
Most gondoljuk vgig az albbi pldt:
NyomtatoVezerlo
'chacha'
lac
'tomi'
NULL
NULL
1

nyomtatonev
'LPT1'
'LPT2'
'LPT3'
'LPT4'
'LPT5'

'Els emeleti nyomtat


'Msodik emeleti nyomtat'
'Harmadik emeleti nyomtat'
'j felhasznl nyomtatja'
'j felhasznl nyomtatja
1

25

1 . fejezet Adatmeghatrozs

Amikor 'chacha' nyomtatja a jelentst, csak az LPT1 nyomtat hasznlatra jogosult,


mg egy 'celko' nev felhasznl az LPT4 vagy LPT5 nyomtatt hasznlhatn. Az el
s esetben egy egyszer lekrdezs megtallja a megfelel sort, s minden jl m
kdik, de a msodik esetben kt sort kapunk vissza s gy nem tudjuk hasznlni az
eredmnyt.
Ltezik egyetlen lekrdezsbl ll megolds?

Megolds
Azt kell vlaszolnom, hogy a hiba az adatokban van. Nzznk a f elhasznalo_id
oszlopot. Mr a neve is mutatja, hogy mezinek egyedinek kell lennik, a N U L L r
tk mgis tbbszr elfordul. A valsgban egy msik gond is jelentkezik: a nyom
tatk terhelst nyilvn gy szeretnnk megosztani az LPT4 s LPT5 nyomtatk k
ztt, hogy egyik se legyen tlterhelve.
Ne talljunk ki semmilyen szellemes lekrdezst - vltoztassuk meg a tblt:
CREATE TABLE NyomtatoVezerlo
(felhasznalo_tol CHAR(8) NOT NULL,
felhasznalo_ig CHAR(8) NOT NULL,
nyomtato_nev CHAR(4) NOT NULL,
leiras CHAR(40) NOT NULL,
PRIMARY KEY (felhasznalo_tol, felhasznalo_ig));
Most pedig vizsgljuk meg az albbi pldt:
NyomtatoVezerlo
felhasznatotoi
'chacha'
'lac'
'tomi'
'aaaaaaaa'
'naaaaaaa'

fethasznaiojg
'chacha'
'lac'
'tomi'
'mzzzzzzz'
'zzzzzzzz'

nyomtatojiev
'LPT1'
'LPT2*
'LPT3'
'LPT4'
'LPT5'

leiras
'Els emeleti nyomtat'
'Msodik emeleti nyomtat'
'Harmadik emeleti nyomtat
'j felhasznl nyomtatja'
'j felhasznl nyomtatja'

26

SQL-fejtrk

gy a lekrdezs a kvetkez alakot lti:


SELECT MIN(nyomtato_nev)
FROM NyomtatoVezerlo
WHERE :vizsgalt_id BETWEEN felhasznalo_tol AND felhasznalo_ig;

A trkk a kezd- s befejez rtkben rejtzik, amelyek az 'aaa...' s 'zzz...' kz


es lehetsges karakterlncokat kvnsgunk szerint osztjk fel. gy a 'celko' fel
hasznl-azonostval rendelkez szemly csak az LPT4 nyomtatt hasznlhatja,
mert a nv az ennek megfelel tartomnyba esik. Egy 'normn' nev felhasznl
egyrtelmen az LPT5 nyomtatt kapn. Ha tudjuk, milyen felhasznli nevekre
szmthatunk, a tartomnyok gondos megvlasztsval egyenl mrtkben oszthat
juk el a munkt a nyomtatk kzt.
ltem azzal a felttelezssel, hogy a kzs nyomtatk mindig magasabb LPTszmmal rendelkeznek. A 'chacha' felhasznli azonostnak kt nyomtat, az
LPT1 s LPT4 is megfelel a tblban, a lekrdezs ebbl vlasztja ki a legkisebbet,
vagyis az LPTl-et. Egy megfontolt optimalizlnak alkalmaznia kell a P R I M A R Y K E Y
indexet is a lekrdezs gyorstsra.

9. feladvny - Szabad helyek


Tegyk fel, hogy egy 1000 frhelyes ttermet vezetnk. Amikor a pincr leltet
egy vendget, ezt feljegyzi a frhelyek tbljba. Hasonlan, ha egy vendg befe
jezte az tkezst, a tblbl eltvoltjuk a helynek a szmt. Egy lekrdezst sze
retnnk rni, ami listt kszt az tterem szabad frhelyeirl. A feladat buktatja,
hogy az adatbzisnak egy tenyrgpen kell futnia, nem nagyszmtgpen, ezrt
a lehet legkisebb trterlet felhasznlsval kell mindezt megvalstani. Felttelez
zk, hogy az lhelyek sorszmai egsz szmok.
Az els tlet, hogy hozzunk ltre egy (szabad/foglalt)" jelzmezt az lhely-sor
szm oszlop mellett. A szabad helyek lekrdezse erre az llapotjelz mezre pl
ne. Ez 1000 sort jelentene az egsz tteremre nzve, ahol minden rekord egy egsz
szmbl s egy jelzkarakterbl llna. Minden bizonnyal jl mkdne a program,
de a feladatban az is szerepel, hogy a legkisebb helyfoglalsra kell trekednnk.
Javtsunk ezen mg egy picit!

1 . fejezet Adatmeghatrozs

1. megolds
Az llapotjelzt kpviselheti egy pozitv vagy negatv eljel az lhely azonost
szmnak mezjben, ezzel megtakartunk egy oszlopot, de ez nagyon rossz elj
rs az adatbzis logikjnak szempontjbl, hiszen kt tulajdonsg olvad ssze
egyetlen mezv. Radsul az 1000 sor is megmarad a tblban.

2. megolds
A msodik gondolat az, hogy hozzunk ltre egy tovbbi, egyetlen oszlopot tartal
maz tblt a foglalt helyek nyilvntartsra s mozgassuk a szmokat a foglalt s
a szabad helyek tbli kztt. Ez a megolds a kt tblban sszesen ignyelne
1000 rekordot.

3. megolds
Inkbb hasznljunk egyetlen tblt s rendeljk a szmokat 0-tl 1001-ig az lhe
lyekhez (a 0 s az 1001 igazbl nem ltezik, s ezeket sohasem adjuk ki a vend
geknek). Trljk a helyet a tblbl, ha elfoglaljk, s rjuk vissza, ha megint sza
badd vlik. Amikor az sszes hely foglalt, az tterem tbla lehet olyan kicsi,
amekkora helyet a kt nem valdi sor elfoglal, de a rekordok szma semmikppen
sem lehet tbb 1002-nl (ez a teljesen res tterem esete).
Az albbi nzettbla megkeresi az els helyet a szabad helyek egyik rsben:
CREATE VIEW Elso_hely (hely)
AS SELECT (hely + 1)
FROM tterem
WHERE (hely + 1) NOT IN
(SELECT hely FROM tterem)
AND (hely + 1) < 1001;
Hasonlan, az albbi nzettbla megkeresi az utols helyet a szabad helyek egyik
rsben:
CREATE VIEW Utolso_hely (hely)
AS SELECT (hely - 1)
FROM tterem

27

28

SQL-fejtrk

WHERE (hely - 1) NOT IN


(SELECT hely FROM tterem)
AND (hely - 1) > 0 ;
Most e kt nzettbla segtsgvel kirathatjuk a szabad frhelyek szakaszait:
SELECT FI.hely AS kezdete, Ll.hely AS vege,
((Ll.hely - FI.hely) + 1) AS res
FROM Elso_hely AS FI, Utolso_hely AS Ll
WHERE Ll.hely = (SELECT MIN(L2.hely)
FROM Utolso_hely AS L2
WHERE Fl.hely <= L2.hely);
Ez a lekrdezs azt is megmutatja, hogy az egyes szabad szakaszokban hny l
hely van, ami igen hasznos, ha a pincr egy csoport szmra keres megfelel he
lyet. Az Olvas szmra hagyom meg azt a feladatot, hogy nzettblk nlkl,
egyetlen lekrdezssel oldja meg mindezt.

10. feladvny - A munka jutalma


Luk Tymowski kanadai programoz egy rdekes problmt kldtt 1994 novem
berben a CompuServe MS-ACCESS frumra. Akkoriban ppen egy nyugdjalap
pal kapcsolatos krdsen dolgozott. Az SQL-92 szerint a krdses tbla szerkezete
az albbi lenne:
CREATE TABLE Nyugdijak
(tb_azon CHAR(9) NOT NULL,
nyug_ev INTEGER NOT NULL,
Szolg_ho INTEGER NOT NULL DEFAULT 0
CHECK (szolg_ho BETWEEN 0 AND 12),
jvedelem DECIMAL (8,2) NOT NULL DEFAULT 0.00);
A tb_azon mez a trsadalombiztostsi azonost (TB-szm), a nyug_ev a nyug
djhoz tartoz naptri v, a szolg_ho az adott vben munkaviszonyban tlttt h
napok szma, a jvedelem mez pedig az abban az vben megszerzett sszes j
vedelem.
A feladat az, hogy sszeszmoljuk az egyes munkavllalk legutbbi 60, egymst
kvet vekben munkaviszonyban tlttt hnapjnak sszjvedelmt. A munka
vllalk nyugdjszmtsnak ez az rtk kpezi az alapjt. A legrvidebb idtartam

1. fejezet Adatmeghatrozs

ezek szerint 5 v lehet, minden vben 12 ledolgozott hnappal. A leghosszabb id


szak 60 v lehetne, minden vben 1 munkban tlttt hnappal. Elfordulhat,
hogy valaki ngy vig dolgozott, de az tdikben mr nem, gy egyltaln nem jo
gosult nyugdjra.
A feladat nehzsgt az okozza, hogy a legutbbi" s egymst kvet" felttelek
rvnyestse nem tl egyszer az SQL-ben.
Jtancs: Minden munkavllal
minden vhez hozzunk ltre rekordot a tbl
ban, mg abban az esetben is, ha a munkavllal
az adott vben nem dolgozott.
Nem csak a lekrdezs lesz ezzel egyszerbb, de gy amikor j adatot kapunk, mr
rendelkezni fogunk a megfelel
rekorddal.

1. megolds
Az albbi lekrdezs megadja annak az sszefgg idszaknak a kezd s befejez
vt, amikor (1) a munkavllal dolgozott (a szolglatban tlttt hnapok szma 0nl nagyobb) s (2) a munkaviszonyban tlttt hnapok szmnak sszege 60
vagy annl tbb.
CREATE VIEW Nyugldoszakok (tb_azon, kezdo_ev, utolso_ev,
ossz_jovedelem)
AS SELECT P0.tb_azon, P0.nyug_ev, Pl.nyug_ev,
(SELECT SUM (jvedelem) -- az idszak sszjvedelme
FROM Nyugdijak AS P2
WHERE P2.tb_azon = P0.tb_azon
AND P2.nyug_ev BETWEEN P0.nyug_ev AND Pl.nyug_ev)
FROM Nyugdijak AS PO, Nyugdijak AS Pl
WHERE Pl.tb_azon = P0.tb_azon - n-sszekapcsols az idszak
ltrehozshoz
AND Pl.nyug_ev >= (P0.nyug_ev - 4) -- mirt korbban?
AND 0 < ALL (SELECT szolg_ho -- folyamatos munkaviszony
FROM Nyugdijak AS P3
WHERE P3.tb_azon = P0.tb_azon
AND P3.nyug_ev
BETWEEN P0.nyug_ev AND Pl.nyug_ev)
AND 60 <= (SELECT SUM (szolg_ho) -- az sszeg tbb 60-nl
FROM Nyugdijak AS P4
WHERE P4.tb_azon = P0.tb_azon
AND P4.nyug_ev
BETWEEN P0.nyug_ev AND Pl.nyug_ev);

29

30

SQL-fejtrk

A S E L E C T listjban lv bels lekrdezs az SQL-92 ltal megengedett trkk, de


szmos megvalsts kpes rtelmezni.
A megolds htultje, hogy ez a lekrdezs az sszes 60 vagy annl tbb hnap
bl ll idszakot meg fogja adni, neknk pedig csak a legksbbi utolso_ev l
tal meghatrozott idszakra van szksgnk. Ezt egy nzettblban egy
MAX (utolso_ev) fggvnnyel lehet kivlasztani:
SELECT *
FROM NygIdszakok AS PO
WHERE utolso_ev = (SELECT MAX(utolso_ev)
FROM Nyugldoszakok AS Pl
WHERE Pl.tb_azon = PO.tb_azon):
Ugyanez megoldhat lenne csnya H A V I N G zradkokkal is az SQL-92-ben, s a ket
tt egyesthetnm a bels lekrdezsben egy E X I S T S () zradkkal, s gy tovbb.
Ezzel az a baj, hogy ezek a megoldsok pillanatnyilag mg kevss hordozhatk.
Tovbbi feladatknt meg lehet prblni az utols bels lekrdezshez hozzadni
egy felttelt, amely szerint nincs a PO. nyug_ev s Pl .nyug_ev kztt olyan v,
amely nagyobb a P4 . nyug_ev rtknl s ugyanakkor 60 vagy tbb hnapos fo
lyamatos munkaviszonnyal br.

2. megolds
A legtbb tovbbfejlesztett megolds, amelyet a CompuServe-n keresztl kaptam,
az n eredeti megoldsomra plt. Viszont Richrd Romley megoldsa, ami a leg
jobbnak bizonyult, teljesen ms oldalrl kzelti meg a krdst. me az lekrdezse:
SELECT Kezd.tb_azon,
Kezd.nyug_ev AS kezdo_ev,
Bef.nyug_ev AS zaro_ev,
SUM (Kozep.jovedelem)
FROM Nyugdijak AS Kezd, Nyugdijak AS Kozep, Nyugdijak AS Bef
WHERE Kezd.szolg_ho > 0
AND Kozep.szolg_ho > 0
AND Bef.szolg_ho > 0
AND Kezd.tb_azon = Kozep.tb_azon
AND Kezd.tb_azon = Bef.tb_azon
AND Kezd.nyug_ev BETWEEN Bef.nyug_ev-59 AND (Bef.nyug_ev - 4)

1 . fejezet Adatmeghatrozs

AND Kozep.nyug_ev BETWEEN Kezd.nyug_ev AND Bef.nyug_ev


GROUP BY Kezd.tb_azon, Kezd.nyug_ev, Bef.nyug_ev
HAVING SUM (Kozep.szolg_ho) >= 60
AND (Bef.nyug_ev - Kezd.nyug_ev) = (COUNT (*) - 1 ) ;
Romley mg hozzfzte: Egyszerbb lett volna a megolds, ha nem engedjk,
hogy a szolglati idvel nem rendelkez vek (szolg_ho=0) is szerepeljenek a tb
lban. Hrom WHERE felttelt kellett csak ezek kiszrsre elvesztegetnem."
Ez egy jabb plda arra, hogy a j adattervezs megknnythette volna a dolgunkat.
A megolds kiemelked rsze a BETWEEN felttel hasznlata arra, hogy megvizsgl
juk, vajon az idszak hossza 5 s 60 v (a folyamatos munkaviszonyban tlttt 60
hnap elrshez szksges legrvidebb s leghosszabb id) kz esik-e, majd
a csoportosts hasznlata a H A V I N G zradkkal biztostva, hogy egymst kvet
vekrl legyen sz.
Amikor ezt a lekrdezst a WATCOM SQL 4.0 rendszeren futtattam, a lekrdezs
tervez becslse Romley megoldsra ngyszer akkora futsidt adott meg, mint az
enymre, tnyleges futsi ideje azonban mgis kevesebb lett. Arra tippelnk, hogy
a becslst a hromszoros n-sszekapcsols (self-join) tvesztette meg, amelynek
idignye rendszerint valban nagy.

11. feladvny - Munkarend


Az itt kvetkez krdst Cenk Ersoy tette fel a Gupta-frumon a CompuServe-n.
Az albbi szerkezet tblval rendelkezett:
CREATE TABLE Projektek
(munkarend CHAR(5) NOT NULL,
menet INTEGER NOT NULL CHECK (menet BETWEEN 0 AND 1000),
llapot CHAR(l) NOT NULL CHECK (llapot IN ('C, ' R' ) ) ;

31

32

SQL-fejtrk

A mintaadatai a kvetkezk voltak:


Projektek
munkarend
'AA100'
'AA100'
'AAIOO'
'AA200'
'AA200'
'AA300'
'AA300'

llapot
'O
R
*R'
'R
R
'C
'C

menet
0
1
2
0
1
0
1

Azokat a munkarend rtkeket szerette volna kivlogatni, amelyek esetn a menet


mez rtke nulla, az llapot rtke ' C ', s az sszes tbbi menet rtknl
az llapot ' R ' . A pldaadatok alapjn csak az ' AA100 ' felel meg ezeknek
a feltteleknek.

Megolds
Valjban egszen egyszer a megolds, de ahhoz, hogy a vlaszt lssuk, t kell fo
galmazni a lekrdezs meghatrozst. Ahelyett, hogy azt mondjuk, az adott mun
karend minden ms menet-rtkhez R llapot tartozzon", legyen a megfogalma
zs a kvetkez: az sszes nem nulla menetnek ' R' legyen az llapota",
gy a megolds szinte az lnkbe pottyan:
1

SELECT munkarend
FROM Projektek AS Pl
WHERE menet = 0
AND llapot = 'C
AND 'R' = ALL (SELECT llapot
FROM Projektek AS P2
WHERE menet <> 0
AND Pl.munkarend = P2.munkarend);

Adatformzs
Azzal szoktunk trflkozni, hogy az SQL rvidts mgtt valjban a Scarcely
Qualifies as a Language" (Nemigen nevezhet nyelvnek") kifejezs ll, mert csu
pn egy adatbzis-lekrdez nyelvrl van sz. Az SQL ANSI/ISO szabvnyban az
egyetlen bemeneti utasts az I N S E R T I N T O , s valdi kimeneti fggvny nincs is.
A lekrdezs eredmnyt a gazdaprogramnak adjuk t, ennek a feladata ezutn
a megjelents kezelse.
A C A S T () fggvnnyel lehetsgnk van egyik adattpusbl egy msikba talakta
ni egy rtket vagy korltozott mrtkben karakterlnc-mveleteket is vgezhe
tnk, de nem hatrozhatjuk meg gy az adatok megjelentsi formjt, mint ahogy
a hagyomnyos programozsi nyelvekben - Cobol, Fortran, PL/I, BASIC stb. - te
hetjk. Az SQL egyszeren nem rendelkezik olyan utastsokkal, mint a Cobolban
a P I C T U R E , a Fortranban a F O R M T vagy a PL/I-ben a P U T EDIT.
Tallkozhatunk olyan termkekkel, amelyek rendelkeznek a bels adattpusokat
formzott karakterlncc talaktani kpes fggvnyekkel, de ezek nem rszei
az ANSI/ISO szabvnynak. Ha utnozni akarjuk a Fortran F O R M T vagy a Cobol
P I C T U R E utastst a szabvnyos SQL-ben, gyakran kellene a C A S T () s
S U B S T R I N G () fggvnyeket, karakterlnc-sszefzst s egyb ehhez hasonl
mveleteket alkalmaznunk.

34

SQL-fejtrk

Az viszont kellemes, ha a gazdanyelvnek gy tudunk tadni egy eredmnytblt,


hogy annak sorai gy festenek, mintha ppen az adott problmra szabott folytonos
llomnybl szrmaznnak. Ebben az esetben a gazdaprogram minimlis erfesz
tssel jelentheti meg ezeket az adatokat. Ezt rtem az SQL-nl adatformzs alatt.

12. feladvny - Alperesek, llapotok


A kvetkez krdst Leonard C. Medl kldte el a CompuServe-nek 1995 novem
berben. A betegek brsgi keresetet nyjtottak be egy egszsggyi intzmny
ellen, amelyeket a Keresetek tblban trolunk:
Keresetek
keresetjd
10
20
30

beteg
'Kovcs'
'Jakab'
'Szab'

Minden keresethez egy vagy tbb alperes, ltalban orvos tartozik, akiket
a Kereset alperes tblban trolunk:
Keresetalperes
kereset id
10
10
10
20
20
30

'Vradi'
'Mjer'
'Takcs'
'Nyrfs'
'Mjer'
'Vradi'

Minden, keresethez rendelt alperes rendelkezik egy esemnysorral, ami az alperes


adott keresettel kapcsolatos llapotnak vltozsait kveti:

2. fejezet Adatformzs

Esemnyek
keresetJd
lu
10
10
10
10
10
10
10
10
20
20
20
30

alperes
'Vradi'
'Vradi'
'Vradi'
'Vradi'
'Mjer'
'Mjer'
'Mjer'
'Takcs'
'Takcs'
'Mjer'
'Mjer'
'Nyrfs'
'Vradi'

llapot
vv
VB'
'KI'
'LZ'
'W
'VB'
'KI'
'W
'VB'
W
VB'
W
'W

vattdatum
'1994-01-01'
'1994-02-01'
'1994-03-01'
'1994-04-01'
'1994-01-01'
'1994-02-01'
'1994-03-01'
'1994-01-01'
'1994-02-01'
'1994-01-0r
1994-02-01'
'1994-01-01'
'1994-01-01'

Az alperesekhez tartoz llapotok egymsra kvetkezse meghatrozott sorrend


ben trtnik, amint azt az llapotok tblja mutatja:
AllapotKodok
llapot
<w
'VB'
'KI'
'LZ'

altepotleir
A zsgalobizoltsagiu \ -r'
'Bizottsg;i vlemny benyjtva'
'A kereset iktatva'
'Lezrva'

sorszm
1
2
3
4

Egy alperes llapota (az adott keresettel kapcsolatban) a hozz rendelt legutols,
legmagasabb sorszmmal rendelkez llapot. Bizonyos jogszablyi okokbl kifo
lylag az esemnyek dtum szerinti sorrendje nem mindig fedi a sorszm szerinti
sorrendet.
Egy kereset llapota annak az alperesnek az llapott jelenti, aki a keresetben rin
tett szemlyek kzl a legkisebb sorszm llapottal rendelkezik. Ezzel egy kereset
llapota tulajdonkppen az llapotsorszmok legnagyobb rtkei kzl a legkisebb.
A pldnkban szerepl adatokra adott vlasz a kvetkez lenne:

36

SQL-fejtrk

keresetjd
10
20
30

beteg
'Kovcs'
'Jakab'
'Szab'

aflapot
'VB'
W
'W

A feladat az egyes keresetek llapotainak megkeresse s megjelentse. n ezt


a krdst a megjelentsi problmk kz soroltam.

1. megolds
Medal vlasza egyetlen SQL-lekrdezs, ami a lerst kzvetlenl kdd fordtja le:
SELECT Cl.kereset_id. Cl.beteg, T2.llapot
FROM Keresetek AS Cl, AllapotKodok AS T2
WHERE T2.sorszm
IN (SELECT MIN(S2.sorszm)
FROM AllapotKodok AS S2
WHERE S2.sorszm
IN (SELECT MAX(S3.sorszm)
FROM Esemnyek AS El, AllapotKodok AS S3
WHERE El.llapot = S3.llapot
AND El.kereset_id = Cl.kereset_id
GROUP BY El.alperes));

2. megolds
Ltezik ms megolds is. Knnyebb kinyerni azon llapotok kdjait egy kereset
ben, amelyeket minden alperes elrt mr:
SELECT
FROM
WHERE
GROUP
HAVING

El.kereset_id, Cl.beteg, El.llapot


Esemnyek AS El, Keresetek AS Cl
El.kereset_id = Cl.kereset_id
BY El.keresetjd, Cl.beteg, El.llapot
COUNT(*) = (SELECT COUNT(DISTINCT alperes)
FROM Esemnyek AS E2
WHERE El.kereset_id = E2.kereset_id)
ORDER BY El.kereset_id;

2. fejezet Adatformzs

Ami mg ennl is Pontosabb: ha az AllapotKodok tblra pillantunk, lthatjuk,


hogy az llapot s a sorszm egyarnt kulcsok ebben a tblban, amelyek az lla
pot lersra mutatnak. (Valjban mindhrom oszlop kulcs). Ez tulajdonkppen
egy kdfordt tbla.
Ha eldobnnk a ktkarakteres llapotkdot, s minden elfordulsi helyn az lla
pot sorszmval helyettestennk, akkor ezzel olyan adatszerkezethez jutnnk,
amelybl knnyen kivlaszthat lenne minden benyjtott keresethez az llapotsor
szm legnagyobb rtke. Ezen talakts legegyszerbb mdja a SELECT utasts
ban elhelyezett bels lekrdezs:
SELECT El.kereset_id, Cl.beteg, (SELECT sorszm
FROM AllapotKodok AS Sl
WHERE Sl.llapot = El.llapot)
FROM Esemnyek AS El, Keresetek AS Cl
WHERE El.kereset_id = Cl.kereset_id
GROUP B Y El.kereset_id, Cl.beteg, El.llapot
HAVING COUNT(*) = (SELECT COUNT(DISTINCT alperes)
FROM Esemnyek AS E2
WHERE El.kereset_id = E2.kereset_id)
ORDER B Y El.kereset_id;

3. megolds
Sorin Shtirbunak ksznhetjk a harmadik megoldsi mdszert:
SELECT kereset_id, MAX(beteg), MAX(TI.llapot)
FROM llapot AS TI, Keresetek AS Cl
WHERE TI.sorszm =
(SELECT MAX(T2.sorszm)
FROM llapot AS T2, Esemnyek AS El
WHERE T2.llapot = El.llapot
AND El.kereset_id = Cl.kereset_id
GROUP B Y El.kereset_id, alperes)
GROUP B Y kereset_id, TI.sorszm
HAVING Tl.sorszm = MIN(TI.sorszm);
Felmerl a krds, hogy vajon ezzel a harmadik megoldssal n-e a hatkonysg.
Valsznleg ez fgg az indexelsi mdtl, s attl is, hogy az adott SQLalkalmazs hogyan kezeli a bels lekrdezseket s a G R O U P B Y zradkot.

37

38

SQL-fejtrk

13. feladvny- Oktatk


1996 mjusban Brendan Campbell egy rdekes problmval lepte meg az Oracle
User Group Forum olvasit. Felhatalmazott, hogy felhasznljam s nyomtatsban is
megjelentessem a feladatot, valamint az hibs PL/SQL megoldst, mint rossz pl
dt, vllalva ezzel a tudomnyos halads rdekben a megszgyenlst s a kz
megvetst. Testnket felajnlani knny, hiszen addigra mr halottak vagyunk, de
a mltsgunkrl lemondani - az bizony roppant nehz.
Egy olyan lekrdezst szeretnnk rni, ami adatokat ad t egy jelentskszt prog
ramnak az egyes kurzusokhoz s hallgatkhoz tartoz oktatk neveinek megjelen
tse cljbl. A feladat nehzsge abban ll, hogy a nyomtatn csak kt oktat ne
vnek megjelentsre van hely.
Ha csak egy oktat felel meg a feltteleknek, a nevt megjelentjk az els oszlop
ban s a msodik oszlop rtkt resre vagy NULL-ra lltjuk. Ha pontosan kett
oktatnk van, a kt oszlopban betrendben megjelentjk a neveiket. Ha kettnl
tbb oktatnak kellene szerepelnie a felsorolsban, kirjuk az els nevt az els
oszlopba, a msodikban pedig a - -Tbb- - ' karakterlncot jelentjk meg.
1

Tegyk fel, hogy a szksges adatokat tartalmaz tbla szerkezete a kvetkez:


CREATE TABLE Nyilvntarts
(kurzus INTEGER NOT NULL,
hallgat CHAR(IO) NOT NULL,
oktat CHAR(IO) NOT NULL,
Brendan eredeti megoldsa 70 sor hossz volt. A tiszta SQL megolds belefr egy
krlbell 12 soros, egyetlen utastst tartalmaz kdba.

1. megolds
J mdszer lehet a szlsrtk-fggvnyek hasznlata.
SELECT
FROM
GROUP
HAVING
UNION

Rl.kurzus, Rl.hallgat, MIN(Rl.oktat), NULL


Nyilvntarts AS Rl
BY Rl.kurzus, Rl.hallgat
COUNT(*) = 1

2. fejezet Adatformzs

SELECT Rl.kurzus, Rl.hallgat, MIN(Rl.oktat),


MAX(R1.oktat)
FROM Nyilvntarts AS Rl
GROUP BY Rl.kurzus, Rl.hallgat
HAVING COUNT(*) = 2
UNION
SELECT Rl.kurzus, Rl.hallgat, MIN(Rl.oktat), '--Tbb--'
FROM Nyilvntarts AS Rl
GROUP BY Rl.kurzus, Rl.hallgat
HAVING COUNT(*) > 2;
Most nzzk a rendszerint fraszt rszleteket:
Az els S E L E C T utasts kiszri a pontosan egy oktatval rendelkez kurzus-hallga
t prokat. Ltjuk, hogyan mkdik a M I N () fggvny? Ha csak egy oktat van, ak
kor versenytrs hjn a legkisebb is lesz. Hinyz rtkek esetn elszeretettel al
kalmazom a NULL rtket, de hasznlhatunk helyette karakterlnc-llandt is.
A msodik S E L E C T a pontosan kett oktatval br kurzus-hallgat megfeleltetse
ket keresi meg. A M I N () s M A X () fggvnyek sorba rakjk a kt nevet, mivel csak
kt megfelel tallat van.
A harmadik S E L E C T a kettnl tbb oktatval rendelkez kurzus-hallgat kombi
ncikat vlasztja ki. A MIN () fggvnyt hasznltam az els oktat kivlasztsra
s a ' Tbb' llandt a msodik oszlopba val kirshoz, ahogy a feladatmeghat
rozs megkvnta.

2. megolds
Richrd S. Romley jfent tltett a nyomtatsban megjelent megoldsomon, azzal
a fogssal, hogy a kt S E L E C T utastst egy C A S E kifejezsben hasznlt szlsrtk
fggvnny srtette, az SQL-92 szablyai szerint:
SELECT kurzus, hallgat, MIN(oktato),
CASE COUNT(*) WHEN 1 THEN NULL
WHEN 2 THEN MAX(oktat)
ELSE '--Tbb-FROM Nyilvntarts
GROUP BY kurzus, hallgat;
1

39

40

SQL-fejtrk

A C A S E kifejezsnek ez a tpusa gondokat okozhat a jelenlegi SQL-alkalmazsokban. Nhny rgebbi SQL-megvalstsbl teljesen hinyoznak a C A S E kifejezsek,
egyesek pedig sszegz fggvnyek hasznlatt nem teszik lehetv a C A S E kifeje
zsen bell. A kifejezsnek ez a formja trhat egy ezzel teljesen egyenrtk
utastsformra:
CASE WHEN COUNT(*) = 1 THEN NULL
WHEN C0UNT(*) = 2 THEN MAX(oktat)
ELSE '--Tbb--'

Ltni fogjuk, hogy a S E L E C T utastsban hasznlt C A S E kifejezsek sokszor nagyon


knyelmes megoldst jelenthetnek az adatmegjelentsi problmkra.

14. feladvny - Telefon


Tegyk fel, hogy egy vllalat telefonknyvt szeretnnk az j adatbzisrendsze
rnkkel megvalstani, s mr rendelkeznk az albbi tblkkal:
CREATE TABLE Alkalmazottak
(alk_id INTEGER PRIMARY KEY,
keresztnv CHAR(20) NOT NULL,
vezetknv CHAR(20) NOT NULL);
CREATE TABLE Telefonok
(alk_id INTEGER NOT NULL,
telefontipus CHAR(3) NOT NULL
CHECK (telefontipus IN (('ott', 'fax'))),
telefonszm CHAR(12) NOT NULL,
PRIMARY KEY (alk_id, telefontipus, telefonszm),
FOREIGN KEY alk_id REFERENCES Alkalmazottak.alk_id);
Az ' ott' s ' fax' kdok azt jelzik, hogy a telefonszm az alkalmazott otthoni te
lefonszma vagy faxszma-e. Egy jelentst szeretnnk kszteni, ami soronknt
minden alkalmazottra megjelenti a hozz tartoz telefonszmokat, vagy NULL rt
ket, ha az egyik vagy mindkt szm hinyzik.
Meg kell jegyeznem, hogy a Telefonok tblban lv F O R E I G N K E Y zradk miatt
nem jelenthetnk meg olyan adatot a listban, ami nem alkalmazotthoz tartozik.

2. fejezet Adatformzs

A P R I M A R Y K E Y egy kicsit hossznak tnik, amg vgig nem gondoljuk a lehetsges


eseteket. Egymssal hzassgban l alkalmazottak hasznlhatjk ugyanazt a faxsz
mot s otthoni telefont, s ugyanaz a szm telefonhoz s faxhoz egyarnt tartozhat.

Megolds
A lekrdezs egy sor hibalehetsget hordoz magban. Az els gondolat az otthoni
telefonok adatainak kln lekrdezsbe foglalsa. Mivel minden alkalmazottat ltni
szeretnnk, egy kls sszekapcsols ( O U T E R J I N ) hasznlatra van szksgnk:
CREATE VIEW Otelefonok (vezetknv, keresztnv, alk_id,
otthoni_szam)
AS SELECT El.vezetknv, El.keresztnv, El.alk_id, Hl.telefonszm
FROM (Alkalmazottak AS El
LEFT OUTER JIN
Telefonok AS Hl
ON El.alk_id = Hl.alk_id AND Hl.telefontipus = 'ott');
Ugyanezzel a megkzeltssel llthatjuk el a faxok adatait egy msik lekrdezssel:
CREATE VIEW Ftelefonok (vezetknv, keresztnv, alk_id, faxszm)
AS SELECT El.vezetknv, El.alk_id, FI.telefonszam
FROM (Alkalmazottak AS El
LEFT OUTER JIN
Telefonok AS FI
ON El.alk_id = Fl.alk_id AND FI.telefontipus = 'fax');
Indokoltnak ltszik a kt nzettbla sszevonsa, ami az albbi eredmnyt adja:
SELECT Otelefonok.vezetknv, Otelefonok.keresztnv, otthoni_szam,
faxszm
FROM Otelefonok AS Hl, Ftelefonok AS FI
WHERE Hl.alk_id = Fl.alk_id;

Csakhogy ez a megolds nem fog mkdni, mert a felsorolsbl kimaradnak


a csak faxszmmal rendelkezk. Ha mindkt tblbl szrmaz adatot meg akarjuk
tartani, egy teljes kls sszekapcsolsra ( F U L L O U T E R J I N ) van szksgnk,
amellyel gy fest a megolds:

41

42

SQL-fejtrk

SELECT Hl.vezetknv, Hl.keresztnv, otthoni_szam, faxszm


FROM Otelefonok AS Hl
FULL OUTER JIN
Ftelefonok AS FI
ON Hl.alk_id = Fl.alk_id;

Sajnos ez a megolds sem jelenti meg a csak faxszmmal rendelkezk nevt, ame
lyek gy resen maradnak, mert csak az otelefonok tblban lv nevek kiratst
tartalmazza a lekrdezs. Ezt a problmt a C O A L E S C E () fggvny oldja meg sz
munkra. Ez a paramterknt kapott kifejezslistbl balrl jobbra haladva az els
nem NULL rtkkel tr vissza:
SELECT COALESCE (Hl.vezetknv, FI.vezetknv),
COALESCE (Hl.keresztnv, FI.keresztnv),
otthoni_szam, faxszm
FROM Otelefonok AS Hl
FULL OUTER JIN
Ftelefonok AS Fl
ON Hl.alk_id = Fl.alk_id;
Ez mkdik ugyan, de futsrl nemigen, inkbb csak vnszorgsrl beszlhetnk,
mert alighanem ellltja a nzettblkat, mieltt hasznln azokat. A megnyugtat
megoldst akkor lelhetjk meg, ha visszatrnk az Ftelefonok s otelefonok n
zettblkban lv OUTER JIN kapcsolatokhoz. Innen kiemelhetjk az Alkalma
zottak tbla kapcsolatt s az albbi mdon sszevonhatjuk a kt F R O M zradkot:
SELECT El.vezetknv, El.keresztnv,
Hl.telefonszm AS Otthon,
Fl.telefonszm AS FAX
FROM (Alkalmazottak AS El
LEFT OUTER JIN
Telefonok AS Hl
ON El.alk_id = Hl.alk_id AND Hl.telefontipus = 'ott')
LEFT OUTER JIN
Telefonok AS Fl
ON El.alk_id = Fl.alk_id AND Fl.telefontipus = 'fax';
Mivel a lekrdezs minden tblt elsre megkap, gyorsabbnak kell lennie, mint
a rossz kiindulssal ellltott megolds. Ez megint egy olyan lekrdezs, amit nem
knny tltetni a Sybase, Oracle vagy Gupta stlus O U T E R J I N formtumra, mi
vel ezek az SQL-ek nem kezelik a begyazott O U T E R J I N kapcsolatokat.

2. fejezet Adatformzs

15. feladvny - A kt legutbbi alapbr


1996 jniusban kldte ezt az elgondolkodtat feladatot Jack Wells a CompuServere. A helyzet ismers azoknak az SQL-programozknak, akik harmadik genercis
nyelvekben gondolkod munkatrsakkal knytelenek egytt dolgozni. A progra
mozk egy jelentst ksztenek az alkalmazottakrl, amelyhez szksgk van az al
kalmazottak jelenlegi s az ezt megelz alapbrre. A jelentsnek szemlyenknt
tartalmaznia kell a bremels dtumt s az alapbr sszegt.
Ez nem nehz feladat, ha minden brt kln sorba rhatunk az eredmnylistban s
az adatformzst a gazdaprogramra hagyhatjuk. Igazbl ez az els programozsi
problma.
Csakhogy elfelejtettem emlteni, hogy a programozk csoportjnak lusta s toho
nya tagjai a jelenlegi s a megelz br informciit is alkalmazottanknt egy sor
ban szeretnk megkapni. gy egy rendkvl egyszer kurzorelhelyez utastssal
megoldhatjk a feladatot, anlkl, hogy tnyleges munkt vgeznnek.
Jack felvette a kapcsolatot Fabian Pascallal, az Understanding Relational
Databases
(John Wiley, 1993) s SQL and Relational Basics (M&TABLE Books, 1993) cm
knyvek szerzjvel, aki egy heti munka utn azt mondta, a problma nem oldhat
meg egy lekrdezssel. Vlemnye szerint egy valdi relcis nyelven meg lehet
ne rni a programot, de mivel az SQL nem az, gy ez lehetetlen, mg az SQL-92-ben
is". Ezzel meglengette elttem a vrs posztt!
Mg egy dolgot nem emltettem, ami korltozza mozgsternket: Jack az Oracle-t
hasznlja munkjhoz. A termk mg mindig nem teljesti az SQL-92 szabvny el
rsait (nincsenek megfelel OUTER JIN kapcsolatok, nincsenek ltalnos skalris
alkifejezsek, s gy tovbb), vagyis a lekrdezsnek a j reg SQL-89 szablyai
szerint kell mkdnie.
Tegyk fel, hogy ezekkel a tesztadatokkal rendelkeznk:
CREATE TABLE Fizetsek
(alkalm CHAR(IO) NOT NULL,
fiz_datum DATE NOT NULL,
fiz_osszeg DECIMAL (8,2) NOT NULL,
PRIMARY KEY (alkalm, fiz_datum));

43

SQL-fejtrk

44

INSERT INTO Fizetsek


VALUES (('Tams', '1996-06-20', 500.00),
('Tams', '1996-08-20', 700.00),
('Tams', '1996-10-20', 800.00),
('Tams', '1996-12-20', 900.00),
('Ferenc', '1996-06-20', 500.00),
('Kroly', '1996-07-20', 500.00),
('Kroly', '1996-09-20', 700.00));
Tamsnak kt fizetsemelse is volt. Ferenc mg j fi, Kroly pedig egy breme
lssel bszklkedhet.

1. megolds
Elszr oldjuk meg a krds knny felt. A megolds annak a lekrdezsnek
a hasznlata, amit ltalnos szlsrtknek, vagy els(n) fggvny"-nek szoktam
nevezni. Helyezzk ezt egy nzettblba:
CREATE VIEW Fizetesekl (alkalm, jel_fiz_datum, jel_fiz_osszeg)
AS SELECT SO.alkalm, SO.fiz_datum, MAX(SO.fiz_osszeg)
FROM Fizetsek AS SO, Fizetsek AS SI
WHERE SO.fiz_datum >= SI.fiz_datum
GROUP BY SO.alkalm, SO .fiz_datum
HAVING COUNT(*) <= 2;
CREATE VIEW Fizetesek2 (alkalm, fiz_datum, fiz_osszeg)
AS SELECT SO.alkalm, SO.sal_date, MAX(SO.fiz_osszeg)
FROM Fizetsek AS SO, Fizetsek AS SI
WHERE SO.fiz_datum <= SI.fiz_datum
AND SO.alkalm = Sl.alkalm
GROUP BY SO.alkalm, SO .fiz_datum
HAVING COUNT(*) <= 2;
Eredmnyek
alkalm
'Ferenc'
'Kroly'
'Kroly'
'Tams'
'Tams'

fizdatum
'1996-06-20'
'1996-07-20'
'1996-09-20'
'1996-10-20'
'1996-12-20'

fizosszeg
500.00
500.00
700.00
800.00
900.00

2. fejezet Adatformzs

A Fizetsek tbla Sl pldnya alkalmazottanknt kett vagy kevesebb fizets


emelsi alkalomban rgzti a hatrt. A M A X () fggvny a br sszegnek kinyers
re szolgl. Ezzel soronknt fog megjelenni minden alkalmazott utols kt fizetsbe
li vltozsa. Ha a programozk nem lennnek olyan lustk, ezt a tblt t is
adhatnnk, rjuk hagyva a jelentsnek megfelel adatformzst.

2. megolds
A valdi problma egy kicsit bonyolultabb. Az SQL-89 korltai kzt mozogva a kr
ds egyik megoldsa az esetek kt csoportra osztsa:
1. Alkalmazottak csupn egyetlen brvltozssal.
2. Alkalmazottak kett vagy annl tbb brvltozssal.
Abban biztosak lehetnk, hogy minden alkalmazott beleesik az egyik, de csak az
egyik csoportba. Az egyik megolds e kt csoport egyestse lehet a UNION utastssal:
SELECT SO.alkalm, SO.fiz_datum, SO.fiz_osszeg, Sl.fiz_datum,
^ Sl.fiz_osszeg
FROM Fizetsek AS SO, Fizetsek AS Sl
WHERE SO.alkalm = Sl.alkalm
AND SO.fiz_datum =
(SELECT MAX(S2.fiz_datum)
FROM Fizetsek AS S2
WHERE SO.alkalm = S2.alkalm)
AND Sl.fiz_datum =
{SELECT MAX(S3.fiz_datum)
FROM Fizetsek AS S3
WHERE SO.alkalm = S3.alkalm
AND S3.fiz_datum < SO.fiz_datum)
UNION ALL
SELECT S4.alkalm, MAX(S4.fiz_datum) , MAX(S4.fiz_osszeg) , NULL,
NULL
FROM Fizetsek AS S4
GROUP BY S4.alkalm
HAVING COUNT(*) = 1;

45

46

SQL-fejtrk

alkalm
'Tams'
'Kroly'
'Ferenc'

fizdatum
'1996-12-20'
'1996-09-20'
'1996-06-20'

fizosszeg
900.00
700.00
500.00

fizdatum
'1996-10-20'
'1996-07-20'
NULL

fizosszeg
800.00
500.00
NULL

A DB2-programozknak ismers lesz ez a megolds, mint az O U T E R J I N megval


stsa az SQL-92 szabvny O U T E R JIN mvelete nlkl. Az els SELECT a legnehe
zebben rthet. Ez egy n-sszekapcsols a Fizetsek tbln, ahol az SO pldny
a legutbbi fizets adatforrsaknt, az Sl pedig az ezt kvet legutbbi fizets for
rsaknt szerepel. A msodik SELECT egy egyszer csoportostott lekrdezs,
amely az alkalmazottakat egy sorba helyezi. Mivel az eredmnyhalmazok klnl
lak, hasznlhatjuk a U N I O N A L L utastst a U N I O N helyett, megtakartva ezzel egy
tovbbi rendezsi mveletet.

3. megolds
Tbb javtott megoldst is kaptam vlaszknt a prblkozsaimra. A Smith Barney
alkalmazsban ll Richrd Romley a kvetkez SQL-92 megoldst kldte. Ez ki
hasznlja a bels lekrdezs elnyeit a nzettblk elkerlsre:
SELECT B.alkalm, B.maxdatum, Y.fiz_osszeg, B.maxdatum2,
W Z.fiz_osszeg
FROM (SELECT A.alkalm, A.maxdatum, maxdatum2 = MAX(X.fiz_datum)
FROM (SELECT W.alkalm, maxdatum = MAX(W.fiz_datum)
FROM Fizetsek AS W
GROUP BY W.alkalm) AS A
LEFT OUTER JIN Fizetsek AS X
ON A.alkalm = X.alkalm
AND A.maxdatum > X.fiz_datum
GROUP BY A.alkalm, A.maxdatum) AS B
LEFT OUTER JIN Fizetsek AS Y
ON B.alkalm = Y.alkalm
AND B.maxdatum = Y.fiz_datum
LEFT OUTER JIN Fizetsek AS Z
ON B.alkalm = Z.alkalm
AND B.maxdatum2 = Z.fiz_datum;

2. fejezet Adatformzs

Ha az ltalunk hasznlt SQL nem tmogat mst, csak a tbla- vagy nzettbla
neveket az OUTER JIN kifejezsben, az A s B nev allekrdezseket trhatjuk
nzettblkk.

4. megolds
Mike Conway egy Oracle-re rt megoldssal llt el, amit tbb-kevesebb sikerrel t
ltettem az SQL-92 szabvny szerint. Az tltets nehzsge az volt, hogy az Oracle
ltal hasznlt SQL nem tmogatja az SQL-92 szerinti O U T E R J I N formtumot, gy fi
gyelni kell a futtatsi sorrendre ahhoz, hogy a megfelel eredmnyt kapjuk. Syed
Kadir, az Oracle szoftvermrnke megoldsom egy tovbbfejlesztett vltozatt
kldte el, ami az els megoldsban alkalmazott nzettblt hasznlja:
SELECT Sl.alkalm, Sl.fiz_datum, Sl.fiz_osszeg, S2.fiz_datum,
S2.fiz_osszeg
FROM Fizetesekl A S Sl, Fizetesek2 AS S2 - a nzettbla hasznlata
WHERE Sl.alkalm = S2.alkalm
AND Sl.fiz_datum > S2.fiz_datum
UNION ALL
SELECT alkalm, MAX(fiz_datum). MAX(fiz_osszeg), NULL, NULL
FROM Fizetesekl
GROUP BY alkalm
HAVING COUNT(*) = 1 ;

Elfordulhat, hogy az utols kt oszlopot a C A S T (NULL A S D A T E ) s a C A S T (NULL


AS DECIMAL (8,2) ) kifejezsekkel kell helyettestennk, hogy a UNION szmra
megfelel adattpusok lljanak rendelkezsre.

5. megolds
Richrd Romley-val hosszasan leveleztnk a feladatra adhat egyb megoldsokkal
kapcsolatban, mg mindketten ugyanarra a hagyomnyoktl elszakadt megkzel
tsre jutottunk, amit formai megfontolsok miatt el akartam vetni. Vgl gy dn
tttem, a teljestmny legyen a dnt sz.

47

48

SQL-fejtrk

A mdszer a dtumok s brek karakterlncokk trtn talaktsn alapul, ame


lyeket a dtummal kezdden sszefznk, majd ebbl vlasztjuk ki jra a fizets
sszegt.
S E L E C T A.alkalm,
MAX(A.fiz_datum) A S datuml,
S U B S T R I N G (MAX(CAST(A.fiz_datum A S CHAR(10))
II CAST(A.fiz_osszeg A S CHAR(8))), 11, 8) A S fizl,
MAX(B.fiz_datum) A S datum2,
S U B S T R I N G (MAX(CAST(B.fiz_datum A S CHAR(10))
II CAST(B.fiz_osszeg A S CHAR(8))), 11, 8) A S fiz2
F R O M Fizetsek A S A
LEFT OUTER JOIN
Fizetsek A S B
O N A.alkalm = B.alkalm
A N D A.fiz_datum > B.fiz_datum
G R O U P B Y A.alkalm;

Ha akarnnk, az egsz S U B S T R I N G () kifejezst jra visszaalakthatnnk


D E C I M A L (8,2) formtumra, ezzel visszanyerve az eredeti adattpust. Tovbbi
elny, hogy a mdszer tovbbi M A X () s S U B S T R I N G () prokkal egszthet ki
a megfelel L E F T O U T E R J O I N hasznlata mellett.

Adatkivlaszts
Rendszerint megemltem az SQL-eladsaim hallgatinak, hogy a nyelvet nagyon
knny elsajttani, mert a S E L E C T . . . F R O M . . . utastsok a munka 90%-t lefe
dik. Tanuljunk meg egyetlen utastst s mris komoly hatalommal rendelkeznk
egy j programozsi nyelv felett. Persze ez olyan, mintha azt mondannk, hogy
a LISP egyszer, hiszen minden program csupn egy fggvnyhvsbl ll.
A csapda termszetesen ott rejtzik, hogy egyetlen S E L E C T utasts is lehet annyira
sszetett, nyakatekert s bonyolult, mint brmely eljrskzpont program.
A most kvetkez feladvnyok alapja egy olyan szellemes mdszer a tblk bizo
nyos adatainak kiszrsre, ami els rnzsre esetleg nem teljesen nyilvnval.

16. feladvny - Folyamatok


Gerard Mank, az ARI alkalmazottja 1994 prilisban kldte be a CompuServe-re
az albbi feladvnyt. Az ARI nem sokkal korbban vltott a Paradoxrl a WATCOM
SQL-re (amit ma Sybase SQL Anywhere-nek hvnak). A korbbi adatbzis tltet
st brmifle normalizlsi vagy adatsszefggsi megfontols nlkl, egyszeren
a Paradox tblk oszlopneveinek s adattpusainak Sybase SQL Anywhere tblkba
trtn msolsval oldottk meg. Tudom, hogy mint SQL-szakrtnek, azt kellett
volna vlaszolnom, hogy a pokol egyik rszlege azok szmra van fenntartva, akik

50

SQL-fejtrk

nem normalizlnak. Ezzel viszont a feladat nem lett volna megoldva, msrszt az
ARI-hoz hasonl hozzllssal idrl idre szembetallkozom a vals problmk
megoldsa sorn.
A rendszer az alkalmazottak egyes feladatok vgrehajtsra ltrehozott csoportjait
kveti nyomon. Minden feladathoz tartozhat pontosan egy elsdleges (primary) fo
lyamat s egyetlen segd- (assistant) folyamat. A krdses tblk az albbi mdon
plnek fel:
C R E A T E T A B L E Feladatok

(feladat_id INTEGER NOT N U L L PRIMARY KEY,


kezd_datum D A T E N O T NULL,

CREATE TABLE Alkalmazottak


(alk_id INTEGER NOT NULL PRIMARY KEY,
nev CHAR (20) NOT NULL,

CREATE TABLE Csoportok


(feladat_id INTEGER NOT NULL,
folyamattipus INTEGER NOT NULL,
alk_id INTEGER NOT NULL,

Az els feladatunk valamilyen adatpsg-ellenrzs megvalstsa a Csoportok


tbln. Ennl a feladatnl ne foglalkozzunk a normalizlssal vagy ms tblkkal.
A f feladat egy lekrdezs ltrehozsa egy jelents szmra, ami a feladatazonos
tk (f eladat_id) szerint kirja a feladatokat, az elsdleges folyamatot (ha van), s
a segdfolyamatot (ha van). Egy kis segtsg: a f eladat_id adatokat csak a Fel
adatok tblbl kaphatjuk meg, mert csak ebben szerepel az sszes feladat, mg
a Csoportok tbla csak azokat tartalmazza, amelyekhez csoport lett rendelve. Egy
alkalmazott egyidben tartozhat egy feladat elsdleges s segdfolyamathoz is.

1. megolds
Az els feladat a hivatkozsi psg biztostsa. A Csoportok tbla valsznleg
F O R E I G N K E Y hivatkozsokon keresztl ms tblkhoz kapcsoldik, de sohasem
rthat, ha egy adatbzisban vgrehajtjuk az albbi ellenrzseket:

3. fejezet Adatkivlaszts

CREATE TABLE Csoportok


(feladat_id INTEGER NOT NULL REFERENCES Feladatok(feladat_id),
folyamattipus CHAR(IO) NOT NULL
CHECK (folyamattipus I N ('Primary', 'Assistant')),
alk_id INTEGER NOT NULL REFERENCES Alkalmazottak(alk_id),

Tapasztaltabb SQL-felhasznlk rgtn a L E F T O U T E R J I N hasznlatra gondolnak,


mivel ahhoz, hogy csak az elsdleges folyamatokat kapjuk vissza, ezt is rhatnnk:
SELECT Feladatok.feladat_id, Csoportok.alk_id AS "Primary",
FROM Feladatok LEFT OUTER JOIN Csoportok
ON Feladatok.feladat_id = Csoportok.feladat_id
WHERE Csoportok.folyamattipus = 'Primary';
Egy hasonl O U T E R J O I N hasznlatval az Alkalmazottak tblt a Csoportok tb
lhoz csatolhatjuk. A gond ezzel az, hogy kt egymstl fggetlen O U T E R J O I N
kapcsolatot szndkozunk ltrehozni az egyes folyamattpusok szmra, s ezek
nek az eredmnyt tennnk egy tblba. Taln lehetsges felpteni egy hatalmas,
mlyen egymsba gyazott visszamutat (self) O U T E R J I N kapcsolatokkal teli
SELECT utastst, de az olvashatatlan s nehezen rthet lenne. A jelents ugyan
megoldhat lenne kln az elsdleges s kln a segdfolyamatokra megrt nzet
tblkkal s ezek egyestsvel, de mindez elkerlhet az albbi lekrdezssel:
SELECT Feladatok.feladat_id,
(SELECT alk_id
FROM Csoportok
WHERE Feladatok.feladat_id =
AND Csoportok.folyamattipus
(SELECT alk_id
FROM Csoportok
WHERE Feladatok.feladat_id =
AND Csoportok.folyamattipus
FROM Feladatok;

Csoportok.feladat_id
= 'Primary') AS "Primary",

Csoportok.feladat_id
= 'Assistant') AS Assistant

A "Primary" sz ketts idzjeles hasznlatnak oka az, hogy az SQL-92-ben ez


egy kulcssz a P R I M A R Y K E Y kifejezsbeli hasznlata miatt. A ketts idzjelek k
z tett szt a parancsrtelmez azonostknt veszi figyelembe. Amikor ugyanez
a sz egyszeres idzjelek (aposztrfok) kztt jelenik meg, akkor karakterlnc
knt szerepel.

51

52

SQL-fejtrk

A trkk a kls S E L E C T utastson belli kt, egymstl fggetlen skalris S E L E C T


utasts hasznlatnak lehetsgben rejlik. Az alkalmazottak neveinek megjelen
tshez csak a bels SELECT utastst kell megvltoztatni.
SELECT

Feladatok.feladat_id,

(SELECT nev
FROM Csoportok, Alkalmazottak
WHERE Feladatok.feladat_id = Csoportok.feladat_id
AND Alkalmazottak.alk_id = Csoportok.alk_id
AND Csoportok.folyamattipus = 'Primary') AS "Primary",
(SELECT nev
FROM Csoportok, Alkalmazottak
WHERE Feladatok.feladataid = Csoportok.feladat_id
AND Alkalmazottak.alk_id = Csoportok.alk_id
AND Csoportok.folyamattipus = 'Assistant') AS Assistant
FROM Feladatok;
Ha olyan alkalmazottunk van, aki egy feladat elsdleges s msodlagos folyamat
ban is rszt vesz, akkor szerepelni fog mindkt helyen. Ha kett vagy annl tbb
elsdleges folyamat, vagy kett vagy tbb segdfolyamat tartozik egy feladathoz,
akkor hibazenetet kapunk - ahogy az el is vrhat. Ha nincs elsdleges vagy se
gdfolyamat, res eredmnyt kapunk N U L L rtk formjban. Ezzel el is jutottunk
a kvnt OUTER JIN eredmnyekhez.

2. megolds
Skip Lees a kaliforniai Chicobl a Csoportok tblra az albbi szablyok rvnye
stst szorgalmazta:
1. Egy f eladat_id rtkhez nulla vagy egy elsdleges folyamat tartozik.
2. Egy f eladat_id rtkhez nulla vagy egy segdfolyamat tartozik.
3- Egy f eladat_id rtkhez legalbb egy (valamelyik tpus) folyamatnak
tartoznia kell.
A 3. szably szerint nem lehet olyan pillanat, amikor egy feladat nem rendelkezik
csoporttagokkal. Emiatt a csoportinformcikat mg a feladat rekordjnak ltreho
zsa eltt rgzteni kell a rendszerben. Egy hivatkozsipsg-ellenrzssel rvnyre
juttathat ez a megszorts. Az 1. s 2. korltozs a feladat_id s a folyamat
tipus ktoszlopos elsdleges kulccs nyilvntsval kiknyszerthet, gy egy
adott folyamattpushoz ugyanaz a feladatazonost nem vihet fel ismtelten.

3. fejezet Adatkivlaszts

C R E A T E T A B L E Feladatok

(feladat_id INTEGER NOT NULL PRIMARY KEY REFERENCES Csoportok


* (feladat_id) ,
kezd_datum DATE NOT NULL,

CREATE TABLE Csoportok


(feladat_id INTEGER NOT NULL,
folyamattipus CHAR(10) NOT NULL
CHECK (folyamattipus IN ('Primary', 'Assistant')),
alk_id INTEGER NOT NULL REFERENCE Alkalmazottak(alk_id),
PRIMARY KEY (feladat_id, folyamattipus));
Azrt ezzel a megoldssal van egy kis gond. Az SQL-92 szerint a hivatkoz tbla
REFERENCES zradka csak olyan oszlopra hivatkozhat, amely a hivatkozott tbl
ban egyedi rtkknt vagy elsdleges kulcsknt szerepel. Azaz a hivatkozsnak
ugyanolyan szm, ugyanolyan tpus, ugyanolyan sorrend oszlopra kell mutatnia,
ahogy a Csoportok tblban a vlasz meg is adja a PRIMARY KEY ( f eladat_id,
folyamattipus) meghatrozsban az elsdleges kulcsot. Emiatt a Feladatok tbla
f eladat_id mezje nem hivatkozhat a Csoportok tblban nmagban
a f eladat_id oszlopra. Az ellentmondst egy U N I Q U E zradkkal feloldhatjuk:
CREATE TABLE Csoportok
(feladat_id INTEGER NOT NULL UNIQUE,
folyamattipus CHAR(10) NOT NULL
CHECK (folyamattipus IN ('Primary', 'Assistant')),
PRIMARY KEY (feladat_id, folyamattipus));
Taln mg termszetesebb, ha ebben a formban rjuk:
CREATE TABLE Csoportok
(feladat_id INTEGER NOT NULL PRIMARY KEY,
folyamattipus CHAR(10) NOT NULL
CHECK (folyamattipus I N ('Primary', 'Assistant')),
UNIQUE (feladat_id, folyamattipus));
Azrt jobb gy, mert a f eladat_id az az oszlop, amelyik a tblban trolt egyede
ket egyrtelmen azonostja. Igazbl a konkrt SQL-alkalmazsokban a P R I M A R Y
KEY megadsa hatssal lehet az adattrols s -elrs mdjra, gy e vlasztsnak
a teljestmnyre nzve gyakorlati kvetkezmnyei is lehetnek.

53

54

SQL-fejtrk

17. feladvny - Munkakzvett iroda


Larry Wade kldte el ennek a feladatnak egy vltozatt az MS-ACCESS frumra
1996 februrjban. Egy munkakzvett hivatalt vezetett, ami egy adatbzissal ren
delkezett, amelyben a munkarendelseket, a jellteket s a jelltek szakismereteit
troltk klnbz tblkban. Olyan lekrdezseket prblunk rni, amelyekkel
a munkarendelseket prostani lehetne a szakismeret alapjn a lehetsges jelltek
kel. A munkarendelsek egy rlapon, logikai kifejezss sszekapcsolva tartalmaz
zk a szksges szakismereteket. Pldul keressk meg az sszes lehetsges jell
tet gyrtsi s raktrozsi, vagy knyvelsi kpessgekkel.
Elszr is gondoljuk vgig a jelltek szakismereteit trol tbla szerkezett. Feltte
lezhetjk, hogy a jelltek szemlyes informciit egy msik tbla tartalmazza, ezzel
nem fogunk foglalkozni a feladat kapcsn.
CREATE TABLE JeloltSzakismeretek
(jelolt_d INTEGER NOT NULL,
szakismeret_kod CHAR(15) NOT NULL,
PRIMARY KEY (jelolt_id, szakismeret_kod));
INSERT INTO JeloltSzakismeretek
VALUES ((100, 'knyvels'),
(100, 'raktrozs'),
(100, 'gyrts'),
(200, 'knyvels'),
(200, 'raktrozs'),
(300, 'gyrts'),
(400, 'raktrozs'),
(400, 'gyrts'),
(500, 'knyvels'),
(500, 'gyrts'));
A kzenfekv megolds egy vgfelhasznli termkben dinamikus SQL lekrdez
sek ltrehozsa lenne minden munkamegrendels szmra:
SELECT jelolt_id, 'munka_id #212' -- lland munka-azonost
FROM JeloltSzakismeretek AS Cl, -- szakismeretenknt egy kapcsolat
JeloltSzakismeretek AS C2.
JeloltSzakismeretek AS C3
WHERE Cl.jelolt_id = C2.jelolt_id
AND Cl.jelolt_id = C3.jelolt_id
AND
-- ide kerl a munkarendels kifejezse

3. fejezet Adatkivlaszts

(Cl.szakismeret_kod = 'gyrts'
A N D C2.szakismeret_kod = 'raktrozs'
OR C3.szakismeret_kod = 'knyvels')
Egy j PowerBuilder- vagy Delphi-programoz egy hten bell elkszti azt az rla
pot, ami elvgzi ezt a feladatot. Ezutn a munka_id kdjnak neve alatt nzettbla
knt mentjk a lekrdezst. Szellemes s gyors megolds! A baj csak az, hogy ezzel
a mdszerrel hatalmas mennyisg nagyon lass lekrdezsnk lesz.
Nincs valami jobb tlet? Elfelejtettem emlteni, hogy a kezelend tevkenysgek
szma 250 ezer fltt van. Az iroda a DOT-rendszert (Dictionary of Occupational
Titles, a magyar TEOR szerinti tevkenysgkd Egyeslt llamokban hasznlt
megfelelje a ford) hasznlja a nyilvntartshoz, ami az llamokban statisztikai
clokat szolgl.

1. megolds
Ha nem kellene ennyi tevkenysggel megkzdennk, a megolds sokkal egysze
rbb lenne. Egy egsz szmot hasznlhatnnk gy, mint egy bitekbl ll karakter
lncot, s ennek minden pozcijt 0-ra vagy l-re llthatnnk a tevkenysgnek
megfelelen. Pldul:
'knyvels' = 1
raktrozs' = 2
'gyrts' = 4
stb.
1

gy a ( ' knyvels ' A N D ' gyrts ' ) brzolhat lenne a (2+4) = 6 formban.
Sajnos negyedmilli ttel esetn ez a fajta megkzelts nem mkdik.
Az els gond, ami itt addik, a keressi felttel rtelmezsvel kapcsolatos.
A gyrts s raktrozs vagy knyvels" vajon a kigyjts sorn gy rtelmezend,
hogy (gyrts A N D raktrozs) OR knyvels vagy gyrts A N D (raktrozs
OR knyvels) ? ljnk a felttelezssel, hogy az A N D mvelet elsbbsget lvez az
rtelmezskor.

55

56

SQL-fejtrk

2. megolds
Egy msik megolds az, hogy minden lekrdezst diszjunktv kanonikus forma sze
rint runk t, ami magyarul annyit jelent, hogy a keressi felttelek AND mveletek
kel sszekapcsolt karakterlncok formjban megadott kritriumok, majd a legfel
sbb szinten ezeket kapcsoljuk egymshoz az OR mvelettel.
Hozzunk ltre a munkarendelsek szmra egy msik tblt, amit adatokkal tlthe
tnk fel:
CREATE TABLE MunkaRendelesek
(munka_id INTEGER NOT NULL,
szakismeret_csoport INTEGER NOT NULL,
szakismeret_kod CHAR(15) NOT NULL,
PRIMARY KEY (munka_id, szakismeret_csoport, szakismeret_kod));
A szakismeret_csoport kd azt jelenti, hogy ezen szakismeretek mindegyike
szksges a munka elvgzshez - ezek az AND mvelettel sszekapcsolt kifejez
sek a kanonikus formban. Ezutn felttelezhetjk, hogy a munkarendelshez tar
toz sszes szakismeret_csoport az OR mvelettel kapcsoland ssze adott
munka_id esetn. Hozzuk ltre a tblt a munkarendelsek szmra, majd vegyk
fel az albbi rendelseket a kanonikus formjukban:
Munka 1 = ('raktrozs' AND 'gyrts') OR 'knyvels'
Munka 2 = ('raktrozs' AND 'gyrts')
OR ('knyvels' AND 'gyrts')
Munka 3 = 'gyrts'
Munka 4 = ('raktrozs' AND 'gyrts' AND 'knyvels')
Ez az albbi adatokat eredmnyezi a tblban:
INSERT ((1,
INTO
VALUES
(1,
(1,
(2,
(2,
(2,
(2,
(3,
(4,
(4,
(4,

MunkaRendelesek
1, 'raktrozs')
1, 'gyrts'),
2, 'knyvels'),
1, raktrozs'),
1, 'gyrts'),
2, 'knyvels ' ) ,
2, 'gyrts'),
1, 'gyrts'),
1, 'raktrozs'),
1, 'gyrts ' ),
1, 'knyvels')) ;
1

3. fejezet Adatkivlaszts

A lekrdezs a relcis oszts egy formja, amelyben a szakismeret_kod s


a szakismeret_csoport mezkbl ll kombincik az osztandk, a jelltek
szakismeretei pedig az osztk. Mivel az egyes munka_id rtkeken belli
szakismeret_csoport rtkekhez tartoz elvrsok VAGY" mvelettel kapcso
ldnak egymshoz, ha brmelyik kzlk megfelel, tallatunk van.
SELECT DISTINCT Jl.munka_id, Cl.jelolt_id
FROM MunkaRendelesek AS Jl INNER JOIN JeloltSzakismeretek AS Cl
ON Jl.szakismeret_kod = Cl.szakismeret_kod
GROUP BY jelolt_id, szakismeret_csoport, munka_id
HAVING COUNT(*) >= (SELECT COUNT(*)
FROM MunkaRendelesek AS J2
WHERE Jl.szakismeret_csoport =
J2.szakismeret_csoport
AND Jl.munka_id = J2.munka_id);

A tesztadatoknak az albbi eredmnyt kell adniuk:

munkid
1
1
1
1
2
2
2
3
3
3
3
4

100
200
400
500
100
400
500
100
300
400
500
100

A rendelsek s jelltek vltozsa esetn is maradhat a lekrdezs az eredeti for


mjban. A lekrdezst nzettblv is alakthatjuk, s gy hasznlhatjuk olyan
munkk kiszrsre, amelyekhez nincs megfelel jellt, vagy a megfelel munka
nlkli jelltek megkeressre, s gy tovbb.

57

58

SQL-fejtrk

3. megolds
Egy msfajta megolds rkezett a Smith Barney alkalmazsban ll Richrd
Romley-tl. Olyan vlasszal llt el, ami nem jr az SQL-92-ben meglv kapcsolt
allekrdezs (korrellt allekrdezs) hasznlatval:
SELECT Jl.munka_id, Cl.jelolt_id
FROM (SELECT munka_id, szakism_csop, COUNT(*)
FROM MunkaSzakismlgenyek
GROUP B Y munka_id, szakism_csop)
AS Jl(munka_id, szakism_csop, csop_szam)
CROSS JIN
(SELECT Rl.munka_id, Rl.szakism_csop, Sl.jelolt_id. COUNT(*)
FROM MunkaSzakismlgenyek AS Rl, JeloltSzakismeretek AS Sl
WHERE Rl.szakismeret_id = Sl.szakismeret_id
GROUP B Y Rl.munka_id, Rl.szakism_csop, Sl.jelolt_id)
AS Cl(munka_id, szakism_csop, jelolt_id, jelolt_szam)
WHERE Jl.munka_id = Cl.munka_id
AND Jl.szakism_csop = Cl.szakism_csop
AND Jl.csop_szam = Cl.jelolt_szam
GROUP B Y Jl.munka_id, Cl.jelolt_id;

A legtbb manapsg hasznlt SQL-megvalsts nem teszi lehetv a bels lekrde


zssel megvalstott tblakifejezst a F R O M kifejezsben, ezeket egyszeren kt Cl
s Jl nev nzettblval helyettesthetjk.
Abban sem vagyok biztos, hogy milyen sebessggel mkdnek majd a G R O U P B Y
kifejezsek a kapcsolt allekrdezsekkel sszevetve. A G R O U P B Y zradkot haszn
l tblknl nincs lehetsg az eredeti tblkon indexek hasznlatra, gy ez
a megkzelts lassabb lehet.

18. feladvny - Reklmlevl


Adva van egy tbla azon gyfelek cmeivel, akiknek reklmlevelet szeretnnk kl
deni. A tblban van egy csald nev oszlop, ami az azonos cmmel rendelkez
gyfeleket kapcsolja ssze. Erre azrt van szksg, mert szablyaink szerint hztar
tsonknt csak egy ajnlatot kldnk. A mez az gyfelek tbla azon rekordjnak
kulcsmezjt tartalmazza, amelyik szemly a tblban elsknt rendelkezik a kr
dses cmmel.

3. fejezet Adatkivlaszts

gyfelek

nev

cm

id

'Lajos'
'Jnos'
'Mrk'
'Mari'
Viktor'
'Pter'

A'B'
'C
'A*
'B'
'D'

csald
XLLL
NULL
NULL
1

NULL

3
5

Trlnnk kell azokat a sorokat, amelyekben a csald mez N U L L rtk, de


a csald ms tagjai szerepelnek a levelezlistn. A fenti pldban Lajost s Jnost
trlni kell, Mrkot s Ptert viszont nem.

1. megolds
Az els ksrlet nem sokkal tbb, mint a szveges feladatlers kzvetlen talakt
sa SQL kdd:
D E L E T E F R O M gyfelek

W H E R E csald I S N U L L -- ennek az egynnek N U L L van a csald mezjben


A N D E X I S T S -- ..s van valaki, aki...
(SELECT *

F R O M gyfelek A S Cl

W H E R E Cl.id <> id -- valaki ms


A N D Cl.cim = cim -- ugyanazon a cmen
A N D Cl.csald I S N O T N U L L ) ; -- van rtk a csald mezben

2. megolds
Ha belegondolunk, hamar rjvnk, hogy a C O U N T (*) fggvny egy adott hztar
tsra 1-nl nagyobb rtket kell hogy adjon.
D E L E T E F R O M gyfelek

W H E R E csald I S N U L L -- ennek az egynnek N U L L van a csald mezj ben


AND

(SELECT

COUNT(*)

F R O M gyfelek A S Cl
W H E R E Cl.cim = cim) > 1;

A lnyeg, hogy a C O U N T (*) sszegzs a N U L L rtk tteleket szmolja ssze.

59

60

SQL-fejtrk

19. feladvny - A legjobb rtkestk


Ez a problma 1995 mrciusban, a Database World killtson merlt fel, amikor
valaki visszajtt az IBM pavilonjtl, hogy beszljen velem. Az IBM egy DB2szakrtt lltott ki egy tblval a krdsek megvlaszolsra, de ez a problma sa
rokba szortotta. A trtnet egy rtkestket s rtkestseik sszegt tartalmaz
tblval indult, amelynek szerkezete az albbi volt:
CREATE TABLE ErtekesitesiAdatok
(krzet INTEGER NOT NULL,
ertekesito CHAR(IO) NOT NULL,
ertekesites_id INTEGER NOT NULL,
sszeg DECIMAL(5,2) NOT NULL);
Bejn a fnk s jelentst kr krzetenknt a legjobb hrom rtkestsrl s rt
kestrl. Hasznljuk ehhez az albbi adatokat:
ErtekesitesiAdatok
krzet
1
1
1
1
1
1
2
2
2
2
3
3
4
4
4
4
4

ertekesito
'Katalin'
'Zsfia'
'Lajos'
'Lajos'
'Lajos'
'Evelin'
'Attila'
'Ferenc'
'Henrik'
'Tams'
'Mt'
'Zoltn'
'Jlia'
'Barbara'
'Mria'
'Adrienn'
'Szilvia'

ertekesitesid
5
11
1
2
3
4
8
7

6
7
10
9
15

16
12
14
13

sszeg
3.00
4.00
50.00
50.00
50.00
5.00
5.00
5.00
5.00
5.00
5.00
7.00
20.00
10.00
50.00
30.00
40.00

3. fejezet Adatkivlaszts

Megolds
Sajnos a feladatmeghatrozs nhny helyen homlyos. A hrom legnagyobb rt
kestsre van szksgnk (fggetlenl attl, hogy ki ttte nylbe az zletet) vagy
a hrom legjobb rtkestre? Klnbsg van ugyanis az eredmnyben: pldul ha
az l-es krzetet vizsgljuk, Lajos lesz a hrom legnagyobb rtkests, de a hrom
legjobb rtkest Lajos, Evelin s Zsfia.
Mi a helyzet akkor, ha hromnl tbb rtkest pontosan ugyanakkora zletet k
ttt, mint a 2-es krzetben? Ha egy krzetben hromnl kevesebb rtkest dolgo
zik, ahogy a 3. krzet esetben, hagyjuk-e ki ket a jelentsbl, vagy sem? Elszr
vegyk gy, hogy a fnk a hrom legnagyobb rtkestsre kvncsi, az rtkest
szemlytl fggetlenl. A lekrdezs ebben az esetben az albbi formt ltheti:
SELECT *
FROM ErtekesitesiAdatok AS SO
WHERE sszeg IN (SELECT sszeg
FROM ErtekesitesiAdatok AS Sl
WHERE SO.krzet = Sl.krzet
AND SO.sszeg <= Sl.sszeg
HAVING COUNT(*) <= 3)
ORDER BY krzet, ertekesito, ertekesites_id, sszeg;

Az SQL-92 szerint a HAVING zradk maga egyetlen csoportknt kezeli az egsz


tblt. Ha SQL-programunk ezt nem szereti, helyettestsk az sszeg IN (SELECT
sszeg . . . rszt az sszeg >= (SELECT MIN (sszeg) . . . felttellel a SELECT
utastsban. Br, ha gy jrunk el, a H A V I N G zradk kihagyja azokat a krzeteket esetnkben a 2-est - , amelyekben csak egy eladsi sszeg szerepel:
Eredmnyek
krzet
1
1
1
3
3
4
4
4

ertekesito
'Lajos'
'Lajos'
'Lajos'
'Mt'
'Zoltn'
'Mria'
'Adrienn'
'Szilvia'

ertekesitesjd
1
2
3
10
9
12
14
13

sszeg
50.00
50.00
50.00
5.00
7.00
50.00
30.00
40.00

61

62

SQL-fejtrk

Mi a helyzet akkor, ha krzetenknt a hrom legjobb rtkestt szeretnnk meg


kapni, tekintet nlkl arra, hogy az adott krzethez hny rtkest tartozik? A le
krdezst az albbi mdon kell ehhez megvltoztatnunk:
SELECT DISTINCT krzet, ertekesito
FROM ErtekesitesiAdatok AS SO
WHERE sszeg <= (SELECT MAX(Sl.sszeg)
FROM ErtekesitesiAdatok AS Sl
WHERE SO.krzet = Sl.krzet
AND SO.sszeg <= Sl.sszeg
HAVING COUNT(DISTINCT sszeg) <= 3 ) ;
Az eredmnyek eszerint llnak el. Ne feledjk, hogy a hrom legnagyobb elads
rl van sz.
A vlasz
krzet
1
1
1
2
2
2
2
3
3
4
4
4

ertekesito
'Zsfia'
'Evelin'
'Lajos'
Attila'
'Ferenc'
'Henrik'
'Tams'
'Mt'
'Zoltn'
'Adrienn'
'Szilvia'
'Mria'

szrevehetjk, hogy a 2-es krzetben a holtverseny miatt ngy rtkest foglalja el


azonos eredmnnyel a hrom legjobbnak kijr helyet. A 3-as krzetben pedig
a verseny hinybl addik, hogy kt szemly alkotja a legjobb hrmat.

3. fejezet Adatkivlaszts

20. feladvny - Teszteredmnyek


A krdst a CompuServe Sybase-frumra 1995 mjusban juttatta el egy bizonyos
Mr. Shankar. Egy teszteredmnyeket tartalmaz tbla feldolgozsrl van sz.
A tbla egy tesztfolyamat elrehaladst kveti nyomon, rgztve a teszt egyes l
pseinek teljestsi dtumt. Az egyes lpsek nem kvetik mindig sorrendben
egymst, s az egyes tesztek klnfle lpsekkel rendelkezhetnek.
CREATE TABLE TesztEredmenyek
(sorszm INTEGER NOT NULL,
lpes INTEGER NOT NULL,
telj_datum DATE,
PRIMARY KEY (sorszm, lpes));
A feladat egy olyan lekrdezs megrsa, ami kigyjti a mg be nem fejezett teszteket.

1. megolds
n a legkzenfekvbb megoldst vlasztottam:
SELECT sorszm
FROM TesztEredmenyek AS
WHERE NOT EXISTS (SELECT
FROM
WHERE
AND

TI
*
TesztEredmenyek AS T2
TI.sorszm = T2.sorszm
T2.telj_datum IS NULL);

Ltezhet ms gondolatmenet is a krds megvlaszolsra?

2. megolds
Roy Harvey egy jobb s egyszerbb megoldst mutatott, amely teljesen mskpp
kzeltette meg a problmt:
SELECT
FROM
GROUP
HAVING

sorszm
TesztEredmenyek
BY sorszm
COUNT(*) = COUNT(telj_datum);

SQL-fejtrk

Ez is mkdik, hiszen a COUNT (*) a NULL rtk tel j_datum mezket is megsz
molja (hiszen valjban teljes sorokat szmol), mg a COUNT (tel j_datum) az
sszegzs eltt eldobja a NULL rtkeket. Ez egy jl hasznlhat fogs, amikor kt
halmazt kell sszehasonltanunk.

21. feladvny - Replgpek s piltk


Az egyik tblnk a piltkat s az ltaluk vezethet replgpeket trolja, a msik
azokat a replgpeket, amelyek a hangrban vrakoznak. Azon piltk neveit ke
ressk, akik az sszes hangrban lv gpet vezethetik.

1. megolds
A hagyomnyos vlasz a krdsre az, hogy levesszk a polcrl valamelyik tan
knyvet s fellapozzuk a relcis osztst. Chris Date, az egyik klasszikus szerz,
knyvnek tdik kiadsban egy olyan pldt kzl, amelyrl lemsolhatjuk
a megoldst. Elosztjuk a piltk kpestst trol tblt (osztand) a hangr tbl
jval (oszt), gy megkapjuk a keresett piltk neveinek listjt (hnyados).

2. megolds
Vessnk egy pillantst a kzvetlenl ezeltti feladvnyra. A Teszteredmnyek prob
lmjra alkalmazott Roy Harvey-fle fogs ebben az esetben is hasznlhat. Fon
tos, hogy a korbban tanult trkkket j problmk esetn is alkalmazni tudjuk!
Kpzeljk el, hogy minden pilta kap egy csomag matrict, amit azoknak a hangr
ban lv gpeknek az oldalra ragaszthat, amelyek vezetsre kpes. Ha a hangr
ban ll replgpek szma megegyezik a pilta ltal felhasznlt matrick szm
val, akkor a pilta minden gpet vezethet. Ez alapjn a lekrdezs az albbi:
SELECT
FROM
WHERE
GROUP
HAVING

Pilta
PilotaKepzettseg AS PS1, Hangr AS Hl
PS1.replgp = Hl.replgp
BY PS1.pilta
COUNT(PS1.replgp) = (SELECT COUNT(*) FROM Hangr);

3. fejezet Adatkivlaszts

A WHERE zradk a PilotaKepzettseg tbla replgpeit a hangrban lvkre


szkti le, mieltt a piltk szerinti csoportosts s sszegzs megtrtnne. Ha
a piltk a hangrban lv gpeknek csak egy rszhalmazra lennnek korltozva,
eldobhatnnk a WHERE zradkot s a kt C O U N T (x) kifejezs helyett hasznlhat
nnk kt C O U N T ( D I S T I N C T X ) kifejezst.

22. feladvny - Az dltulajdonos


Karn Gallaghar prblta hasznlni az albbi (MS-ACCESS-bl trt) SQL-lekrdezst egy jelents ksztsre, amely megmutatta volna, ki fizette mr ki a brleti d
jat egy dlkzpontban:
SELECT *

F R O M Brlemnyek AS Ul

LEFT O U T E R JIN
(Berlok AS T I
LEFT O U T E R JIN
Djfizetsek AS RP1
ON TI.berlo_azon = RPl.berlo_azon)
ON Ul.brlemny_azon = TI.brlemny_azon
WHERE Ul.komplexum_azon = 32
AND Ul.brlemny_azon = RP1.berlemeny_azon
AND TI.tvozott I S NULL
AND ((RP1.fizdatum >= :vizsg_datum
AND RPl.fizdatum < :vizsg_datum)
OR RPl.fizdatum IS NULL)
ORDER BY Ul.berlemeny_szam, RPl.fizdatum;

A listban minden brlemny-brl kombincira szerepelni kellett volna vagy


a Dj fizetsek rekordoknak a megfelel dtumtartomny feltntetsvel, vagy
res rekordoknak, ahol nincs megfelel Di j fizetsek rekord. Ennek ellenre
Karn nem kapott olyan res rekordokat, amelyekbl hinyoztak a Di j fizetsek
tbla adatai mindaddig, amg ki nem iktatta a Dij fizetsek tbla feltteleit. Meg
tudjuk keresni a problmt s kijavtani a lekrdezst?

SQL-fejtrk

Megolds
Gondoljunk arra, hogy mi az lland s mi a vltoz rsz az O U T E R J I N kapcsola
tokban. A brlemny-brl prokbl kell kiindulnunk: a brlemnyek mindig
ugyanazok, de a brlk jnnek-mennek, gy meg kell riznnk a LEFT O U T E R J I N
kapcsolat brlemny felli oldalt. Ha megvannak a brlemny-brl prjaink, te
gyk fel mg egyszer ugyanezt a krdst. Megllapthatjuk, hogy a djfizetsek is
jhetnek s mehetnek, mg akkor is, ha a brlemnyt valaki ppen brli.
SELECT *
FROM (Brlemnyek AS Ul
LEFT OUTER JIN Berlok AS T I
O N Ul.brlemny_azon = Tl.brlemny_azon
AND Tl.tvozott IS NULL
AND Ul.komplexum_azon = 32)
LEFT OUTER JIN Djfizetsek AS RPl
O N (Tl.berlo_azon = RPl.berlo_azon
AND Ul.berlemeny_azon = RPl.brlemny_azon)
WHERE ((RPl.fizdatum >= :vizsg_datum
AND RPl.fizdatum < :vizsg_datum)
OR RPl.fizdatum IS NULL)
ORDER BY Ul.berlemeny_szam. RPl.fizdatum;
A (Tl.berlo_azon = RPl.berlo_azon AND Ul.brlemny_azon =
RPl.brlemny_azon) felttel azt jelenti, hogy egy bizonyos brl fizetett mr
egy bizonyos brlemnyrt. Ez azokat az eseteket fedi le, amikor ugyanaz a trsa
sg a komplexum egynl tbb brlemnyt veszi brbe. Felttelezhetjk, hogy
a hivatkozsi megszortsok megvnak attl, hogy olyasvalakitl szedjnk be br
leti djat, aki nem rendelkezik egy brlemnnyel sem.

23. feladvny - Folyiratok eladsa


A krdst 1994 novemberben kldte a CompuServe Sybase-frumra Keith
McGregor. Az egyik felhasznlja az albb lthat lekrdezssel kereste fel. Hrom
napi sikertelen prblkozs ellenre nem tallta meg a helyes irnyt a felhasznl
tbaigaztsra. Cobol nyelv s kapcsolat nlkli fjlok hasznlatval krlbell har
minc perc alatt rjtt a megoldsra, de az SQL-ben nem tallt megfelel mdszert.

3. fejezet Adatkivlaszts

Adottak az albbi tblk egy folyirat terjesztsi adatbzisbl:


CREATE TABLE Cimek
(termek_id INTEGER NOT NULL PRIMARY KEY,
cim INTEGER NOT NULL,
kiads INTEGER NOT NULL,
kiadas_ev INTEGER NOT NULL);
CREATE TABLE Eladsok
(termek_id INTEGER NOT NULL,
stand_szam INTEGER NOT NULL,
net_eladott_menny INTEGER NOT NULL,
PRIMARY KEY (termek_id, ugyfel));
CREATE TABLE Ujsagosstandok
(stand_szam INTEGER NOT NULL PRIMARY KEY
stand_nev CHAR (2 0) NOT NULL);

A kvetkez jsgrust helyeket kellett kivlasztani:


1. Azokat, ahol az tlagos net_eladott_menny a 02667 s 48632 cmek
esetben egyarnt nagyobb 2-nl (ha brmelyiknl 2 vagy annl kisebb,
ne vlasszuk ki az gyfelet).
vagy
2. Ahol az tlagos net_eladott_menny a 01107 cm termknl nagyobb
5-nl (ha ez igaz, mindenkppen vlasszuk ki az gyfelet, fggetlenl az
1. felttel teljeslstl).

1. megolds
sszekapcsolva a hrom tblt hozzunk ltre egy nzettblt, gy megkapjuk azo
kat az alapvet informcikat, amik utn kutatunk. Taln ksbb mg jl jn majd
ez a nzettbla egyb jelentsek ksztsekor.
CREATE VIEW Magazinok(stand_nev, cim, net_eladott_menny)
AS SELECT Eladsok.stand_nev, Cimek.cim, net_eladott_menny
FROM Cimek, Eladsok, Ujsagosstandok
WHERE Eladsok.stand_szam = Ujsagosstandok.stand_szam
AND Cimek.termek_id = Eladsok.termek_id;

SQL-fejtrk

Ezutn megrjuk ezt a pokoli lekrdezst:


SELECT stand_nev
FROM Magazinok AS MO
GROUP BY stand_nev
HAVING -- a kt elfogad felttel
((SELECT AVG(net_eladott_menny)
FROM Magazinok AS Ml
WHERE Ml.stand_szam = MO.stand_szam
AND cim = ' 01107') > 5)
OR ((SELECT AVG(net_eladott_menny)
FROM Magazinok AS M2
WHERE M2.stand_szam = MO.stand_szam
AND cim IN ('02667', '48632')) >' 2)
AND NOT -- a kt visszautast felttel
((SELECT AVG(net_eladott_menny)
FROM Magazinok AS M3
WHERE M3.stand_szam = MO.stand_szam
AND cim IN = ' 02667 ' ) < 2
OR
(SELECT AVG(net_eladott_menny)
FROM Magazinok AS M4
WHERE M4.stand_szam = MO.stand_szam
AND cim = '48632') < 2) ;
Ha valaki egyszersti, vagy tovbbfejleszti a kifejezst, annak jutalompontot adok!
Segtsg: a DeMorgan-trvny
a
megoldsban.

hasznos lehet, s egy dntsi tbla is segthet

2. megolds
1995 prilisban Carl C. Federl, az Illinois llamban fekv Clarendon Hillsben l
fggetlen szakrt vetette fel, hogy a feladvnyra adott vlasz kt fogs alkalmaz
sval nagymrtkben leegyszersthet. Elszr egy nzettblt hoz ltre az elad
sok tlagnak szmra, majd egy EXISTS () fggvnyt vesz fel a felttelhez, amely
ben mindkt cmnek meg kell haladnia egy kszbrtket.
CREATE VIEW Magazinok (stand_szam, cim, atl_elad_menny)
AS SELECT Eladsok.stand_szam, Cimek.cim,
AVG(Eladsok.net_eladott_menny)
FROM Cimek, Ujsagosstandok, Eladsok

3. fejezet Adatkivlaszts

WHERE
AND
AND
GROUP

Cimek.termek_id = Eladsok.termek_id
Ujsagosstandok.stand_szam = Eladsok.stand_szam
Cimek.cim IN (01107, 02667, 48632)
BY Eladsok.stand_szam, Cimek.cim;

A lekrdezs most mr lnyegesen egyszersdik:


S E L E C T DISTINCT Ujsagosstandok.stand_nev
FROM Magazinok AS M0, Ujsagosstandok AS NO
WHERE NO.stand_szam = M0.stand_szam
AND ((MO.cim = 1107 AND M0.atl_elad_menny > 5)
OR (MO.cim = 2667 AND M0.atl_elad_menny > 2
AND EXISTS (SELECT *
FROM Magazinok AS Msik
WHERE Msik.cim = 48632
AND Msik.stand_szam =
M0 .stand_szam
AND Msik.atl_elad_menny > 2)));
A Sybase SQL s mg nhny adatbziskezel program rgebbi vltozataiban az
sszegzfggvnyt tartalmaz nzettbla illesztse nem a kvnt eredmnyt szolgl
tatja, ezrt ezeknl a V I E W helyett tmeneti tbla hasznlata szksges.

24. feladvny - Tzbl egy


Alan Flancman botlott ebbe a problmba valamilyen korbbi rendszertl rklt
adatokkal vgzett munkja sorn, amelyeket egy SQL adatbzisba vittek t. A tbla
gy nzett ki:
CREATE TABLE Tbla
(kulcsmezo INTEGER NOT NULL,
fl INTEGER NOT NULL,
f2 INTEGER NOT NULL,
flO INTEGER NOT NULL,
) ;
Az f l-f 10 oszlopok egy prblkozs eredmnyeit jelentik meg, amelyben egy
tmbt alaktottak t tblban val trolsra. Alan egy olyan, elegns mdon meg
rt tesztet akart ltrehozni, amelyben az f l-f 10 oszlopokat vizsgln, s azokat

69

70

SQL-fejtrk

a rekordokat jelenten meg, ahol pontosan egy nem NULL elem van az oszlopok
rtkei kztt. Vajon hny klnbz elvre pl megoldst tudunk sszelltani?
Most a vltozatossgot s nem a teljestmnyt lltjuk a kzppontba.

1. megolds
A Sybase s ms hasonl SQL-ek hasznlata esetn alkalmazhatjuk a SIGN () fgg
vnyt. A fggvny a -1, 0 vagy +1 rtkekkel tr vissza, ha a paramterknt tadott
rtk negatv, nulla vagy pozitv (ebben a sorrendben). Felttelezve, hogy a szma
ink nullk vagy annl nagyobbak, egyszeren rhatjuk a kvetkezt:
SELECT *
FROM Tbla
WHERE SIGN(fl) + SIGN(f2) + ... + SIGN(flO) = 1;

Ezzel az egyedlll, nem nulla rtkeket keressk meg. Ha negatv rtkek is el


fordulhatnak, a fggvnyeket egsztsk ki S I G N (ABS (fn)) kifejezss. A S I G N ()
fggvny az SQL-92 szerint C A S E kifejezssel is megoldhat:
CASE WHEN X > 0 THEN 1
WHEN X = 0 THEN 0
ELSE -1 END

2. megolds
Mivel a mezkkel valban egy tmbt helyettestettek, normalizlnunk kell ezt
a tblt az INF (els normlforma) szerint:
CREATE TABLE Akrmi
(kulcsmezo INTEGER NOT NULL,
i INTEGER NOT NULL CHECK (i BETWEEN 1 AND 10),
f INTEGER NOT NULL,
PRIMARY KEY (kulcsmezo, i));
Az i nven hozzadott oszlop a tmb indexe. Most mr tekinthetnk gy a krds
re, mint annak az egyednek a megkeressre, amelyik pontosan kilenc nulla rtk
f-kkel rendelkezik, ahelyett, hogy azokat kutatnnk, amelyek pontosan egy nem
nulla f-rtkkel brnak. Ez igen egyszer:

3. fejezet Adatkivlaszts

SELECT
FROM
WHERE
GROUP
HAVING

kulcsmezo
Akrmi
f =0
BY kulcsmezo
COUNT(*) = 9;

Ltrehozhatunk egy nzettblt, amely az Akrmi tbla szerkezetvel br, de egy j


optimalizl nlkl nagyon lassan fog futni a lekrdezs:
CREATE VIEW Akrmi (kulcsmezo, f)
AS SELECT kulcsmezo, fl FROM Tbla
UNION
SELECT kulcsmezo, f2 FROM Tbla
UNION
UNION
SELECT kulcsmezo, flO FROM Tbla;

3. megolds
Ennek a megoldsnak a mkdse az SQL-92 egy olyan tulajdonsgra pl, ami
nek az elrhetsge manapsg mg nem ltalnosan biztostott. Nzzk elszr
a kdot, utna a magyarzatot:
SELECT *
FROM Tbla
WHERE (fl, f2, ... , flO) IN
((fl, 0, 0, 0, 0, 0, 0, 0, 0, 0 ) ,
(0, f2, 0, 0, 0, 0, 0. 0, 0, 0 ) ,
(0, 0, 0, 0, 0, 0, 0, 0, 0, flO));,
Az SQL-92-ben a feltteles lltsokban hasznlhatunk sorltrehoz fggvnyeket.
Az IN () prediktum a kifejezst OR mvelettel sszekapcsolt egyenlsgi feltte
lekk bontja ki. Az egyenlsg sormegfelel vltozata ezutn pozcinknt haladva
hajtja vgre az ellenrzst, amelynek sorn minden megfelel rtknek egyenlnek
kell lennie.

71

72

SQL-fejtrk

4. megolds
Ha kizrlag egy mez lehet nem nulla, akkor ez annyit jelent, hogy lteznie kell
a mezk olyan kilences csoportjnak, amelyben minden rtk nulla.
SELECT
FROM
WHERE
OR

*
Tbla
(f2 + f3 + .. flO) = 0 -- az fl-et kivve
(fl + f3 + .. flO) = 0 -- az f2-t kivve

OR (fl + f2 + ., f9) - 0; -- az flO-et kivve

25. feladvny - Mrfldkvek


Ez a feladvny - egy kicsit eltr formban - Brian Youngtl rkezett. Az ltala
hasznlt rendszer azoknak a dtumoknak a sorozatt (a mrfldkveket") kveti
nyomon, amikor a vllalat egy bizonyos szolgltatsbl rtkestett. Ezekbl a d
tumokbl ll ssze egy szolgltats szlltsi menetrendje, a szlltott szolgltats t
pustl fggen. A vezetsg minden zletre szlltsi menetrendenknt egy sorban
szeretn ltni az adatokat, ami - ismerjk el - rthet kvnsg. Azt is szeretnk, ha
megadhat lenne a megjelenteni kvnt szolgltatstpus (szolg_tip).
Brian rakadt a problma egy eszesebb megoldsra egy Steve Roti ltal az SQL ki
szolglkrl rt knyvben, de az a SUM () fggvnyre s egy 1-gyel val szorzsra
pt. (Ez a Roti fi nagyon lelemnyes!) Sajnos ez az eljrs dtumoknl nem m
kdik, me a tblaszerkezet:
CREATE TABLE Menetrend
(zlet CHAR (3) NOT NULL,
rendels CHAR (10) NOT NULL,
men_sor SMALLINT NOT NULL CHECK ('men_sor IN (1,2,3),
szolg_tip CHAR (2) NOT NULL,
men_akt_datum DATE);
ahol a men_sor kdok az albbi jelentst hordozzk:
1

(1-elfogadva )
(2-teljestve')
(3='visszaigazolva')

73

3. fejezet Adatkivlaszts

Az adatok rendes krlmnyek kztt ebben a formban jelennek meg:


Menetrend
uztet
002
002
002
002
002
002

rendels
4155526710
4155526710
4155526710
4155526711
4155526711
4155526711

men_sor
1
2
3
1
2
3

szolgtip
ul
01
01
01
01
01

men_akt_daturn
'1994-07-16'
'1994-07-30'
'1994-10-01'
'1994-07-16'
'1994-07-30'
NULL

Az albbi tblzat a kvnt formtumot mutatja, amikor a szolg_tip=01 kd szol


gltatstpusra vagyunk kvncsiak:
rendels
4155526710
4155526711

elfogadva
'1994-07-16'
'1994-07-16'

teljestve
'1994-07-16'
'1994-07-16'

visszaigazolva
'1994-10-01'
NULL

1. megolds
Az SQL-92-ben a megolds bels lekrdezsek hasznlatval egyszer s gyors:
SELECT rendels,
(SELECT men_akt_datum
FROM Menetrend AS Sl
WHERE Sl.men_sor = 1
AND Sl.rendels = SO.rendels) AS elfogadva,
(SELECT men_akt_datum
FROM Menetrend AS S2
WHERE S2.men_sor = 2
AND S2.rendels = SO.rendels) AS teljestve,
(SELECT men_akt_datum
FROM Menetrend AS S3
WHERE S3.men_sor = 3
AND S3.rendels = SO.rendels) AS visszaigazolva
FROM Menetrend AS SO
WHERE szolg_tip = :vizsg_szolg_tip; -- a szolg. tpus belltsa
Az j fogsokkal az a baj, hogy a hasznlt SQL-ben esetleg nem optimalizlhatk.

SQL-fejtrk

2. megolds
Egy msik megkzelts n-sszekapcsolsokat alkalmaz, ami az SQL-89 s SQL-92
szerint egyarnt mkdik.
SELECT SO.rendels.men_akt_datum, SO.men_akt_datum,
Sl.men_akt_datum, S2.men_akt_datum, S3.men_akt_datum
FROM Menetrend AS SO, Menetrend AS Sl,
Menetrend AS S2, Menetrend AS S3
WHERE SO.szolg_tip = :vizsg_szolg_tip -- a szolg. tpus belltsa
AND SO.rendels = :vizsg_rendeles -- a rendels belltsa
AND Sl.rendels = SO.rendels AND Sl.men_sor = 1
AND S2.rendels = SO.rendels AND S2.men_sor = 2
AND S3.rendels = SO.rendels AND S3.men_sor = 3;

Ezzel a megoldssal az a gond, hogy egyes SQL-ekben az n-sszekapcsolsok na


gyon idignyesek. A korszer SQL-termkekben viszont valsznleg ez a leg
gyorsabb mdszer. Van msfajta elkpzelsnk a megoldsra?

3. megolds
Esetleg megprblhatjuk UNlON-ok s egy munkatbla hasznlatval ktdimenzis
s (fiat table) alaktani az eredeti tblt. Ennek teljestmnye rendszerint nem tl j,
de ha az eredeti tbla nagyon nagy, nha gyorsabb lehet a 2. megoldsnl.
INSERT INTO Munka (rendels, elfogadva, teljestve, visszaigazolva)
SELECT rendels, NULL, NULL, NULL
FROM Menetrend AS SO
WHERE szolg_tip = :vizsg__rendeles -- a szolg. tpus belltsa
UNION
SELECT rendels, men_akt_datum, NULL, NULL
FROM Menetrend AS Sl
WHERE Sl.men_sor = 1
AND Sl.rendels = :vizsg_rendeles
AND szolg_tip = :vizsg_szolg_tip -- a szolg. tpus belltsa
UNION
SELECT rendels, NULL, men_akt_datum, NULL
FROM Menetrend AS S2
WHERE S2.men_sor = 2
AND S2.rendels = :vizsg_rendeles
AND szolg_tip = :vizsg_szolg_tip -- a szolg. tpus belltsa

3. fejezet Adatkivlaszts

UNION
SELECT rendels, NULL, NULL, men_akt_datum
FROM Menetrend AS S3
WHERE S3.men_sor = 3
AND S3.rendels = :vizsg_rendeles
AND szolg_tip = :vizsg_szolg_tip -- a szolg. tpus belltsa

Ezt az egyszer unit esetenknt ngy INSERT utastss kell felbontani.


A vgs lekrdezs egyszeren ez lesz:
SELECT rendels, MAX(elfogadva), MAX(teljesitve).,
MAX(visszaigazolva)
FROM Munka
GROUP BY rendels;

A MAX () fggvny a csoport legnagyobb nem NULL rtkt veszi ki, ami ugyanak
kor az egyetlen nem NULL rtk a csoportban.

26. feladvny - Folyamatbrk


Ennek a feladvnynak egy vltozatt Tom Bragg kldte a CompuServe CASE-frumra. Egy folyamatbrkat (adatfolyam-diagramokat, AFD) trol tblnk van, ami
trolja az brk nevt, az egyes brkat alkot alakzatok neveit, s az adatramlst
jelz vonalakhoz tartoz cmkk szvegeit. A szerkezete a kvetkez:
CREATE TABLE AFD
(diagram CHAR(IO) NOT NULL,
alakzat CHAR(IO) NOT NULL,
adataram CHAR(IO) NOT NULL,
PRIMARY KEY (diagram, alakzat, adataram));
A krds jobb megvilgtshoz hasznljuk az albbi pldaadatokat:

AFD
diagram

alakzat

Lolyl

bemenet

Folyl
Folyl

bemenet
dnts

adataram
becslsek
vlemnyek
tnyek

75

76

SQL-fejtrk

diagram
lolyl
Folyl
Folyl
Folyl
Foly2
Foly2

alakzat
dnts
dnts
kimenet
kimenet
szmts
szmts

adataram
becslsek
vlemnyek
tnyek
becslsek
becslsek
vlemnyek

Azokat az adatramokat szeretnnk megkeresni, amelyen nem jutunk el az adott


folyamat minden egyes alakzathoz. Ez egyfajta rendszeres diagram-ellenrz elj
rs lenne, ami felkutatja a hinyz adatramokat. A feladat megknnytse rdek
ben lnk a felttelezssel, hogy minden alakzathoz el kell jutnia az sszes adat
ramnak. Ez a pldaadataink esetben azt jelenti, hogy a (Folyl, bemenet)
alakzatnl hinyzik a 'tnyek', s a (Folyl, kimenet) alakzathoz a 'vlem
nyek ' adatram nem jut el.

1. megolds
Hasznlhatnnk a kvetkez SQL-92 lekrdezst:
SELECT FI.diagram, FI.alakzat, F2.adataram
FROM (SELECT Fl.diagram, FI.alakzat FROM AFD AS FI
CROSS JIN
SELECT DISTINCT F2.adataram FROM AFD AS F2)
EXCEPT
SELECT F3.diagram, F3.alakzat, F3.adataram FROM AFD AS F3
ORDER BY Fl.diagram, Fl.alakzat, F2.adataram;
A mkds lnyege, hogy ellltjuk a diagramok s adatramok sszes lehetsges
kombincijt, majd eltvoltjuk azokat, amelyek szerepelnek a tblban. A rossz
hr az, hogy a mai SQL-termkek tbbsgben ezt valsznleg csak nzettblk
segtsgvel valsthatjuk meg.

3. fejezet Adatkivlaszts

2. megolds
Egy msik SQL-92 lekrdezs lehetne az albbi:
SELECT FI.diagram, FI.alakzat, F2.adataram
FROM (SELECT Fl.diagram, Fl.alakzat FROM AFD AS FI),
CROSS JIN
(SELECT DISTINCT F2.adataram
FROM AFD AS F2
WHERE adataram NOT IN (SELECT F3.adataram
FROM AFD AS F3
WHERE F3.diagram
Fl.diagram
AND F3.alakzat
Fl.alakzat))
ORDER BY Fl.diagram, Fl.alakzat, F2.adataram;

3. megolds
Ha az SQL-89 szerint szeretnnk a vlaszt megrni, akkor nzettblk hasznlatra
lesz szksgnk:
-- az sszes adatram ellltsa
CREATE VIEW MindenAFDAram (adataram)
AS SELECT DISTINCT adataram FROM AFD;
-- az egyes adatramok hozzrendelse az eredeti tbla soraihoz
CREATE VIEW Uj AFD (diagram, alakzat, adataram, hianyzo_adataram)
SELECT DISTINCT Fl.diagram, Fl.alakzat, Fl.adataram, F2.adataram
FROM AFD AS Fl, MindenAFDAram AS F2
WHERE Fl.adataram <> F2.adataram;
-- Lssuk az egyes (diagram, alakzat) prokat s a hinyz
-- adatramokat, ahol a hinyz adatram nem felel meg
-- a prhoz tartoz egyik adatramnak sem
SELECT DISTINCT diagram, alakzat, hianyzo_adataram
FROM UjAFD AS ND1
WHERE NOT EXISTS (SELECT *
FROM UjAFD AS ND2
WHERE ND1.diagram = ND2.diagram
AND ND1.alakzat = ND2.alakzat
AND ND1.adataram = ND2.hianyzo_adataram)
ORDER BY diagram, alakzat, hianyzo_adataram;

77

SQL-fejtrk

Taln tlzsba vittem a D I S T I N C T zradkok hasznlatt, rdemes ksrletezni vele


a jobb futsid rdekben. Mg mindig gyorsabb ez a megolds, mint ha az sszes
rekordot tvinnnk a hlzaton.

27. feladvny - Egyenl halmazok megkeresse


A halmazelmlet kt jelet klnbztet meg a rszhalmazok jellsre. Az egyik egy
oldalra fordtott patk" ( c ) , amelyet akkor hasznlunk, ha az egyik halmaz tartal
mazza a msikat; ezt valdi rszhalmaznak hvjk. A msik ugyanez a jel, alatta egy
vonallal ( c ) , ez annyit jelent, hogy az egyik halmaz vagy tartalmazza a msikat,
vagy egyenlek.
A szabvnyos SQL sohasem rendelkezett olyan mvelettel, ami kt tblt tudott
volna egymssal sszehasonltani. A relcis adatbzisokkal foglalkoz nhny
egyetemi tanknyv emleget egy bizonyos C O N T A I N S felttelt, ami a szabvnyos
SQL-89-ben nem szerepel s az SQL-92-hez sem javasoltk. Kt ilyen knyv az An
introduction to Data Base Systems (Bevezets az adatbzisrendszerekbe), Bipin C.
Desai-tl (West Publishing, 1990) s Elmasri s Navthe Fundamentals
ofDatabase
Systems (Az adatbzisrendszerek alapjai) cm knyve (Benjmin Cummings,
1989). Ez a mvelet mg ltezett az IBM els, ksrleti SQL-rendszerben,
a SYSTEM R-ben, de a ksbbi SQL-megvalstsokbl nagy futsid-ignye miatt
kihagytk. Az I N () felttel az elfordulst s nem a rszhalmazokat vizsglja. Akik
mg emlkeznek a kzpiskolai tanulmnyaikbl a halmazelmletre, azok tudjk,
hogy az elfordulst egy epszilonhoz hasonl jellel (e , olvasskor: eleme" ) jell
jk, a jobb oldalon a halmazzal, amely tartalmazza a bal oldalon ll elemet. Az
elforduls mindig egy elemre vonatkozik, ellenttben a rszhalmazzal, ami n
magban is halmazt alkot.
A Database Programming & Design magazin decemberi szmban (A Matter of
Integrity, Part II" According to Date, December 1993) megjelent, Chris Date ltal
felvetett problma egy beszlltkalkatrszek tblt hasznlt arra, hogy megkeres
se azokat a beszlltkat, akik pontosan ugyanazokat az alkatrszeket biztostjk.
Ez tulajdonkppen az egyenl halmazok keressnek problmja.

3. fejezet Adatkivlaszts

Adott a kvetkez tbla:


CREATE TABLE BeszallitoAlkatresz
(Beszall_id CHAR(2) NOT NULL,
alkatresz_id CHAR(2) NOT NULL,
PRIMARY KEY (Beszall_id, alkatresz_id));
Hnyflekppen tudunk vlaszt adni a krdsre?

1. megolds
Az egyik megkzeltsi md egy F U L L O U T E R J I N hasznlata lenne minden egyes
beszlltpron. gy elkerlne minden olyan alkatrsz, ami nincs mindketthz
rendelve, de soronknt az I N N E R J I N kapcsolatban nem szerepl beszllttl
szrmazan egy N U L L is megjelenne valamelyik oszlopban. Ezzel megtudjuk, mely
prok nem illeszkednek, de hogy melyik rszrl, azt nem. A befejez lps ezen
nem illeszked prok eltvoltsa az sszes lehetsges pr kzl.
S E L E C T SP1.Beszall_id, SP2.Beszall_id
FROM BeszallitoAlkatresz AS SP1
INNER JIN
BeszallitoAlkatresz AS SP2
EXCEPT
(SELECT DISTINCT SP1.Beszall_id, SP2.Beszall_id
FROM BeszallitoAlkatresz AS SP1
FULL OUTER JIN
BeszallitoAlkatresz AS SP2
ON SP1.alkatresz_id = SP2.alkatresz_id
AND SP1.Beszall_id < SP2.Beszall_id)
WNERE SP1.Beszall_id IS NULL
OR SP2.Beszall_id IS NULL;

2. megolds
Kt halmaz egyenlsgt gy szoks bizonytani, hogy megmutatjuk, hogy az
A halmaz tartalmazza B-t, ugyanakkor a B halmaz is tartalmazza az A-t (A c B A B
c A) > (A = B). A szabvnyos SQL-ben az lltst, hogy A rszhalmaza B-nek,
rendszerint azzal a mdszerrel ltjuk be, hogy az A halmaznak nincs olyan eleme,
ami a B-nek nem az eleme. gy az els prblkozs ltalban valami ilyesmi:

79

SQL-fejtrk

SELECT DISTINCT SP1.Beszall_id, SP2.Beszall_id


FROM BeszallitoAlkatresz AS SP1, BeszallitoAlkatresz AS SP2
WHERE SP1.Beszall_id < SP2.Beszall_id
AND SP1.alkatresz_id IN (SELECT SP22.alkatresz_id
FROM BeszallitoAlkatresz AS SP22
WHERE SP22.Beszall_id = SP2.Beszall_id)
AND SP2.alkatresz_id IN (SELECT SP11.alkatresz_id
FROM BeszallitoAlkatresz AS SP11
WHERE SPll.Beszall_id = SPl.Beszall_id);
Hopp, ez nem mkdik, mert ha kt beszlltnl akr csak egy kzs termk is
szerepel, azok mr megjelennek a felsorolsban.

3. megolds
A 2. megoldsban vzolt hagyomnyos teszt megvalstsra hasznlhatjuk az ALL
felttelt:
SELECT SPl.Beszall_id, SP2.Beszall_id
FROM BeszallitoAlkatresz AS SPl. BeszallitoAlkatresz AS SP2
WHERE SPl.Beszall_id < SP2.Beszall_id
AND NOT EXISTS (SELECT *
FROM BeszallitoAlkatresz AS SP3
WHERE SPl.Beszall_id = SP3.Beszall_id
AND SPl.alkatresz_id
NOT IN (SELECT alkatresz_id
FROM BeszallitoAlkatresz AS SP4
WHERE SP2.Beszall_id =
SP4.Beszall_id))
AND NOT EXISTS (SELECT *
FROM BeszallitoAlkatresz AS SP5
WHERE SP2.Beszall_id = SP5.Beszall_id
AND SP2.alkatresz_id
NOT IN (SELECT alkatresz_id
FROM BeszallitoAlkatresz AS SP4
WHERE SPl.Beszall_id =
SP4.Beszall_id));

3. fejezet Adatkivlaszts

4. megolds
A halmazok egyezsgi vizsglatnak hagyomnyos mdja: elszr sszekapcsol
juk a kt beszlltt a kzs rszk alapjn, kikszblve azt a helyzetet, amikor az
1. beszllt megegyezik a 2. beszlltval, gy megkapjuk a kt halmaz metszett.
Ha a metszet pontosan annyi szm prt tartalmaz, mint brmelyik halmaz elem
szma, akkor a kt halmaz egyenl.
SELECT SPl.Beszall_id, SP2.Beszall_id
FROM (SELECT Beszall_id, alkatresz_id FROM BeszallitoAlkatresz)
AS SP1
INNER JIN
(SELECT Beszall_id, alkatresz_id FROM BeszallitoAlkatresz
AS SP2
ON SP1.alkatresz_id = SP2.alkatresz_id
AND SP1.Beszall_id < SP2.Beszall_id)
GROUP BY SP1.Beszall_id, SP2.Beszall_id
HAVING (SELECT COUNT(*)
FROM BeszallitoAlkatresz AS SP3
WHERE SP3.Beszall_id = SP1.Beszall_id)
= (SELECT COUNT(*)
FROM BeszallitoAlkatresz AS SP4
WHERE SP4.Beszall_id = SP2.Beszall_id);

Ha a BeszallitoAlkatresz tblt a beszlltk kdja szerint indexeljk, akkor


a COUNT rtkeket kzvetlenl megkapjuk, s a J I N vgrehajtsa is gyorsabb.

81

Szmtsok.
Az SQL nem tartozik a szmtsi nyelvek kz. Az ANSI/ISO szerinti szabvnyos
SQL-92 csak 4 szmtsi mveletet tesz lehetv, s ezzel gyengbb teljestmnyt
nyjt, mint egy j minsg szmolgpes karra. A legtbb szoftvercg azonban
az SQL-termkeibe is bept ms fordtprogramokban megszokott fggvny
knyvtrakat, gy szksg esetn rendelkezsnkre ll a szmtsi kpessg. A je
lenlegi ANSI/ISO SQL3 ajnlsok tbb eljrst hatroznak meg a nyelv szmra.
A fejlesztk szmra nyitott a lehetsg, hogy termkeikben megvalstsk az
SQL3 ajnlsait mr azeltt is, hogy a szabvny rvnybe lpne.
A fggvnyek, amelyeket az SQL-ben sajt magunknak kell megrnunk, sszegz
s skalris fggvnyek lehetnek.
Az alapvet skalris fggvnyek - mint amilyen a szinusz vagy a koszinusz - meg
valstsnak egyik egyszer mdja egy tbla ltrehozsa, majd ebben egy keress
az adott rtkre. Ennl fantziadsabb megoldst egy kzelt rtket szmt le
krdezs vagy nzettbla jelenthet.
A bonyolultabb fggvnyek megvalstsa rendszerint tbb tblbl val rtkki
keresssel s ezeket felhasznlva tovbbi szmtsokkal jr.

84

SQL-fejtrk

28. feladvny - A szinusz fggvny kiszmtsa


Tegyk fel, hogy az ltalunk hasznlt SQL nem rendelkezik a szinusz fggvnnyel
a beptett fggvnyknyvtrban. Tudnnk-e olyan lekrdezst rni, ami kiszmt
ja egy radinban megadott szm szinuszt?

1. megolds
Egyszeren hozzunk ltre egy tblt, ami az sszes szksges rtket tartalmazza:
CREATE TABLE Szinusz
(x REL NOT NULL,
sin REAL NOT NULL);
INSERT INTO Szinusz VALUES (0.00, 0.0000);
INSERT INTO Szinusz VALUES (0.75 0.6816);
INSERT INTO Szinusz VALUES (0.76 0.6889);
stb.
A tbla feltltshez egy tblzatkezel programot clszer ignybe venni. Ezutn
mr hasznlhatjuk is az albbi bels lekrdezst a sin (: vizsgalt_ertek) kisz
mtsra:
(SELECT sin FROM Szinusz WHERE x = :vizsgalt_ertek)
Termszetesen egyes fggvnyek megvalstshoz igen nagy tblkra lenne szk
sgnk, de kisebb, korltozott tartomnyon rtelmezett fggvnyeknl j lehet ez
a megkzelts. A szinusz fggvnynl ppensggel rettenetes vlaszts, mivel egy
folytonos, minden vals szmon rtelmezett fggvnyrl van sz.

2. megolds
szrevettk, hogy ha a : vizsgalt_ertek nem szerepel az els megoldsban meg
adott tblban, akkor a lekrdezs N U L L rtket ad vissza? Ez gy nem j.

4. fejezet Szmtsok

Ha elvesznk egy rgi, szmtsokkal vagy trigonometrival foglalkoz knyvet,


megtudhatjuk, hogy az eldeink hogyan hasznltk a tblzatokat a szmolgpek
megjelense eltti korban. A kzeltsnek (interpolci) nevezett, tbb klnbz
formban ltez matematikai mdszert hasznltk.
A legknnyebb a lineris kzelts. Adott kt ismert rtke egy fggvnynek, f (a)
s f (b), s egy harmadik rtket szeretnnk megkapni, ami valahol a kett kztt
foglal helyet. Matematikai formban ezt a kvetkezkppen rhatjuk:
f(a) + (x-a) * ((f(b) - f(a))/ (b-a))
Tegyk fel pldul, hogy a sin(0,754) rtket keressk, de rtktblnk csak az
albbi rtkeket tartalmazza:
INSERT INTO Szinusz VALUES (0.75 0.6816);
INSERT INTO Szinusz VALUES (0.76 0.6889);

Behelyettestve az elz kpletbe a kvetkezt kapjuk:


0.6816 + (0.754 - 0.75) * ((0.6889 - 0.6816)/ (0.76 - 0.75)) =
.68452

Ezt betehetjk egy lekrdezsbe is:


SELECT A.sin + (:vizsgalt_ertek - A.x)
* ((B.sin - A.sin)/ (B.x - A.x))
FROM Szinusz AS A, Szinusz AS B
WHERE A.x = (SELECT MAX(x) FROM Szinusz WHERE x <=
:vizsgalt_ertek)
AND B.x = (SELECT MIN(x) FROM Szinusz WHERE x >=
:vizsgalt_ertek);
Ms kzeltsi mdszerek is lteznek, de az alapelv mindegyiknl ugyanez.

85

86

SQL-fejtrk

29. feladvny - Keressk meg a mduszt!


Felttelezem, hogy az Olvas tudja, hogy az SQL-ben az egyetlen ler statisztikai
fggvny az tlagfggvny (AVG ( ) ) . Br ez a statisztikban gyakran hasznlt fgg
vny, de kzel sem az egyetlen. Paul Dong egy olyan lekrdezssel lepett meg,
amely egy tbla valamelyik oszlopban megkeresi a leggyakrabban elfordul rt
keket. Ezt a statisztikban mdusznak nevezik. Legyen Fiz_jegyz a tbla neve,
amelyben a fizetsi utalvnyok szmait s a kifizetett sszegeket troljuk.
CREATE TABLE Fiz_jegyz
(fiz_utalvany INTEGER NOT NULL PRIMARY KEY,
kereset DECIMAL(8,2) NOT NULL,

Ltni szeretnnk a fizetsi jegyzken leggyakrabban elfordul sszeget s az el


fordulsok szmt. Hogyan lehetne ezt a lekrdezst megrni az SQL-89-ben? s az
SQL-92-ben?

1. megolds
Az SQL-89-ben a legjobb megolds taln az, ha elszr egy nzettblt hozunk ltre:
CREATE VIEW KeresetSzamok
A S SELECT COUNT(*) A S fiz_utalvany_szam
FROM Fiz_jegyz
GROUP BY kereset;
Ezutn ennek a nzettblnak a hasznlatval megkeressk a leggyakrabban el
fordul fizetssszeget:
SELECT kereset, COUNT (*)
FROM Fiz_jegyz
GROUP BY kereset
HAVING COUNT (*) = (SELECT MAX(fiz_utalvany_szam)
FROM KeresetSzamok);
Ezzel a megoldssal azonban egy nzettblt vagyunk knytelenek az adatbzisban
trolni. Ha erre ms okbl is szksgnk van, akkor a hasznlata knyelmes, ellen
kez esetben viszont feleslegesen bonyoltja az adatbzist. Jobb lenne, ha V T E W
nlkl, egy lekrdezssel megoldhat lenne ugyanez.

87

4. fejezet Szmtsok

2. megolds
Az SQL-92 lehetv teszi, hogy a nzettblt egy tblzatos bels lekrdezss ala
ktsuk t:
S E L E C T kereset,

COUNT(*)

F R O M Fiz_jegyz
G R O U P B Y kereset
HAVING

COUNT(*)

( S E L E C T MAX(fiz_utalvany_szam)
FROM

(SELECT COUNT(*)

A S fiz_utalvany_szam

F R O M Fiz_jegyz
G R O U P B Y kereset));

A legbell lv S E L E C T utastst teljesen ki kell bontani, mieltt tadnnk az ered


mnyeknt elll csoportostott tblt a kvetkez S E L E C T utastsnak. Ez az uta
sts megkeresi a M A X () rtket, s ezt az egyetlen szmot tovbbtja a legkvl l
v S E L E C T utastsnak. J eslynk van r, hogy a folyamat vgn a ltrehozott
tbla megsemmisl. Ha az optimalizl jl mkdik, akkor menti az els lekrde
zs tartalmt a vgs vlasz ellltshoz val jrafelhasznls cljbl, de erre
nem rdemes fogadnunk. Figyeljnk csak tovbb!

3. megolds
me egy jabb SQL-92 megolds, ami kicsit mskpp kezeli a N U L L rtkeket. Meg
tudjuk llaptani, mi a klnbsg?
SELECT

PO.kereset,

COUNT(*)

F R O M Fiz_Jegyz
G R O U P B Y kereset
HAVING

COUNT(*)

>= A L L (SELECT

COUNT(*)

F R O M Fiz_jegyz
G R O U P B Y kereset);

E vltozat lehetsges elnye, hogy mivel nem hasznlunk M A X () fggvnyt, na


gyobb r az eslynk, hogy az egyik S E L E C T ltal ltrehozott csoportostott tbla
megrzdik a msik szmra is. Vegyk szre, hogy a legbels S E L E C T a kvl l
vnek egy vetlete.

88

SQL-fejtrk

Prbljuk ki mindhrom megoldst, hogy lssuk, az ltalunk hasznlt SQL-ben me


lyik megolds mutat jobb teljestmnyt.

30. feladvny - tlagos vsrlsi srsg


Raymond Petersen tette fel nekem a kvetkez krdst: adott egy vsrls nev
tbla a vsrlsok dtumval s az gyfelek oszlopaival. Van-e md arra, hogy egy
SQL-lekrdezssel kiszmtsuk az egyes gyfelek vsrlsai kztt eltelt napok tla
gt? A pldban hasznljunk egy olyan tblt, amelyben felttelezzk, hogy egy
adott gyflhez egy bizonyos napon csak egy vsrls tartozhat:
CREATE TABLE Vsrls
(ugyfel CHAR(5) NOT NULL,
vasrlas_datum DATE NOT NULL,
PRIMARY KEY (ugyfel, vasarlas_datum));
Vessnk egy pillantst a jnius els hetben trtnt vsrlsokra:
Vsrls
ugyfel
'Feri'
'Mari'
'Zoli'
'Feri'
'Zoli'
'Zoli'
'Zoli'
'Zoli'
'Zoli'
'Zoli'
'Feri'
'Mari'

vasariasdatum
'1994-06-01'
'1994-06-01'
'1994-06-01'
'1994-06-02'
1994-06-02'
'1994-06-03'
'1994-06-04'
'1994-06-08'
'1994-06-06'
'1994-06-07'
'1994-06-07'
'1994-06-08'

Az adatokbl az ltszik, hogy Feri elszr egy napot vrt, majd a kvetkez vsr
lsig tt, gy addik szmra az tlagos hromnaponknti ltogats. Mari ht na
pot vrt kt vsrls kztt, ez htnapos tlagot jelent, Zoli pedig szablyosan, na
ponta teszi tisztelett.

4. fejezet Szmtsok

1. megolds
Az els sugallat, hogy ltre kellene hozni valamikppen egy rszletes nzettblt,
amely minden gyfl esetn sorban mutatja a beszerzsek kzt eltelt idt. Ebben
a megkzeltsben az els feladat, hogy egy tblba gyjtsk ssze az aktulis s
a megelz vsrlsok dtumait:
CREATE VIEW Utolso_vasarlasok (ugyfel, ez_a_datum, utolso_datum)
AS SELECT Sl.ugyfel, Sl.vasrlas_datum,
(SELECT MAX(vasarlas_datum)
FROM Vsrls AS S2
WHERE S2.vasarlas_datum < Sl.vasarlas_datum
AND S2.ugyfel = Sl.ugyfel)
FROM Vsrls AS Sl, Vsrls AS S2;
Ez a kisebbek fels hatrt keres lekrdezs: az adott gyflhez tartoz, a vizsglt
dtumnl korbbi legnagyobb dtumot keressk.
Most egy nzettblt hozunk ltre az aktulis s a megelz vsrlsok kzt eltelt
napok szmval. Egyetlen utastsban is megvalsthatnnk a kt nzettblt, de
gy nehezen olvashatv vlna s valsznleg a futtats szempontjbl sem jelen
tene hatkonyabb megoldst.
CREATE VIEW Idokoz (ugyfel, napok)
AS SELECT ugyfel, DAYS(ez_a_datum, utolso_datum)
FROM Utolso_vasarlasok;

A vgs vlasz egyetlen lekrdezs:


SELECT ugyfel, AVG(napok)
FROM Idokoz
GROUP BY ugyfel;

A kt nzettblt az AVG () fggvny paramtereknt is megadhatnnk, de ezzel


a kd teljesen olvashatatlann vlna, a futsi id pedig az egekbe szkne.

89

90

SQL-fejtrk

2. megolds
Azrt mutattam be az els megoldst, hogy megmutassam: vannak olyan esetek,
amikor tl okosak vagyunk a feladathoz. Mivel csak az egyes gyfelek vsrlsai
kzt eltelt napok tlagra vagyunk kvncsiak, nincs szksg rszletes nzettbla
ltrehozsra. Egyszeren szmoljuk ssze gyfelenknt az sszes eltelt napot,
majd az sszeget osszuk el a vsrlsok szmval:
SELECT ugyfel, (MAX(vasarlas_datum) - MIN(vasarlas_datum)) /
(COUNT(*)-l)
FROM Vsrls
GROUP BY ugyfel
HAVING COUNT(*) > 1;
A (COUNT (*) -1) kifejezs magyarzata, hogy mindig egyel kevesebb a vsrlsok
kzti idszakok szma, mint a vsrlsok, ha nem szmtjuk a mai dtum s az
utols vsrls kzti idszakot. A HAVING zradk eltvoltja az egyetlen vsrlssal
br gyfeleket. Ezek az egyszeri gyfelek is bevonhatk a SELECT utastsba, ha
a MAX (vasarlas_datum) kifejezst CURRENT_DATE fggvnyre cserljk.
Egybknt mindkt megkzeltssel kezelhetjk a napi tbb vsrlst nylbe t
gyfeleket is.

31. feladvny - Az sszes termk megvsrlsa


A Software AG bemutatott egy rtelmes SQL lekrdezs-kszt termket, amit
Esperantnak neveztek el. A billentyzet s egy vlasztklista segtsgvel a felhasz
nl egy angol nyelv mondatot alkot, amelyet a gp fordt le az eredmnyhez
szksges SQL lekrdezsek sorozatv.
A termszetes nyelven trtn lekrdezs-megfogalmazs nem j tlet, de a legtbb
korbbi ksrletnl mindig szksg volt a mkdshez a termszetes nyelv kifejez
seinek valamilyen fok elreprogramozsra. Az Esperant olyan mrtk munkt
kpes nllan is elvgezni, ami mr rdemess teszi arra, hogy foglalkozzunk vele.
Minden elzetes programozs nlkl kpes a relcis felosztsok, nzettblk s
sszetett tranzakcik ltrehozsra. A Software AG ismertetjben tbbek kztt ta
llhatunk gyfladatokat, rendelseket s rendelsi rszleteket trol tblkat is.

4. fejezet Szmtsok

CREATE TABLE gyfelek


(ugyfel_id INTEGER NOT NULL,
egyenleg DECIMAL (12,2) NOT NULL,

CREATE TABLE Rendelesek


(ugyfel_id INTEGER NOT NULL,
rendeles_id INTEGER NOT NULL,

CREATE TABLE Rend_ttelek


(rendeles_id INTEGER NOT NULL,
tetel_id INTEGER NOT NULL,
... ) ;
CREATE TABLE Termkek
(tetel_id INTEGER NOT NULL,
menny INTEGER NOT NULL,
A pldafeladat rsze volt azon gyfelek tlagos egyenlegnek meghatrozsa, akik
minden termkbl rendeltek mr, illetve azon gyfelek, akik mg nem rendelkez
nek rendelssel minden termkbl. Az Esperant elismersre mlt munkt vgzett,
de rengeteg nzettblt hozott ltre a hordozhatsg rdekben. Tudunk-e javtani
a lekrdezsen az SQL-92 j lehetsgeinek vagy a korbbi SQL-89 tulajdonsgai
nak jobb kihasznlsval?

1. megolds
A hagyomnyos megolds egy sokszorosan begyazott lekrdezs. A lekrdezst
gy lehetne htkznapi nyelvre lefordtani: Hatrozzuk meg azoknak az gyfelek
nek az tlagegyenlegt, akik esetben ltezik olyan termk, amely nem szerepel
a rendelseik kztt!".
SELECT AVG(egyenleg)
FROM gyfelek AS Cl
WHERE EXISTS
(SELECT *
FROM Termkek AS Pl
WHERE Pl.tetei
NOT IN (SELECT Dl.tetei
FROM Rendelesek AS 01, Rend_tetelek AS Dl
WHERE 01.ugyfel_id = Cl.ugyfel_id
AND 01.ugyfel_id = Dl.ugyfel_id));

91

92

SQL-fejtrk

Az sszes gyfl tlagos egyenlegnek kiszmtshoz az


E X I S T S () kittelre cserlhetjk.

EXISTS

() felttelt N O T

2. megolds
Az angliai Worcestershire-ben l Gillian Robertson egy gyes trkkel megtakar
totta az sszefgg bels lekrdezsek nhny rtegt.
SELECT AVG(egyenleg)
FROM gyfelek AS Cl
WHERE (SELECT COUNT(DISTINCT tetel_id) FROM Termkek)
<> (SELECT COUNT(DISTINCT tetel_id)
FROM Rendelesek, Rend_tetelek
WHERE Rendelesek.ugyfel_id = Cl.ugyfel_id);
Ez a lekrdezs kiszmtja azoknak az gyfeleknek az tlagos egyenlegt, akik nem
vsroltak minden termkbl, biztostva azt a felttelt, hogy az gyfelek ltal vs
rolt klnbz termkek szma nem egyezik meg a termktblban lv klnb
z termkek szmval. Nyilvnval, hogy a <> egyenlsgjelre val cserjvel azo
kat az gyfeleket kapjuk meg, akik minden forgalmazott termkbl rendeltek mr.

32. feladvny - Adszmts


Az albbi feladvnyt Richrd Romley kldte be a CompuServe-n keresztl. Ez az
adszmtssal kapcsolatos problma egyszerstett vltozata. Adzsi krzeteket
hatrozunk meg, amelyekben tbb adhatsg mkdhet. Az adzsi krzet lehet
pldul egy adott vros, ebben a vrosban pedig mkdhet vrosi, megyei s lla
mi adhatsg. Amikor egy zleti tranzakci utn adt fizetnk, a fizetett ad a v
rosi, megyei s llami ad sszegeknt ll el. Az egyes adhatsgok mindegyike
a tbbitl fggetlenl mdosthatja az ltala megllaptott ad mrtkt.
Adott az albbi tbla:
CREATE TABLE AdoKorzetHatosag
(adhatsg CHAR(IO) NOT NULL,
adokorzet CHAR(IO) NOT NULL,
PRIMARY KEY (adhatsg, adokorzet));

4. fejezet Szmtsok

Egy olyan rendszerrl van sz, amelyben minden adkrzet fizeti a megfelel ad
kat azoknak az adhatsgoknak, amelyek krzetbe beleesik:
AdoKorzetHatosag
adhatsg
adokorzet
'vrosi' 'vrosi'
'varos2' 'varos2'
Varos3'
'megyei'
'megyei'
'megye2'
'llami'
'llami'
'llami'

Varos3'
'vrosi'
'varos2'
'varos3'
'vrosi'
'varos2'
'varos3'

Ez annyit jelent, hogy a vrosi s a varos2 az llami llam megyei megyjhez


tartozik, a varos3 pedig az llami llam megye2 megyjhez. A feladathoz szk
sges msik tbla az adk mrtkt tartalmazza, az albbiak szerint:
CREATE TABLE AdoMertekek
(adhatsg CHAR(IO) NOT NULL,
hatlybalps DATE NOT NULL,
hat_adomertek DECIMAL (8,2) NOT NULL,
PRIMARY KEY (adhatsg, hatlybalps));
A tblt a kvetkez adatokkal tltjk fel:
AdoMertekek
adhatsg
'vrosi'
'vrosi'
'varos2'
'varos2'
'varos2'
'varos3'
'varos3'
'megyei'
'megyei'

hatlybalps
'1993-01-01'
'1994-01-01'
'1993-09-01'
'1994-01-01'
'1995-01-01'
'1993-01-01'
'1993-07-01'
'1993-01-01'
'1994-10-01'

hat^adomertek
1,0
1,5
1,5
2,0
2,5
1,7
1,9
2,3
2,5

93

94

SQL-fejtrk

adhatsg
'megyei'
'megye2'
'megye2'
'megye2'
'llami'
'llami'
'llami'
'llami'

hatlybalps
'1995-ui-or
'1993-01-01'
'1994-01-01'
'1995-01-01'
1993-01-01'
'1994-07-01'
'1994-07-01'
'1994-10-01'

hatadomertek
2,7
2,4
2,7
2,8
0,5
0,8
0,9
1,1

Ez a tbla az adbehajt olyan krdseinek megvlaszolsra hasznlatos, hogy


Mi a teljes adzsi arny a varos2 vrosban 1994. november 1-n?" Erre a bizonyos
krdsre a vlaszt a kvetkez mdon szmthatjuk ki:
Varos2 admrtk
Megyei admrtk
llami admrtk

= 2,0
= 2,5
=1,1

Teljes admrtk:

= 5,6

Tudnnk-e egyetlen SQL-92 lekrdezssel vlaszolni erre a krdsre?

Megolds
A legjobb, ha rszletekben oldjuk meg a krdst. Elszr is azt kell tudnunk, hogy
milyen adhatsgok tartoznak a vroshoz, amit egy bels lekrdezssel kapha
tunk meg:
(SELECT adhatsg
FROM AdoKorzetHatosag AS Al
WHERE Al.adokorzet = ' v a r o s 2 ' )

Az eredmnyhalmaz a ( ' v a r o s 2 ' , 'megyei', 'llami') lesz.


Msodszor tudnunk kell az 1994. november 1-n rvnyes admrtkeket, amihez
egy msik bels lekrdezst runk:

4. fejezet Szmtsok

(SELECT adhatsg, hat_adomertek


FROM AdoMertekek AS Rl
WHERE Rl.hatlybalps = (SELECT MAX(R2.hatlybalps)
FROM AdoMertekek AS R2
WHERE R2.hatlybalps
<= '1994-11-01'))

Most egyestsk a kt lekrdezst, vgezzk el az sszegzst, s tegyk llandin


kat egy S E L E C T listba, hogy olvashat legyen a vlasz.
A valsgban ezeket az lland rtkeket a megolds ltalnostsa cljbl param
terekk alaktanm, de most a plda kedvrt ragaszkodjunk az eredeti feladathoz:
SELECT 'varos2' AS varos, '1994-11-01' AS hatlyossg,
SUM (hat_adomertek) AS ossz_ado
FROM AdoMertekek AS Rl
WHERE Rl.hatlybalps =
(SELECT MAX (R2.hatlybalps)
FROM AdoMertekek AS R2
WHERE R2.hatlybalps <= '1994-11-01'
AND Rl.adhatsg = R2.adhatsg)
AND R2.adhatsg IN (SELECT adhatsg
FROM AdoKorzetHatosag
AS Al
WHERE Al.adokorzet
= 'varos2')
GROUP BY varos, hatlyossg;

Vrjunk csak! Tovbbi egyestsi lehetsg is van: a msodik AND felttelt a m


lyebb szint bels lekrdezsbe is mozgathatjuk:
SELECT 'varos2' AS varos, '1994-11-01' AS hatlyossg,
SUM (hat_adomertek) AS ossz_ado
FROM AdoMertekek AS Rl
WHERE Rl.hatlybalps =
(SELECT MAX (R2.hatlybalps)
FROM AdoMertekek AS R2
WHERE R2.hatlybalps <= '1994-11-01'
AND Rl.adhatsg = R2.adhatsg
AND R2.adhatsg
IN (SELECT adhatsg
FROM AdoKorzetHatosag AS Al
WHERE Al.adokorzet = 'varos2'))
GROUP BY varos, hatlyossg;

95

SQL-fejtrk

Mivel a bels lekrdezs eredmnye egy nem sszefgg llandlista, a teljest


mnynek jnak kell lennie. Amikor megnztem a WATCOM SQL futtatsi tervt, azt
tapasztaltam, hogy az Rl s R2 tblkban a keressek sorrendben zajlanak, de az
Al tbla hasznlja az elsdleges kulcs indext. Ha a AdoMertekek tblhoz indexe
ket hozunk ltre, akkor ezzel a futsi id tovbb rvidthet.
Diosdado Nebres Washington llambl kldtt egy msik lehetsges megoldst
a feladvnyra:
SELECT SUM(T2.hat_adomertek)
FROM AdoKorzetHatosag AS TI, AdoMertekek AS T2
WHERE Tl.adokorzet = 'varos2'
AND T2.adhatsg = TI.adhatsg
AND T2.hatlybalps =
(SELECT MAX(hatlybalps)
FROM AdoMertekek
WHERE adhatsg = T2.adhatsg
AND hatlybalps <= '1994-11-01');

A programoz itt elhagyta a G R O U P B Y zradkot, ami valban j lps, hiszen


enlkl a lekrdezs ugyanolyan jl - vagy mg jobban - mkdik. Tovbb a leg
mlyebb bels lekrdezst helyettestette egy AdoKorzetHatosag-AdoMertekek
kapcsolattal, ami jelentsen cskkenti a bels lekrdezs futtatsainak szmt.

33. feladvny - rtkcskkens


A feladvny egy Gerhard F. Jilovec ltal a CompuServe-re kldtt problmn ala
pul. Akkoriban egy gyr adatbzisn dolgozott, ami alapjn a gpek rtkcskke
nst szerette volna megllaptani. Erre a clra az adatbzisban ltrehozott egy g
peket trol tblt, a kvetkez szerkezettel:
CREATE TABLE Gpek
(gep CHAR(2 0) NOT NULL PRIMARY KEY,
beszerzes_datum DATE NOT NULL,
kezdeti_ertek DECIMAL (10, 2) NOT NULL,
varhato_elettartam INTEGER NOT NULL);
A tblban a beszerzes_datum jelentse az, amire kvetkeztetni lehet, az adott
gp beszerzsnek dtuma. A kezdeti_ertek mez a gp kezdeti rtke,
a varhato_elettartam pedig az eszkz vrhat lettartama napban kifejezve.

4. fejezet Szmtsok

Egy msik tblban az egyes gpek hasznlata kzben adott munkaegysg elvg
zsekor felmerl kltsgeket troljuk:
CREATE TABLE Gyrtsi_Ktg
(gep CHAR(20) NOT NULL REFERENCES Gpek,
munka_datum DATE NOT NULL,
folyamat INTEGER NOT NULL,
munka_ktg DECIMAL (6,2) NOT NULL,
PRIMARY KEY (gep, munka_datum, folyamat));
A munka_datum mez azt a dtumot trolja, amikor az adott munkafolyamat lezaj
lott a gpen, a munka_ktg pedig ennek a kltsgt. Egy hasonl tblban a terme
lsi idk arrl tjkoztatnak, hogy az egyes munkaegysgek vgrehajtshoz
mennyi idre van szksg. Ez a tbla a kvetkez mdon pl fel:
CREATE TABLE Gyartasi_Orak
(gep CHAR(20) NOT NULL REFERENCES Gpek,
munka_datum DATE NOT NULL,
folyamat INTEGER NOT NULL,
munkark DECIMAL(4,2) NOT NULL,
PRIMARY KEY (gep, munka_datum, folyamat));
A feladatunk, hogy egy clszerbb adatbzisszerkezetet javasoljunk az adatok tro
lsra. Ezutn lekrdezst kell rnunk, amely megadja egy tetszlegesen kivlasz
tott dtum s gp esetn a gp mkdtetsnek egy rra vettett tlagos kltsgt.

Megolds
Az eredeti adatbzisszerkezetben az id s a kltsgek adatait kln tblban trol
tuk, mivel az adatokat kln forrsbl kapta a rendszer, egyrszt blyegzkrtyk
rl, msrszt a szmlzsi osztlytl.
A termelsi kltsgeket (munka_ktg) s a szksges idt (munkark) egyetlen
tblban, sszevonva kellene trolni, amelyben a gp, a dtum s a munkafolya
mat szma alkotna kulcsot. Ha lehetnek olyan rk, amelyek kltsgei nem ismer
tek, vagy kltsgek, amelyekhez nem tartozik id, akkor ezekben az oszlopokban
engedlyezhetjk a N U L L rtkeket, de a matematikai mveletekre figyelni kell.
A kt tblt az albbival helyettestenm:

97

98

SQL-fejtrk

CREATE TABLE GyartasiOraKtg


(gep CHAR(20) NOT NULL REFERENCES Gpek(gep),
munka_datum DATE NOT NULL,
folyamat INTEGER NOT NULL,
munkark DECIMAL(4,2) NOT NULL,
munka_ktg DECIMAL (6,2) NOT NULL,
PRIMARY KEY (gep, munka_datum, folyamat));
Nzznk egy pldt nhny adattal. t vvel ezeltt 10 000 dollrrt vsroltunk
egy vggpet, amelyen ht munkafolyamatot tudtunk futtatni. A gp lettartama
ezer munkanap.
GyartasiOraKtg
'Vagogep'
'Vagogep'
'Vagogep'
'Vagogep'
'Vagogep'
'Vagogep'
'Vagogep'

munkadatum
'1995-07-24'
'1995-07-25'
'1995-07-25'
'1995-07-26'
'1995-07-27'
'1995-07-27'
'1995-07-28'

folyamat
101
102
103
104
105
106
107

munkark
2,5
2,5
2,0
2,5
2,5
2,5
2,5

munkaktg
123,00
125,00
110,00
125,00
120,00
120,00
125,00

Jlius 24-n, a hasznlatba vtelt kvet els napon az tlagos mkdsi kltsg
((123,00 + 10,00)/2,5) = 127,00 dollr volt rnknt. Ellenben jlius 25-n, a haszn
lat msodik napjn, az tlagos kltsg rnknt mindssze (123,00 + 125,00 +
110,00 + (2*10,00))/(2,5 + 2,5 + 2,0) = 55,43 dollr, ami figyelemre mlt cskkens.
Az els 5 v vgn a gp zemeltetsi kltsge rnknt 52,82 dollrra cskkent.
Br ms megkzeltsi mddal is megkaphatnnk a helyes eredmnyt, n inkbb
nzettblt hozok ltre az sszes kltsg s id meghatrozsra, ez felhasznlhat
egyb napi jelentsek ksztshez is.
CREATE VIEW OsszOraKtg (gep, munka_datum, napi_ktg, napi_orak)
AS SELECT gep, munka_datum, SUM(munka_ktg), SUM(munkark)
FROM GyartasiOraKtg
GROUP BY gep, munka_datum;
Tegyk fel, hogy kt dtum kzt eltelt napok szma a kt DATE tpus vltoz rtk
bl kivonssal meghatrozhat. Ezzel a lekrdezs egyszeren az albbi alakot lti:

4. fejezet Szmtsok

SELECT :vizsg_datum, Ml.gep,


(((kezdeti_ertek/varhato_elettartam) -- naponknti rtkcskkens
* (:vizsg_datum - Ml.beszerzes_datum + 1 ) ) -- eddigi lettartam
napban
-- az tlagos rnknti kltsg hozzadsa
+ (SELECT SUM(OsOK.napi_ktg)/SUM(OsOK.napi_orak)
FROM OsszOraKtg AS OsOK
WHERE Ml.gep = OsOK.gep)) AS ora_ktg
FROM Gpek AS Ml
WHERE :vizsg_datum BETWEEN Ml.beszerzes_datum AND munka_datum;
lljunk meg egy percre s gondoljuk vgig a WHERE felttelt. Ez egy szp fogs an
nak elkerlsre, hogy a szmts els felben az ora_ktg rtke negatv legyen.

34. feladvny - Tancsadi djazs


A kvetkez problmnak egy vltozatt Brian K. Buckley segtsget krve kldte
a PowerSoft Compuserve frum WATCOM SQL rszbe 1994 novemberben. H
rom tblja az albbi szerkezetekkel rendelkezett:
CREATE TABLE Szakrtk
(alk_id INTEGER NOT NULL,
nev CHAR(10) NOT NULL);
INSERT INTO Szakrtk
VALUES ((1, 'Viktor'),
(2, 'Szilvia'),
(3, 'Szilvia'));
CREATE TABLE Dijazasok
(alk_id INTEGER NOT NULL,
ervenyessegi_datum DATE NOT NULL,
dijazas DECIMAL (5,2));
INSERT INTO Dijazasok
VALUES ((1, '1990-01-01', 25.00);
(2, '1989-01-01', 15.00),
(3, '1989-01-01', 20.00),
(1, '1991-01-01', 30.00));
CREATE TABLE Ledolg_Orak
(munka_id INTEGER NOT NULL,
alk_id INTEGER NOT NULL,
munka_datum DATE NOT NULL,
raszm DECIMAL(5, 2));

SQL-fejtrk

INSERT INTO Ledolg_Orak


VALUES ((4, 1, '1990-07-01',
(4, 1, '1990-08-01',
(4, 2, '1990-07-01',
(4, 1, '1991-07-01',

3),
5),
2),
4));

Egyetlen lekrdezst szeretett volna, ami a nevek listja mellett feltntetn az egyes
munkkhoz tartoz sszes djat. A dj sszegt alkalmazottanknt llaptjuk meg,
a munkban tlttt id s a munka idpontjnak megfelel radj szorzataknt.
A pldban megadott adatok az albbi eredmnyt szolgltatnk:

Eredmnyek
'Viktor''
'Szilvia'

320.00
30.00

Viktor ((3 + 5 ra * 25 $ + 4 ra * 30 $) = 320,00 $ djazsban rszesl, mg Szilvia


dja-. (2 ra * 15 $) = 30,00 $.

1. megolds
gy gondolom, a legjobb mdszer, hogy ltrehozunk egy nzettblt, majd ez
alapjn elvgezzk az sszegzst. Ebbl az albbi V I E W addik:
CREATE VIEW radjak (alk_id, nev, munka_datum, raszm, dijazas)
AS SELECT Hl.alk_id, nev, munka_datum, raszm,
(SELECT dijazas
FROM Dijazasok AS B0
WHERE ervenyessegi_datum = (SELECT
MAX(ervenyessegi_datum)
FROM Dijazasok AS Bl
WHERE Bl.ervenyessegi_datum
< = Hl.munka_da t ura
AND B0.alk_id = Bl.alk_id
AND B0.alk_id = Hl.alk_id))
FROM Ledolg_Orak AS Hl, Szakrtk AS El
WHERE El.alk_id = Hl.alk_id;

4. fejezet Szmtsok

A jelents pedig egyszeren:


SELECT alk_id, nev, SUM(oraszm * dijazas) AS telj_dijak
FROM radjak
GROUP BY alk_id, nev;

Mivel Buckley mindent egyetlen lekrdezsben szeretett volna, a kvnt megolds


a kvetkezkppen fest:
SELECT Cl.alk_id, Cl.nev, SUM(raszm) *
(SELECT dijazas
FROM Djazsok AS BO
WHERE ervenyessegi_datum = (SELECT MAX(ervenyessegi_datum)
FROM Djazsok AS Bl
WHERE Bl.ervenyessegi_datum <=
Hl. munka_datum
AND B0.alk_id = Bl.alk_id
AND B0.alk_id = Hl.alk_id))
FROM Ledolg_Orak AS Hl, Szakrtk AS Cl
WHERE Hl.alk_id = Cl.alk_id
GROUP BY Cl.alk_id, Cl.nev;
Ez a vlasz nem magtl rtetd egy kezd SQL-programoz szmra, ezrt szl
junk rla nhny szt. Kezdjk a legbels lekrdezssel, amely minden alkalmazott
hoz megkeresi a mostani szmts eltti legutols rvnyessgi dtumot. Az egyms
ba gyazott lekrdezsek kvetkez szintje ezt az rtket hasznlja a munka
elvgzsnek idpontjban rvnyes djazs meghatrozsra, ez az oka a kls,
BO nev kapcsolat hasznlatnak. Ezt a djazsi rtket kapja meg a SUM () fggvny
s ez szorzdik ssze a ledolgozott rk szmval. Vgl a legkls lekrdezs
csoportostja az egyes alkalmazottak munkadjait, s egy vgsszeget kpez.

2. megolds
Linh Nguyen ms megoldssal rukkolt el:
SELECT nev, SUM(oraszm*dijazas)
FROM Szakrtk AS CO, Djazsok AS BO, Ledolg_Orak AS HO
WHERE C0.alk_id = B0.alk_id
AND C0.alk_id = H0.alk_id
AND ervenyessegi_datum = (SELECT MAX(ervenyessegi_datum)

101

SQL-fejtrk

FROM Djazsok AS Bl
WHERE Bl.alk_id = C0.alk_id
AND Bl.ervenyessegi_datum <=
k HO.munka_datum)
AND HO.munka_datum >= ervenyessegi_datum
GROUP BY nev;

Ennek a vltozatnak az elzvel szemben megvan az az elnye, hogy nem fgg az


SQL-92 olyan szolgltatsaitl, mint a bels lekrdezsekben hasznlhat kifejezsek,
amelyeket sok kereskedelmi termkbe nem ptettek mg be. A trtnet tanulsga,
hogy nem szabad elbznunk magunkat az j lehetsgektl elknyeztetve sem.

35. feladvny - Ignylsek


E feladvny megoldsa az SQL-92-ben villmgyorsan elllthat, viszont az SQL-89ben vagy ms adatbzisnyelvekben megrni igen krlmnyes. Tegyk fel, hogy egy
cg leltrozsi feladatt bztk rnk. Az ignyllapokbl megtudhatjuk, hogy az
adott napon milyen kszletek ramlottak be a raktrba, illetve ki onnan. A mennyi
sg olykor pozitv (tbb a bevtel), mskor negatv (tbb a kiads).
CREATE TABLE Ignylsek
(igny_datum DATE NOT NULL,
menny INTEGER NOT NULL CHECK (menny <> 0));

A feladatunk, hogy egy SQL lekrdezs oszlopaknt ellltsuk a mindenkori


egyenleget. Az eredmnynek a kvetkezkppen kell kinznie:
Raktr
igeny_datum
'1994-07-01'
'1994-07-02'
'1994-07-03'
'1994-07-04'
'1994-07-05'

menny
100
120
-150
50
-35

keszlet_menny
100
220
70
120
85

4. fejezet Szmtsok

1. megolds
Az SQL-92-ben hasznlhatunk bels lekrdezst a S E L E C T listjban, a felttel csak
az, hogy eredmnyl egyetlen rtket kell szolgltatnia (innen a skalris bels le
krdezs" elnevezs), s ha a lekrdezs eredmnye res tbla, akkor az eredmny
a N U L L rtk. Az SQL-92 szabvnynak ez az rdekes szablya lehetv teszi, hogy
egy O U T E R JIN kapcsolatot a S E L E C T utastson belli lekrdezssel valstsunk
meg. Pldul az albbi lekrdezs csak akkor mkdik, ha minden gyflnek nulla
vagy egy rendelse van:
SELECT ugyf_szam, ugyf_nev,
(SELECT rend_osszeg
FROM Rendelesek
WHERE Ugyfelek.ugyf_szam = Rendelesek.ugyf_szam)
FROM gyfelek;
Ez ugyanazt az eredmnyt adja, mint a kvetkez lekrdezs:
SELECT ugyf_szam, ugyf_nev, rend_osszeg
FROM gyfelek LEFT OUTER JIN Rendelesek
ON Ugyfelek.ugyf_szam = Rendelesek.ugyf_szam;

Feladatunkban ssze kell adnunk az sszes ignylst, amit a krdses nap eltt s
azon a napon feladtak. A lekrdezs egy begyazott n-sszekapcsols, mint a k
vetkez kdrszlet is mutatja:
SELECT igny_datum, menny,
(SELECT SUM(menny)
FROM Ignylsek AS R2
WHERE R2.igny_datum <= Rl.igny_datum) AS keszlet_menny
FROM Ignylsek AS Rl
ORDER BY igeny_datum;
Azt be kell vallani, hogy ez sokkal lassabb, mint egy eljrskzpont megolds,
ami az aktulis mennyisget az elz mennyisg alapjn egy kznl lv rendezett
fjlbl is veheti.

SQL-fejtrk

2. megolds
Jim Armes a Trident Data Systemstl az elsnl nmileg egyszerbb megoldssal
llt el:
SELECT
FROM
WHERE
GROUP

Rl.igeny_datum, Rl.menny, SUM(R2.menny) A S keszlet_menny


Ignylsek A S R2, Ignylsek A S Rl
R2.igeny_datum <= Rl.igeny_datum
B Y Rl.igeny_datum, Rl.menny

O R D E R B Y Rl.igny_datum;

A lekrdezs mkdik, de tl idignyes. Tegyk fel, hogy n darab ignylst tro


lunk a tblban. A legtbb SQL-megvalstsban a G R O U P B Y zradk rendezst von
maga utn. Mivel a G R O U P B Y minden ignylsi dtumra lefut, ez a lekrdezs egy
sort rendez az els napon, kr sort a msodik naphoz tartoz ignylseknl, s gy
tovbb, amg az utols napon rendezi az n sort.
Az els megolds S E L E C T a S E L E C T utastsban" megkzeltse nem jr rendezs
sel, mert nem szerepel benne G R O U P B Y zradk. Felttelezve, hogy az igeny_datum mez nincs indexelve, a bels lekrdezses megolds minden naphoz ugyan
azt a keresst hajtja vgre a tbln, mint a G R O U P B Y zradkot hasznl lekrdezs,
de kzben meg tudja rizni a mindenkori sszeget. gy vrhat, hogy az els meg
kzelts kevesebb keresssel jr.

36. feladvny - Ktszeres illetk


Nigel Blumenthal kldtt egy olyan megjegyzst a CompuServe-re, hogy gondjai
vannak egy PowerBuildert s WATCOM SQL-t hasznl alkalmazssal. A program
feladata egy olyan tbla adatainak feldolgozsa volt, ami egy cg alkalmazottainak
beosztsait trolta, ahol a 'V jelentette a vezett, a 'H' a hivatalnokot, a tbbivel pe
dig most nem is rdemes foglalkoznunk. Egy olyan jelentst szeretnnk ltrehozni,
ami 'M' betvel jelli, ha valaki vezet s hivatalnok is egyszerre. A forrsadatok
a kvetkezkppen nzhetnek ki:
Beosztsok
szemly
'Szab'
'Szab'

beoszts
'H'
'V

105

4. fejezet Szmtsok

szemly
'Kovcs'
'Tmr'
'Barna'

beoszts
'H'
'V
'X'

Az eredmnyhalmaz pedig:
Eredmnyek
szemly
'Szab'
'Kovcs'
'Tmr'

sszevont beoszts
'M'
'H'
'V

Nigel els ksrlete egy tmeneti tbla hasznlatt clozta, de ez tl lass lett volna.
Leonard C. Medal a krdsre egy lekrdezst kldtt, ami nzettblaknt is hasz
nlhat lenne s megkmli a felhasznlt az tmeneti tbla ltrehozsainak bonyo
dalmaitl. Az prblkozsa valami ilyesmi volt:
SELECT DISTINCT Rl.szemly,
CASE WHEN EXISTS (SELECT *
FROM Beosztsok A5 R2
WHERE R2.szemly = Rl.szemly
AND R2.beoszts IN ('V','0')) = V , ' 0 '
THEN 'M'
ELSE (SELECT R3.beoszts
FROM Beosztsok AS R3
WHERE R3.szemly = Rl.szemly
AND R3.beoszts IN ('V'/O'))
END AS osszevont_beosztas
FROM Beosztsok AS Rl
WHERE Rl. beoszts IN ('V, ' 0 ' ) ;
,

Ki tudnnk valami jobbat tallni?

SQL-fejtrk

1. megolds
Prbltam a gondolatmenetet az n-sszekapcsolsok fel terelni, pedig jobban
tennnk, ha inkbb a UNlON-t hasznl megoldst rszestennk elnyben. A ketts
beosztssal rendelkez alkalmazottak ktszer fognak megjelenni, ezrt elg, ha
egyszeren megkeressk a ktszer elfordul sorokat.
SELECT
FROM
WHERE
GROUP
HAVING
UNION
SELECT
FROM
WHERE
GROUP
HAVING

Rl.szemly, MAX(Rl.beoszts)
Beosztsok AS Rl
Rl.beoszts IN ( ' V , ' 0 ' )
BY Rl.szemly
C0UNT(*) = 1
R2.szemly, 'M'
Beosztsok AS R2
R2.beoszts IN ('V','0')
BY R2.szemly
COUNT(*) = 2 ;

Az SQL-92-ben nem okoz gondot a U N I N hasznlata egy nzettbln bell, de n


hny rgebbi SQL nem teszi ezt lehetv.

2. megolds
Az SQL-92 rendelkezik egy CASE kifejezssel is, amit gyakran hasznlhatunk rtk
cserre. Ezzel el is rkeztnk az utols, legegyszerbb formhoz:
SELECT szemly,
CASE WHEN COUNT(*) = 1
THEN beoszts
ELSE 'M' END
FROM Beosztsok
GROUP BY szemly;
A THEN beoszts zradk a vrakozsnak megfelelen mkdik, hiszen tudjuk,
hogy egy szemlyen bell" egyedi rtkkel kell rendelkeznie, mivel csak egyetlen
ilyen sor ltezik. Mgis, nhny SQL-termk esetleg csak a THEN MAX (beoszts)
kifejezst fogadja el ehelyett, mivel a beoszts nem szerepel a G R O U P BY zradk
ban, s gy formai hibt vl felfedezni a S E L E C T s a G R O U P B Y zradk kztt.

4. fejezet Szmtsok

37. feladvny - Mozg tlag


Negyedrnknt rgztett statisztikai adatokat trolunk egy rendszerben. Az gyfe
lnk rnknt szeretn ltni az adatokat, de nem az rai adatot, hanem az eltelt ra
tlagadatt. Vagyis nem arra kvncsi, mi volt a mrt adat a 00:00, 01:00 vagy 02:00
idpontokban, hanem a krds az els ngy, negyedrnknt (00:00, 00:15, 00:30,
00:45) mrt adat tlaga, majd a kvetkez ngy rtk (00:15, 00:30, 00:45, 01:00) t
laga, s gy tovbb. Ezt az rtket nevezik mozg tlagnak. Felttelezzk, hogy
a pldban szerepl tbla az albbi szerkezettel rendelkezik:
CREATE TABLE Mintk
(minta_idopont TIMESTAMP NOT NULL PRIMARY KEY,
ertek REAL NOT NULL);

1. megolds
Az egyik lehetsges mdszer, hogy egy jabb mezt hozunk ltre a mozg tlag
trolsra:
CREATE TABLE Mintk
(minta_idopont TIMESTAMP NOT NULL PRIMARY KEY;
mozgo_atlag REAL NOT NULL DEFAULT 0
ertek REAL DEFAULT 0 NOT NULL);
Ezutn egy utastssorozattal frisstjk a tblt:
UPDATE Mintk
SET mozgo_atlag
= (SELECT AVG(S1.ertek)
FROM Mintk AS Sl
WHERE Sl.minta_idopont
IN (Mintk.minta_idopont,
(Mintk.minta_idopont
- INTERVAL 15 MINUTES),
(Mintk.minta_idopont
- INTERVAL 3 0 MINUTES),
(Mintk.minta_idopont
- INTERVAL 45 MINUTES));

107

108

SQL-fejtrk

2. megolds
Nem ez az egyetlen mdja az U P D A T E utasts megrsnak. Elfordulhat, hogy
a felttelezsnk, miszerint pontosan minden 15. percben vesszk az rtkmintt,
nem mkdik; lehetnek mintavteli hibk, amelyek kvetkeztben esetleg perce
kig kihagy az idrgzt. Megprblhatjuk inkbb az egyrs idkz hasznlatt
a pontos egyezs felttelezse helyett:
U P D A T E Mintk

S E T mozgo_atlag
=

(SELECT AVG(S1.ertek)
F R O M Mintk AS Sl
W H E R E Sl.minta_idopont
BETWEEN

(Mintk.minta_idopont

- INTERVAL

1 HOUR)

A N D Mintk.minta_idopont);

3. megolds
Az utbbi U P D A T E azt sugallja, hogy ezt a felttelt egy mozg tlagot elllt lekr
dezs ltrehozsra is hasznlhatnnk:
S E L E C T Sl.minta_idopont, AVG(S2.ertek) A S elozo_ora_atlag_ertek
F R O M Mintk A S Sl, Mintk A S S2
WHERE

S2.minta_idopont
BETWEEN

(Sl.minta_idopont - I N T E R V A L

1 HOUR)

A N D Sl.minta_idopont
G R O U P B Y Sl.minta_idopont;

Vajon az j mez beszrsa vagy a lekrdezs rsa a problma jobb megkzeltsi


mdja? Kijelenthetjk, hogy a lekrdezs a jobb, mert az U P D A T E utasts hasznla
tval denormalizljuk az adatbzist. Mindamellett, ha a rgztett adatokat nem vl
toztatjuk meg s az tlag kiszmtsa tl sok erforrst ignyelne, dnthetnk
a msik mdszer hasznlata mellett.

" 7

Adatok csoportostsa
Az SQL nem jelentskszt nyelv, mgis gyakran hasznljk egyszerbb jelentsek
elksztshez, amikor valamilyen szempont szerint csoportostva kell az adatokat
megjelenteni. Ennek oka, hogy egy gyfl-kiszolgl rendszerben a kiszolgl
rendszerint sokkalta nagyobb teljestmny gp, mint az gyfl. A munknak minl
nagyobb rszt vgzi el a kiszolgl, annl jobb lesz az sszteljestmny.
Az SQL nyelv G R O U P B Y zradka nem egyszeren a S E L E C T utasts egy klnle
ges fajtja. A G R O U P B Y olyan nem res rszekre osztja az eredeti halmazt, amelyek
nem fedik t egymst. Ezutn minden rszhalmazt egyetlen sorr alakt, amely vala
melyik csoportostsi rtkbl, skalris kifejezsbl, llandbl, sszegz fgg
vnybl vagy ezekbl alkotott valamilyen kifejezsbl szrmazik. Rviden, a cso
portostott tbla egy sora magrl a csoportrl s nem pedig a tbla valamelyik
nll rekordjrl szolgltat informcit.
A legtbb programoz a problma megoldst a S E L E C T lista felvzolsval kezdi,
ezutn a F R O M zradkba berja az sszes tblt, amiben a kvnt rtkek meg
tallhatk, vgl gondolkozni kezd azon, milyen W H E R E felttellel tudn mk
dkpess tenni a lekrdezst. Egy kis tlzssal azt is mondhatjuk, hogy az SQL
nyelvn fogalmazzk meg a Mit akarok? Hol tallom meg? Hogyan jutok hozz?"
krdshrmast.

SQL-fejtrk

110

Pedig vannak olyan helyzetek, amikor a legjobb a GROUP BY zradkkal kezdeni


a feladatmegoldst, felelni a Milyen csoportokat ltunk?" krdsre, s ezutn trni
r a SELECT utastsra a Mit akarunk tudni ezekrl a csoportokrl?" krdssel.

38. feladvny - Kltsgvetsi jelents


A floridai Miamiban mkd LanSoft Inc. programozja, Mark Frontra kldtt egy
krdst a CompuServe WATCOM-frumra 1995 szeptemberben. Hrom tblban
trolta a kltsgvetsrl szl adatokat: kifizetsre vr ttelek, az ezekre fordtand
becslt sszeg s a korbban ezekre fordtott sszeg. Figyeljnk arra, hogy egy t
telhez tbb bizonylat is tartozhat s nha egy bizonylat klnbz tteleket fed le.
Ttelek
tetelazon
10
20
30
40
50

lers
'10-es
'20-as
'30-as
'40-es
'50-es

ttel'
ttel
ttel
ttel'
ttel'
1

Eddigiek
tetelazon
10
20
20
30

eddigiosszeg
300,00
325,00
100,00
525,00

Becslesek
tetelazon
10
10
20
20
40

becsutt_osszeg
300,00
50,00
325,00
110,00
25,00

biz_szam
'iiir
'2222'
'3333'
'1111'

111

5. fejezet Adatok csoportostsa

Az albbi eredmnyt szeretnnk kapni egyetlen lekrdezsbl:


Eredmnyek
tetei azon
10
20
30
40

teiras
'10-es
'20-as
'30-as
'40-es

ttel
ttel'
ttel'
ttel'

eddigossz
300,00
425,00
525,00
NULL

becs ossz
35u,uo
435,00
NULL
25,00

bizszam
'1111'
'Tbb'
'1111'
NULL

A Ttelek tbla 50-es szm ttele nem szerepel, mert sem az Eddigiek, sem pe
dig a Becslesek tblban nem volt hozz tartoz rekord. Az eddigi_ossz oszlop
a ttelhez tartoz jelenlegi sszeget, a becs_ossz pedig a becslt sszeget mutatja.

Megolds
Azt hiszem, az adatbzisszerkezet is ignyelne nmi mdostst, de skalris bels
lekrdezsekkel s egy kis csel alkalmazsval megoldhat a krds.
SELECT Il.tetel_azon, Il.leiras,
(SELECT SUM (Al.eddigi_osszeg)
FROM Eddigiek AS Al
WHERE II.tetel_azon = Al.tetel_azon) AS eddigi_ossz,
(SELECT SUM (El.becsult_osszeg)
FROM Becslesek AS El
WHERE II.tetel_azon = El.tetel_azon) AS becs_ossz,
(SELECT CASE WHEN COUNT(*) = 1
THEN MAX(biz_szam)
ELSE 'Tbb' END
FROM Eddigiek AS A2
WHERE II.tetel_azon = A2.tetel_azon
GROUP BY tetel_azon) AS biz_szam
FROM Ttelek AS II
WHERE eddigi_ossz IS NOT NULL
OR becs_OSSZ IS NOT NULL;
A trkk a skalris lekrdezsekben bjik meg. Az els kett kiszmolja a jelenlegi
teljes sszeget s a becslt vgsszeget, mintha egy GROUP BY s egy LEFT OUTER
JIN rszei lennnek.

112

SQL-fejtrk

Az utols bels lekrdezs mg cselesebb. A lekrdezs megkeresi az Eddigiek


tbla minden ttelt, ami kapcsolatban ll az adott ttellel s az eredmnytblnak
megfelelen csoportokat kpez bellk. Ha a csoport res (nincs a ttelhez ktd
bizonylat), akkor a bels lekrdezs egyetlen N U L L rtkkel tr vissza, amit meg is
jelentnk. Ha a csoporthoz egy bizonylat tartozik, akkor a CASE kifejezs ezt az
egyetlen bizonylatszmot adja vissza eredmnyl. A M A X () fggvny biztostja,
hogy skalris eredmnyt ad vissza a lekrdezs, ez az SQL-92 szabvnynak megfe
lel termkekben esetleg elhagyhat. Ha egynl tbb bizonylat lett a ttellel kap
csolatban kibocstva, akkor a C O U N T (*) egynl nagyobb, s a ' Tbb' karakterlnc
jelenik meg eredmnyknt az egyetlen bizonylatszm helyn.

39. feladvny - Halszmlls


Gyernk, menjnk horgszni! Egy vad- s halr valami olyasminek az tlagt
igyekszik megtallni, ami nincs meg neki. A feladat nem olyan klns, mint els
hallsra gondolnnk, de nem is tl egyszer. A halr a kvetkez tblban gyjti
a halakrl vett mintaadatait:
CREATE TABLE Mintk
(minta_id INTEGER NOT NULL,
hal CHAR(20) NOT NULL,
talalt_db INTEGER NOT NULL,
PRIMARY KEY (minta_id, hal));
INSERT INTO Mintk
VALUES ((1, 'frge csell', 18),
(1, 'csuka', 7 ) ,
(2, 'csuka', 4 ) ,
(2, 'ponty', 3 ) ,
(3 , 'ponty', 9 ) ,
... ) ;

CREATE TABLE MintaCsoportok


(csoport_id INTEGER NOT NULL,
leiras CHAR(20) NOT NULL,
minta_id INTEGER NOT NULL,
PRIMARY KEY (csoport_id, minta_id));
INSERT INTO MintaCsoportok
VALUES ((1, 'zavaros vz', 1 ) ,
(1, 'zavaros vz', 2 ) ,

5. fejezet Adatok csoportostsa

(2, 'friss vz', 1) ,


(2, 'friss vz', 3) ,
(2, 'friss vz', 4) ,
. . -);

Figyeljk meg, hogy a mintk sokflekppen csoportosthatk; az l-es minta egy


zavaros vzbl szrmaz hal.
A halrnek szksge van a mintacsoportokban elfordul egyes halfajok tlagos
szmra, pldul az egyes szm csoport ( ' zavaros v z ' ) l-es s 2-es mintval
rendelkezik. A megfelel paramterek hasznlatval (: vizsg_hal = ' frge
csell', : vizsg_csoport = l) meghatrozhatjuk a frge csellk szmt az l-es
csoportban:
SELECT hal, AVG(talalt_db)
FROM Mintk
WHERE minta_id IN (SELECT minta_id
FROM MintaCsoportok
WHERE csoport_id = :vizsg_csoport)
AND hal = :vizsg_hal
GROUP BY hal;
A lekrdezs a frge csellk tlagra 18-at fog adni, ami rossz eredmny. Az egyes
csoportban 2-es mintaazonostval (minta_id) nem volt frge csell, ezrt a helyes
tlag ((18 + 0)/2 = 9. Ahhoz, hogy a lekrdezs j vlaszt adjon, tbb lpsben kell
kijavtanunk a hibkat: elszr hasznljunk egy S E L E C T utastst az rintett mintk
szmnak meghatrozsra, majd egy msikat az sszeg ellltsra s ebbl kz
zel" kiszmthat az tlag. Vajon van-e lehetsg arra, hogy ezt egyetlen S E L E C T
utastssal megkapjuk?

1. megolds
A kzenfekv megolds, hogy 0-t runk minden mintaazonost al, ahol nem sze
repel az adott hal, vagyis nem engedjk meg a hinyzst. Ez a mdszer lehetv te
szi az eredeti lekrdezs hasznlatt. A hinyz sorok beszrshoz a kvetkez
utastst hasznlhatjuk:
INSERT I N T O Mintk
SELECT Ml.minta_id, M2.hal, 0
FROM Mintk AS Ml, Mintk AS M2

114

SQL-fejtrk

WHERE NOT EXISTS (SELECT *


FROM Mintk AS M3
WHERE Ml.minta_id = M3.minta_id
AND M2.hal = M3.hal);

2. megolds
Sajnos kiderl, hogy tbb mint 100 000 klnbz halfajta ltezik s a mintk sz
ma is tzezres nagysgrend. Az alkalmazott trkk tbb helyet foglalna, mint
amennyivel a halr rendelkezik. Az SQL-92 fogsait kell alkalmaznunk ahhoz, hogy
egyetlen utastssal megoldhassuk a feladatot:
SELECT hal, SUM(talalt_db)/
(SELECT COUNT(minta_id)
FROM MintaCsoportok
WHERE csoport_id = :vizsg_csoport)
FROM Mintk
WHERE hal = :vizsg_hal
GROUP BY hal;
A skalris bels lekrdezs kifejezse az tlagszmts szablyt alkalmazza, misze
rint az rtkek sszegt osztani kell az sszegben szerepl tagok szmval. Az SQL
azonban egy kicsit trkksebb.
A SUM () kifejezs az osztandban akkor ad vissza N U L L rtket, ha res halmaz az
eredmny. Ez esetben a trt (hnyados) rtke is N U L L . A skalris bels lekrdezs
az osztandban abban az esetben lehet N U L L , ha az eredmny res halmaz, hiszen
a lekrdezsben szerepl sszest fggvny eredmnye abban az esetben lehet
nulla, ha a paramterknt megadott halmaz res.
A C O U N T (<kifejezs>) sszest fggvny eredmnye egy tblnl csak akkor le
het N U L L , ha abban csak N U L L rtkek szerepelnek. Mivel mi a tblk megadsnl
ezt kizrtuk, ez biztosan nem kvetkezhet be.

3. megolds
A Kansas llambeli Anilbabu Jaiswal egy kiss eltr Oracle-megoldst kldtt,
amelynek SQL-92 vltozata gy fest:

5. fejezet Adatok csoportostsa

SELECT hal, AVG(COALESCE(talalt_db, 0))


FROM Mintk AS SA
LEFT OUTER JOIN
MintaCsoportok AS SG
ON SA.minta_id = SG.minta_id
AND SA.hal = :vizsg_hal
AND csoport_id = :vizsg_csoport
GROUP BY hal;
A C O A L E S C E () fggvny megvizsglja a paramterlistjt, s az els nem N U L L r
tket adja vissza, gy az A V G () paramtert NULL-rl nullra alaktja t. A legtbben
zavarba esnek a gondolattl, hogy egy sszegz fggvny paramtere kifejezs is
lehet, nem csak oszlopnv. A megolds msik j tlete a L E F T O U T E R J I N kapcso
lat kt oszloppal, s nem csupn eggyel trtn megvalstsa. Ez nagyon gyes,
hiszen egy tbla elsdleges kulcsa nem minden esetben egyetlen oszlopbl ll.

40. feladvny - Diplomaszerzs


Ezt a krdst Richrd S. Romley fogalmazta meg egy bonyolultabb problma logik
ja alapjn. A feladat nagyon j pldt mutat arra, mennyire mskpp kell elemez
nnk a problmkat az ANSI/ISO SQL-92 hasznlatval, mint tettk azt annak eltte.
Ltezik nhny valban gyes megolds, amelyekre nem jhetnk r addig, amg
meg nem tanuljuk az SQL-92-nek megfelel gondolkodsmdot. Az albbi megol
ds kihasznlja a szrmaztatott tblk, a CASE kifejezsek s a nem egyenlsgen
alapul OUTER JIN kapcsolatok elnyeit - mindezt egyetlen lekrdezsen bell.
A feladvnyban egyetemi hallgatk kurzusokat vesznek fel, amelyekrt krediteket
kapnak. Minden kurzus egy meghatrozott kategriba tartozik. Ezeket a kategri
kat, valamint az adott kategriban a diplomhoz szksges minimlis kreditszmot a Kategrik tbla sorolja fel. A SzerzettKreditek minden teljestett kur
zushoz tartalmaz egy bejegyzst, amelyben trolja a hallgatt, a kurzus kategrijt
s a megszerzett kreditek szmt. (Logikusabb lenne, ha a hallgatt, kurzust s
a krediteket tartalmazn, a kategrit pedig a Kurzusok tblbl vennnk, de most
egy kicsit leegyszerstettem a feladatmeghatrozst.) Az els feladatunk, hogy lt
rehozzunk egy listt azokrl a hallgatkrl, akik teljestettk a diploma feltteleit,
vagyis akik minden kategriban megszereztk a minimlisan szksges kreditszmot. Ezutn hozzunk ltre egy listt, ami a nem megfelelt hallgatkat tartalmaz
za. A legjobb megolds mgis az, ha ezt a kt listt egybeolvasztjuk, s egy olyan,
minden hallgatt tartalmaz listt hozunk lre, amelyben a megfelel oszlopba tett
jel tjkoztat arrl, hogy a krdses hallgat megfelelt-e vagy sem.

116

SQL-fejtrk

AlkalmassagiJelentes
hallgat
Robi
Jzsi
Jnos
Mari

megfelelt

nem_felelt_meg
X

X
X
X

CREATE TABLE Kategrik


(kategria CHAR(l) NOT NULL,
szuks_kreditszam INTEGER NOT NULL);
CREATE TABLE SzerzettKreditek
(hallgat CHAR(IO) NOT NULL,
kategria CHAR(l) NOT NULL,
kreditszam INTEGER NOT NULL);
INSERT INTO Kategrik
VALUES ( ( 'A, 10) ,
( 'B', 3) ,
cc- , 5 ) ) ;
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT

imo

INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO

SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek

VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES

( Jzsi , 'A' 3) ;
('Jzsi , 'A' 2) ;
('Jzsi ', 'A' 3) ;
('Jzsi ', 'A' , 3) ;
('Jzsi , 'B' 3) ;
('Jzsi '. C ' 3) ;
('Jzsi ', ' C ' 2) ;
('Jzsi' , ' C ,' 3) ;
('Robi', ' A' ,2) ;
('Robi , 'C , 2) ;
('Robi', 'A' , 12) ;
('Robi', c , 4) ;
('Jnos' , 'A' 1) ;
('Jnos' , 'B' , 100
('Mari', 'A' , 1) ;
('Mari', ' A ' ,1) ;
('Mari', 'A , 1) ;
('Mari', ' A ' ,
1) ;
('Mari', 'A' , 1) ;
('Mari', ' A' ,1) ;
('Mari', 'A' , 1) :
1

117

5. fejezet Adatok csoportostsa

INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT
INSERT

INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO
INTO

SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek
SzerzettKreditek

VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES
VALUES

( Mari',
('Mari ,
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari',
('Mari,
('Mari',
('Mari',
('Mari',
1

'A'
'A'
'A'
'A'

, 1)
, 1)
, 1)
. 1)
' s , 1)
' S ' 1)
,
' S ' 1)
,
' S ' 1)
,
'B' , 1)
'B' , 1)
' S ' 1)
,
1)
c,
'C , 1)
'C , 1)
'C , 1)
'C , 1)
C ' ,1)
'C ' ,1)
'C , 1)

;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
;
,
,

Ez a legjobb megolds, amit ki tudtam tallni:


SELECT X.hallgat,
CASE WHEN COUNT(C.kategria)
>= (SELECT COUNT(*) FROM Kategrik
THEN 'X'
ELSE ' ' END AS megfelelt,
CASE WHEN COUNT(C.kategria)
< (SELECT COUNT(*) FROM Kategrik)
THEN 'X'
ELSE ' ' END AS nem_felelt_meg
FROM (SELECT hallgat, kategria, SUM(kreditszam) AS
^ kat_kreditszam
FROM SzerzettKreditek
GROUP BY hallgat, kategria) AS X
LEFT OUTER JOIN
Kategrik AS C
ON X.kategria = C.kategria
AND X.kat_kreditszam >= C.szuks_kreditszam
GROUP BY X.hallgat;

SQL-fejtrk

Eredmnyek
hallgat
Robi
Jzsi
Jnos
Mari

megfelelt

nemfeteftmeg
X

X
X
X

Az x nev szrmaztatott tbla minden hallgat-kategria prosrl trol egy rekor


dot a hallgat, a kategria s az sszesen megszerzett kreditek feltntetsvel.
A megolds kulcsa a L E F T O U T E R J I N kapcsolatban rejtzik, amely ezt az x tblt
a kategrik tbljhoz kapcsolja a (kreditek >= szksges kreditek) felttellel.
Ezutn hallgatk szerint csoportostva az eredmnyt a COUNT(C.kategria) kife
jezs a hallgat ltal ltogatott kurzusokhoz tartoz kategrik szerint fogja meg
mutatni, hogy a hallgat hny esetben rte el a diplomhoz szksges krediteknek
legalbb a minimumt. A kapott eredmnyt sszehasonltva a kategrik szmval
kiderl, hogy a dik kaphat-e diplomt. Ezt kveten a megfelel oszlopban fel
tntethet az X jel. A lekrdezs nmkden kezeli azt az esetleg elll helyze
tet is, amikor a hallgat egy kategriban egyltaln nem vett fel kurzust.
A COUNT(C.kategria) kifejezs csak azokat a kurzusokat veszi szmtsba,
amelyekben a hallgat elrte legalbb a minimlis kvetelmnynek megfelel
kreditszmot.

41. feladvny - Modellprok


A kvetkez feladvnyt Abbott de Rham kldte 1996 szeptemberben az MSACCESS frumra. A modellprokat tartalmaz adatok pnztri nyugtkrl jutnak
a rendszerbe, az rustpontokrl val sszegyjts sorrendjben. A tbla szerkeze
te a kvetkez:
CREATE TABLE Nyugtk
(modell_a INTEGER NOT NULL,
modelljo INTEGER NOT NULL,
darabszm INTEGER NOT NULL);
A tbla a rendelsen elsknt feltntetett s a modell_a nvvel jellt modell alap
jn van rendezve, a modell_b pedig az a ttel, amelyik a rendelsen a modell_a
nevt kveti. A tbla olyan prokat is tartalmaz, ahol a kt sszetartoz rtk
ugyanaz a modell.

5. fejezet Adatok csoportostsa

Prok
modeti_a

modellj)

123 i5
12345
67890

12315
67890
12345

darabszm
12
9
5

Nhny jelentshez arra lenne szksg, hogy a prok s a fordtottjaik sszegezve,


egy ttelknt jelenjenek meg az eredmnylistban:
Prok
modella

modellj)

darabszm

12345
12345

12345
67890

12
14

Odig nincs gond, hogy a rekordokat egy n-sszekapcsolssal a fordtott prjaik


kal sszegezve jelentsk meg, viszont a kettztt rekordoktl mr nehezebb meg
szabadulni:
SELECT
AS
FROM
WHERE
AND
GROUP

S0.modell_a, SO.modell_b, SUM(SO.darabszm + Sl.darabszm)


darabszm,
Nyugtk AS SO, Nyugtk AS Sl
S0.modell_b = Sl.modell_a
S0.modell_a = Sl.modell_b
BY S0.modell_a, S0.modell_b, Sl.modell_a, Sl.modelljo;

A kapott hibs eredmny:


Eredmny
modeHa

modellj)

123
12345
67890

123-15

67890
12345

darabszm
24
14
14

Abbott egy olyan kd rst fontolgatta, ami megkeresi a fordtott prokat, hozzad
ja az rtket s trli a rekordot, mikzben az azonos modellszm modellprokat
tugorja, de mg remnykedett abban, hogy ltezik SQL-megoldsa a feladatnak.

SQL-fejtrk

1. megolds
A korbbi lekrdezs knnyen kijavthat:
SELECT S0.modell_a, SO.modelljo, SUM(SO.darabszm + Sl.darabszm)
AS darabszm,
FROM Nyugtk AS SO, Nyugtk AS Sl
WHERE S0.modell_a <= S0.modell_b
AND S0.modell_a = Sl.modelljo
AND S0.modell_b = Sl.modell_a
GROUP BY S0.modell_a, S0.modell_b, Sl.modell_a, Sl.modelljo;
Az n-sszekapcsols meglehetsen erforrs-ignyes, s igazbl nincs is r szk
sg. Nhny SQL-alkalmazsban (az ACCESS nem tartozik ezek kz) esetleg a k
vetkez formt is hasznlhatjuk:
SELECT CASE WHEN modell_a <= modell_b
THEN modell_a
ELSE modelljo END AS ml,
CASE WHEN modell_a <= modell_b
THEN modell_b
ELSE modell_a END AS m2,
SUM (darabszm)
FROM Nyugtk
GROUP BY ml, m2;

szintn szlva, ez valsznleg nem fog mkdni, mivel az ml s m2 nevek csak


a GROUP BY rvnybe lpse utn jnnek ltre, ezrt nem hasznlhatk a kifejezs
ben. Ennek ellenre sok SQL-megvalsts tmogatja ezt a formt, mivel ez els
knt a S E L E C T listt hozza ltre s csak ezutn tlti fel rtkekkel. A megfelel
SQL-92 vltozat tblzatos bels lekrdezssel oldja meg a krdst:
SELECT sl, m2, SUM(darabszm)
FROM (SELECT CASE WHEN modell_a <= modelljo
THEN modell_a
ELSE modelljo END,
CASE WHEN modell_a <= modelljo
THEN modelljo
ELSE modell_a END,
darabszm
FROM Nyugtk) AS Jelents (sl, IT\2 , darabszm)
GROUP BY ml, m2;

5. fejezet Adatok csoportostsa

2. megolds
Ha az SQL-89 szablyai szerint szeretnnk ugyanezt megvalstani, elszr egy n
zettblba kellene tennnk a tblzatos bels lekrdezs eredmnyt, majd ezt
a viEW-t hasznlhatnnk egy msik lekrdezsben. Igazbl ugyanarrl a kdrl
van sz, csak kln lpsekre bontottuk a megoldst, aminek megvan az az el
nye, hogy a nzettbla ms jelentsekben is felhasznlhat.
CREATE VIEW Jelents (ml, m2, darabszm)
AS SELECT CASE WHEN modell_a <= modell_b
THEN modell_a
ELSE modell_b END,
CASE WHEN modell_a <= modelljo
THEN modell_b
ELSE modell_a END,
darabszm
FROM Nyugtk;
SELECT ml, m2, SUM(darabszm)
FROM Jelents
GROUP BY ml, m2;

3. megolds
A legjobb mdszer mgis az, ha az adatbzist vltoztatjuk meg a lekrdezs eltt
oly mdon, hogy a modell_a a kt kdszm kzl mindig a kisebb rtkt tartal
mazza. Ez igen egyszeren megvalsthat:
UPDATE Nyugtk
SET modell_a = modell_b,
modell_b = modell_a
WHERE modell_a > modell_b;
Ugyanezt egy kiold (trigger) hasznlatval s beszrssal is megvalsthattuk volna.

42.feladvny - Pepperoni
Egy klasszikus szmolsi feladat jelentst rni a korbbi szmlzsok idbeli rendj
rl. Szerepeljen a pldnkban a Pepperoni bartai nev klub, amelynek hitelkrty
jt elfogadjuk a pizzerinkban. J lenne, ha mindig tudnnk, hogy a klubtagok ren
delkeznek-e mg megfelel kerettel a hitelkrtys vsrlshoz.

122

SQL-fejtrk

Rendelkezsnkre ll a szmlzsokat tartalmaz tbla, amelyben a tagazonost


szmot (ugyf_azon), a szmlzs dtumt (szamla_datum) s a szmlzott ssze
get (sszeg) troljuk. Ezek egyike sem kulcs a tblban, vagyis egy gyflnek tbb
bejegyzse is lehet klnbz dtumokkal s sszegekkel. Egy rgimdi naplzfjlrl van sz, amelyet SQL tblaknt trolnak.
Egy olyan listra lenne szksgnk, ami gyfelenknt megmutatja a bizonyos id
tartamokon bell kifizetett ttelek sszegt. Az idtartamok a pillanatnyi dtumhoz
igazodnak a kvetkezk szerint: 0-30 nappal korbbi, 31-60 nappal korbbi, 61-90
nappal korbbi s a 90 napnl rgebbi szmlk. Az ilyen, a szmlzsok idbeli el
oszlst mutat jelentst jl tudjuk hasznlni annak vizsglatra, hogy a Pepperoni
bartai programnak milyen hatsa van az zletre.

1. megolds
Lekrdezst rhatunk egyenknt a megfelel idtartamokra, majd a UNION mvelet
tel egyesthetjk ezeket:
1

SELECT ugyf_azon, '0-30 nap = AS idtartam, SUM (sszeg)


FROM PepperoniBaratai
WHERE szamla_datum BETWEEN CURRENT_DATE
AND (CURRENT_DATE - INTERVAL 30 DAY)
GROUP BY ugyf_azon
UNION
SELECT ugyf_azon, '31-60 nap = ' AS idtartam, SUM (sszeg)
FROM PepperoniBaratai
WHERE szamla_datum BETWEEN (CURRENT_DATE - INTERVAL 31 DAY)
AND (CURRENT_DATE - INTERVAL 60 DAY)
GROUP BY ugyf_azon
UNION
SELECT ugyf_azon, '61-90 nap = ' AS idtartam, SUM(sszeg)
FROM PepperoniBaratai
WHERE szamla_datum BETWEEN (CURRENT_DATE - INTERVAL 61 DAY)
AND (CURRENT_DATE - INTERVAL 90 DAY)
GROUP BY ugyf_azon
UNION
SELECT ugyf_azon, '90+ nap = ' AS idtartam, SUM(sszeg)
FROM PepperoniBaratai
WHERE szamla_datum < CURRENT_DATE - INTERVAL 90 DAY) GROUP BY
ugyf_azon
ORDER BY ugyf_azon, idtartam;

5. fejezet Adatok csoportostsa

A msodik oszlopban szveges tpusknt kezelve az idtartamok oszlopt a ren


dezs az egyes gyfelek rekordjain bell egyszerbb, mivel a karakterlncok id
rendi sorrendben vannak. A lekrdezs mkdik, de gyorsnak nemigen nevezhet.
Kell lennie jobb megoldsnak is az SQL-92-ben.

2. megolds
Ne hasznljunk U N I N mveleteket, ha helyette rendelkezsnkre l a CASE.
A UNiON-ok hasznlatval tbbszr vgig kell vizsglnunk a tblt, mg a CASE kife
jezssel csak egyszer.
SELECT ugyf_azon,
SUM(CASE WHEN szamla_datum
BETWEEN CURRENT_TIMESTAMP
AND CURRENT_TIMESTAMP
THEN sszeg ELSE 0.00) AS
SUM(CASE WHEN szamla_datum
BETWEEN CURRENT_TIMESTAMP
AND CURRENT_TIMESTAMP
THEN sszeg ELSE 0.00) AS
SUM(CASE WHEN szamla_datum
BETWEEN CURRENT_TIMESTAMP
AND CURRENT_TIMESTAMP
THEN sszeg ELSE 0.00) AS
SUM(CASE WHEN szamla_datum
< CURRENT TIMESTAMP THEN sszeg ELSE 0.00) AS
FROM PepperoniBaratai;

- INTERVAL 3 0 DAYS
idotartaml,
- INTERVAL 60 DAYS
- INTERVAL 31 DAYS
idotartam2,
- INTERVAL 9 0 DAYS
- INTERVAL 61 DAYS
idotartam3,
INTERVAL 91 DAYS
idotartam4

A CASE kifejezs hasznlata a UNiON-ok helyett egy gyakran alkalmazhat fogs.

43. feladvny - ruhzi akcik


A minap nyertk el egy nagyruhz rtkestsi igazgati llst. Adatbzisunkban
kt tbla ll rendelkezsnkre: az egyik az ruhz ltal szervezett rtkestsi akci
k naptra, a msik pedig az akcik alatti rtkestsek adatait tartalmazza. Ahhoz,
hogy az alkalmazottak megfelel jutalomban rszeslhessenek, egy jelentsre len
ne szksgnk arrl, hogy az egyes akcik alatt melyik elad kttte sszessg
ben a legnagyobb zletet.

123

SQL-fejtrk

CREATE TABLE Akcik


(akcio CHAR (25) NOT NULL PRIMARY KEY,
kezdo_datum DATE NOT NULL,
bef_datum DATE NOT NULL);
Akcik
akcio
'Szeni 1 n g > e s Ics/uv.il'
'Nemzeti klykpard
'Karcsony hete'
1

kezdodatum
'1995-02-01'
'1995-11-Or
'1995-12-18'

CREATE TABLE Ertekesitesek


(elad CHAR (15) NOT NULL,
ert_datum DATE NOT NULL,
sszeg DECIMAL (8,2) NOT NULL);
A tblban trolt adatok:
rtkestsek
elad
'Szilvi'
'Szilvi'
'Szilvi'
'Szilvi'
'Szilvi'
'Szilvi'
'Lajos'
'Lajos'
'Lajos'
'Lajos'
'Lajos'
'Lajos'
'Lajos'
'Lajos'
'Laura'
'Laura'
'Laura'
'Laura'
'Laura'
'Laura'
'Laura'

ert_datum

sszeg

'1995-U2-IJ3'

250,99
250,99
100,00
400,98
400,98
4,98
257,50
110,00
300,98

'1995-02-03'
'1995-02-04'
'1995-02-05'
'1995-12-19'
'1995-12-20'
'1995-02-03'
'1995-02-04'
'1995-02-05'
1995-ii-or
'1995-11-01'
'1995-11-02'
'1995-12-23*
'1995-12-24'
'1995-11-01'
'1995-11-01'
'1995-11-03'
'1995-12-18'
'1995-12-19'
'1995-12-20'
'1995-01-04'

150,25
325,00
150,75
257,50
25,50
325,00
999,75
150,00
800,00
100,00
200,00
100,00

bef datum
'1995-U2-07'
'1995-11-07'
'1995-12-25'

5. fejezet Adatok csoportostsa

1. megolds
Az albbi lekrdezs lnyege, hogy kiszmtjuk az egyes eladk ltal az adott akci
ban eladott rtk sszegt, majd ezen csoportokbl kivlasztjuk a legnagyobb
sszeget. Az els rsz egy viszonylag egyszer JOIN s GROUP BY zradkokat al
kalmaz utasts.
A legnagyobb sszeg megkeresse az egyes csoportokban mr ignyel egy trkks
HAVING zradkot. Nzzk elszr a megoldst, utna a magyarzatot:
SELECT El.elad, Al.akci, SUM(El.sszeg) AS ossz_eladas
FROM Ertekesitesek AS El Akcik AS Al
WHERE El.ert_datum BETWEEN Al.kezdo_datum AND Al.bef_datum
GROUP BY El.elad, Al.akci
HAVING SUM(sszeg) >=
ALL (SELECT SUM(sszeg)
FROM Ertekesitesek AS E2
WHERE E2.elado <> El.elado
AND E2.ert_datum
BETWEEN (SELECT kezdo_datum
FROM Akcik AS A2
WHERE A2.akcio = Al.akcio)
AND (SELECT bef_datum
FROM Akcik AS P3
WHERE P3.akcio = Al.akcio)
GROUP BY E2.elado);
Azt szeretnnk, ha a kivlasztott elad akcin belli eladsainak sszege egyenl
vagy nagyobb lenne az sszes tbbi elad adott akcihoz tartoz rtkestsi
sszegnl. Az E2 . elado <> El. elado felttel kizrja a tbbi eladt az sszegkp
zs lekrdezsbl. A BETWEEN felttelben lv kifejezs bels lekrdezsei bizto
stjk, hogy j dtumokat hasznlunk az akcihoz.
A lekrdezs javtsn elmlkedve az els gondolat az lehet, hogy a BETWEEN felt
tel bels lekrdezseit kzvetlen kls hivatkozsra cserljk:
SELECT El.elado, Al.akcio, SUM(El.sszeg) AS ossz_eladas
FROM Ertekesitesek AS El Akcik AS Al
WHERE El.ert_datum BETWEEN Al.kezdo_datum AND Al.bef_datum
GROUP BY El.elado, Al.akcio
HAVING SUM(sszeg) >=
ALL (SELECT SUM(sszeg)

125

126

SQL-fejtrk

FROM rtkestsek AS E2
WHERE E2.elad <> El.elad
AND E2.ert_datum -- Hiba !!
BETWEEN Al.kezdo_datum AND Al.bef_datum
GROUP BY E2.elad);

Ez azonban nem fog mkdni. Ha kitalljuk, mirt, akkor valban jl ismerjk az


SQL-t. Prbljuk meg, mieltt tovbb olvasnnk!

2. megolds
A GROUP BY El. elad, Al. akci zradk olyan csoportostott tblt hozott ltre,
ami csak sszegz fggvnyeket s kt csoportostott oszlopot tartalmaz. A F R O M
zradkban ltrejv eredeti munkatblt megszntettk, a csoportostott munka
tbla vltotta fel, gy a kezdo_datum s a bef_datum szintn megsznik ltezni
ezen a ponton.
Jllehet a bels lekrdezs kifejezse mkdik, mert az Al kls tblra hivatko
zik, ami mg mindig elrhet, hiszen a lekrdezs a legbels lekrdezsbl dolgo
zik, nem pedig a csoportostott tblbl. Ha a teljestmnyre kt ismert, lland d
tum kztt lennnk kvncsiak, a msodik lekrdezs is mkdne, ha az
Al. kezdo_datum s az Al. bef_datum rtkeket kicserlnnk ezekre az lland
dtumrtkekre.
Rovatom kt olvasja kldtt erre a problmra javtott megoldsokat: Richrd
Romley s J. D. McDonald. Mindketten megemltik, hogy ha felttelezzk, hogy az
akcik nem fedik t egymst, akkor az Akcik tbla csak kulcsmezkkel rendelke
zik, gy az (akci, statdate, bef_datum) kifejezs hasznlata a GROUP BY zra
dkban nem vltoztatja meg a csoportostst. Ezzel a kezdo_datum s a bef_datum elrhetv vlik a HAVING zradk szmra, vagyis:
SELECT El.elad, Al.akci, SUM(El.sszeg) AS ossz_eladas
FROM rtkestsek AS El Akcik AS Al
WHERE El.ert_datum BETWEEN Al.kezdo_datum AND Al.bef_datum
GROUP BY Al.akci, Al.kezdo_datum, Al.bef_datum. El.elad
HAVING SUM(El.sszeg) >
ALL (SELECT SUM(E2.sszeg)
FROM rtkestsek AS E2

5. fejezet Adatok csoportostsa

WHERE E2.ert_datum BETWEEN Al.kezdo_datum AND


Al.bef_datum
AND E2.elad <> El.elad
GROUP BY E2.elad);
Egy msik lehetsg, hogy a felttelek szmt cskkentjk a HAVING zradkban
azzal, hogy nhny egyszer vltoztatst hajtunk vgre a bels lekrdezsben:

HAVING SUM(El.sszeg) >=


ALL (SELECT SUM(E2.sszeg)
FROM rtkestsek AS E2,
WHERE E2.ert_datum BETWEEN Al.kezdo_datum AND Al.bef_datum
GROUP BY E2.elado);
Nem tudom, hogy a kett kztt teljestmnyben van-e valamilyen eltrs, de
a msodik tlthatbb megolds. Hogy jobban lssuk az adatokat, me az egyes ak
cikban elrt, eladk szerinti eredmny:
'Szent Frigyes fesztivl'
'Szih i
luu2.% ' . \ ) cites
'Lajos'
668.48
'Laura'
0.00

'Nemzeti klykpard'
'Szilvi'
0.00
'Lajos'
626.00
'Laura'
1474.75 <== Nyertes

'Karcsony
'.viivi'
'Lajos'
'Laura'

hete'
io5.yo
283.00
1100.00 <== Nyertes

127

128

SQL-fejtrk

44. feladvny - lhelyszakaszok


A feladvny eredeti vltozata a georgiai egyetemen dolgoz Bob Stearns-tl szr
mazik, s egy kiszolglknt mkd szmtgpen trtn helyfoglalssal foglal
kozik. n tfogalmaztam a feladatot gy, hogy a tma egy sznhz els sorban l
v lhelyek lefoglalsa legyen. A foglals tartalmazza a tulajdonos nevt, valamint
a lefoglalt szakasz kezd s befejez helynek sorszmt. A foglals szablya, hogy
a szakaszok nem lehetnek tfedsben. A foglalsokat tartalmaz tbla szerkezete
a kvetkez:
CREATE TABLE Foglalasok
(tulajdonos CHAR(IO) NOT NULL PRIMARY KEY,
kezd INTEGER NOT NULL,
befejez INTEGER NOT NULL);
Foglalasok
tulajdonos
'Tercsi'
Tercsi'
'Kata'
'Klra'

kezd
1
6
10
16

befejez
4
7
15
18

A feladat egy olyan megszorts ltrehozsa a tblhoz, ami biztostja, hogy a fel
vett foglalsok soha ne lehessenek fedsben. A krds bonyolultabb, mint els r
nzsre gondolnnk, hacsak nem lpsenknt oldjuk meg a problmt.

1. megolds
Az els vltozat egy C H E C K () zradk alkalmazsa lehetne. Esetleg felrajzolhatunk
nhny vzlatot azzal kapcsolatosan, hogy az lsszakaszok hnyflekppen fed
hetik egymst, s valami ilyesmit kaphatunk eredmnyknt:
C R E A T E TABLE Foglalasok
(tulajdonos CHAR(IO) NOT NULL PRIMARY KEY,
kezd INTEGER NOT NULL,
befejez INTEGER NOT NULL,
CONSTRAINT Nincs_atfeds
CHECK (NOT EXISTS

5. fejezet Adatok csoportostsa

( S E L E C T Rl.tulajdonos

FROM Foglalasok AS Rl
W H E R E kezd BETWEEN Rl.kezd AND Rl.befejez
OR befejez BETWEEN Rl.kezd AND Rl.befejezo)));
Ez egy gyes fogs, amellyel a ktszer szerepl kezd s befejez lhelyek
ugyangy kiszrhetk, mint az tfedsek.

2. megolds
Kt gond addik. Az SQL-92 Intermediate szintje nem engedi meg a CHECK () zra
dkban lev bels lekrdezseket, de a Full SQL-92 igen, gy elfordulhat, hogy az
ltalunk hasznlt alkalmazssal ez a megolds nem fog mkdni. Ha krbejrjuk
a problmt, esetleg azt tapasztalhatjuk, hogy nem tudjuk felvenni az els helyfog
lalst. A P R I M A R Y K E Y s a N O T N U L L megszortsokkal nem lehet baj. Ezzel szem
ben amikor az rtelmez a CHECK () megszortshoz r, a bels lekrdezs alapjn
Rl nven egy msolatot kszt az res Foglalasok tblrl.
Innentl kezdve a dolog kezd egy kicsit zavaross vlni. Az Rl. kezd s
Rl .befejez rtkek a C R E A T E T A B L E utasts szerint nem lehetnek N U L L rtk
ek, viszont az Rl res, vagyis mgis N U L L rtkek lesznek a B E T W E E N felttelben.
J eslynk van r, hogy ez az nmagra mutat hivatkozs megzavarja a megszo
rts-ellenrzt, s nem fogunk tudni els sort felvinni a tblba. A legbiztonsgo
sabb eljrs, ha meghatrozzuk a tblt, felvesznk egy vagy kt sort, majd ezutn
adjuk hozz a Nincs_atfeds megszortst.

45. feladvny - Csoportok felbontsa


Sissy Kubu egy klns krdst kldtt szmomra a CompuServe-n keresztl.
Az albbi tblval addtak gondjai:
CREATE TABLE Raktrkszlet
(aru CHAR(IO) NOT NULL PRIMARY KEY,
darabszm INTEGER NOT NULL CHECK (darabszm >= 0));

129

130

SQL-fejtrk

Fel szerette volna bontani a tblt, ami annyit jelent, hogy olyan nzettblt vagy
valdi tblt akart ltrehozni, ami kln sorral rendelkezik minden alkotelem sz
mra. Pldul az eredeti tblban szerepl ( CD-ROM' , 3) rekordhoz 3 kln sort
szeretett volna, amelyek mindegyikben a ( C D - R O M ', 1) rtkek szerepelnek. Mi
eltt felmerlne a krds, sietek kijelenteni: fogalmam sincs rla, hogy erre mirt
volt szksg - tekintsk egyszeren gyakorlfeladatnak.
1

Mivel az SQL nem rendelkezik UN-COUNT (*) ... DE-GROUP BY . . mveletekkel,


ezt vagy kzzel", vagy valamilyen programozsi nyelvvel valsthatjuk meg. Beval
lom, n is valamilyen jelentskszt programmal s nem SQL lekrdezssel olda
nm meg a feladatot, mivel az eredmny nem egy kulccsal rendelkez tbla.
Eljrskzpont mdszerrel az lenne a kzenfekv megolds, hogy SQL-nk prog
ramozsi nyelvn runk egy eljrst, amely vesz egy sort a Raktrkszlet tbl
bl, majd a msodik tblba berja az ru nevt, s ezt annyiszor ismtli, amennyi
a darabszm mez rtke. A vgrehajts meglehetsen lass lesz, mivel (SELECT
SUM(darabszm) F R O M Raktrkszlet) szm sorbeszrsra lesz szksg a mun
katblba.
Van esetleg jobb megolds?

1. megolds
llandan hangslyozom, hogy ha az SQL-ben programozunk, akkor halmazokban
kell gondolkodnunk. A legjobb megolds megtallsnak egyik mdja az ismtelt
sorbeszrsok alkalmazsa az eredeti tbln, ami a szmtstechnika hskorban
osztsi s szorzsi mveletekre hasznlt orosz paraszt algoritmus" elvre pl. Ha
kvncsiak vagyunk r, matematikatrtnettel vagy szmtstudomnnyal foglalkoz
knyvekben megtallhatjuk ezt a binris aritmetikra pl, az assembly nyelvek
ben balra, illetve jobbra lptet mveletekkel megvalsthat programozsi eljrst.
Mg mindig szksgnk lesz nmi negyedik genercis kdolsi tudsra, de ez
mr nem lesz olyan vszes. Elszr is hozzunk ltre kt munkatblt, egyet pedig
a vgeredmny szmra:
CREATE TABLE Munkatablal
(aru CHAR(IO) NOT NULL,
darabszm INTEGER NOT NULL);

5. fejezet Adatok csoportostsa

CREATE TABLE Munkatabla2


(aru CHAR(IO) NOT NULL,
darabszm INTEGER NOT NULL);
CREATE TABLE Eredmny
(aru CHAR(IO) NOT NULL,
darabszm INTEGER NOT NULL);
Most kezdjk el ttlteni azokat az rukat a vlasztblba, amelyek csak egy pl
dnyban fordulnak el a raktrban:
INSERT INTO Eredmny
SELECT * FROM Raktrkszlet WHERE darabszm = 1;

Most a maradk adatot tegyk t az els munkatblba:


INSERT INTO Munkatablal
SELECT * FROM Raktrkszlet WHERE darabszm > 1;

Az albbi kdrszlet a msodik munkatblt tlti fel azokkal a rekordprokkal,


amelyek mindegyike fele akkora (vagy fele akkora plusz egy) darabszmmal ren
delkezik, mint az els munkatblban lv:
INSERT INTO Munkatabla2
SELECT aru, FLOOR(darabszam/2.0)
FROM Munkatablal
WHERE darabszm > 1
UNION ALL
SELECT aru, CEILING(darabszam/2.0)
FROM Munkatablal
WHERE darabszm > 1;

A F L O O R (x) s C E I L I N G (x) fggvnyek a legnagyobb x-nl kisebb, illetve legki


sebb x-nl nagyobb egsz rtket adjk vissza. Ha az ltalunk hasznlt SQL nem
rendelkezik ezekkel, knnyen megvalsthatjuk kerekt s csonkol fggvnyek
kel. Fontos tovbb, hogy (2 . 0)-val s ne 2-vel osszunk, mivel ez a lps biztostja
a decimlis eredmnyt.
Most takartsuk be azokat a sorokat, amelyek a msodik munkatblban egyes da
rabszmmal rendelkeznek, majd rtsk ki az els munkatblt:

SQL-fejtrk

INSERT INTO Eredmny


SELECT *
FROM Munkatabla2
WHERE darabszm = 1;
DELETE FROM Munkatablal;

Cserljk fel a kt munkatbla szerept, majd ismteljk addig az eljrst, amg


mindkt munkatbla ki nem rl. A mdszer egyszer, tiszta eljrskzpont k
dolst ignyel. rdekes dolog vgigkvetni, ahogy az eredmny tblrl tblra
vndorolva ltrejn. Akr animcis filmknt is elkpzelhetjk ezeket a szemlltet
tblzatokat:
1. lps: Tltsk fel az els munkatblt, kivlogatva minden olyan termket, amely
mr egy darabszmmal rendelkezik:
Munkatablal
aru
'Alla
'Bta'
'Delta'
'Gamma'
1

Munkatabla2
darabszm
4
5
16
50

aru

darabszm

Az ( ' Epszilon' , 1) sor azonnal az Eredmny tblba kerl.


2. lps: Felezzk a darabszmot s kettzzk meg a sorokat a msodik munkatb
lban. Az els munkatblt kirtjk.
Munkatablal
aru

Munkatabla2
darabszm

aru
Alia
'Alfa'
'Bta'
'Bta'
'Delta'
'Delta'
'Gamma'
'Gamma'
1

darabszm
2
2
2
3
8
8
25
25

5. fejezet Adatok csoportostsa

3- lps: Ismteljk addig a folyamatot, amg mindkt munkatbla kirl.


Munkatablal

aru

Munkatabla2

'Alfa'
'Alfa'
'Alfa'
'Alfa'
'Bta'
'Bta'
'Bta'
'Bta'
'Bta'

darabszm
aru
darabszm
1
1
1
1
1 Az 'Alfa' s a 'Bta' kszen llnak a begyjtsre
1
1
1
1

'Delta'
'Delta'
'Delta'
'Delta'
'Gamma'
'Gamma'
'Gamma'
'Gamma'

4
4
4
4
12
12
13
13

A teljes kirts ideje ltalban igen rvid. Ugyangy a sorok msolsnak idig
nye (ezek a lemezen ltalban fizikai blokkok, amelyeket teljes tmeneti trknt
mozgathatunk) egyik tblbl a msikba sokkal kisebb, mint egyenknt beszrni
a sorokat.
A kdot gy is megrhattuk volna, hogy az eredmny az egyik munkatblban ke
letkezzen, de ez a megkzelts lehetv teszi, hogy a munkatblk egyre kisebbek
legyenek, gy jobb az tmeneti tr kihasznltsga. Az algoritmus ( S E L E C T
SUM (darabszm) FROM Raktrkszlet) szm sort trol s (log2 ( ( S E L E C T
MAX (darabszm) FROM Raktrkszlet) ) +1) mozgatst vgez, ami mindkt
szempontbl j eredmnynek mondhat.

133

SQL-fejtrk

2. megolds
Pter Lawrence a CompuServe-n egy msik megoldst javasolt erre a feladvnyra.
Elszr hozzunk ltre egy tblt, ami az sszes egsz szmot tartalmazza, legalbb
a darabszmok legnagyobb rtkig (n):
CREATE TABLE Darabszam_tabla (darabszam_ssz INTEGER NOT NULL);
INSERT INTO Darabszam_tabla VALUES ( (1) , (2) , ..., (n));
A lekrdezs pedig legyen a kvetkez:
SELECT
FROM
WHERE
AND

aru, 1 AS darabszm, darabszam_ssz


Raktrkszlet AS II, Darabszam_tabla AS TI
II.darabszm >= TI.darabszam_ssz
TI.darabszam_ssz >= 1;

Eredmnyknt ezt kell kapnunk:

Eredmnyek

aru
'CD-ROM'
'CD-ROM'
'CD-ROM'
'Nyomtat'
'Nyomtat'

jgPfeszam

rabszam_ssz

1
1

1
2

1
1
1

3
1
2

Pter nagyon hasznosnak tallta a fenti Darabszam_tabla tblkhoz hasonl t


meneti tblk hasznlatt, s gyakran hasznlja ket dtum-id tartomnyok ese
tn is. Jl hasznlhat hasonl lekrdezsekhez, pldul azoknak az rknak
a meghatrozsra, amikor valaki az irodban tartzkodott, ha csak az rkezs s
tvozs idpontjt troljuk.
Szeretem ezt a megoldst, s minden bizonnyal gyorsabb is, mint az n bonyolult
adattologatsom a kt tbla kztt. Nem Lawrence volt az egyetlen a DBMS rova
tom olvasi kzl, aki e mdszer hasznlatval jutott el a megoldsig.
Az egyetlen vltoztatsom az lenne, hogy biztostanm a Darabszam_tabla mre
tt, s mindenekeltt elsdleges kulcsot adnk meg a meghatrozsban:
CREATE TEMPORARY TABLE Darabszam_tabla
(darabszam_ssz INTEGER NOT NULL PRIMARY KEY);

5. fejezet Adatok csoportostsa

Mary Attenborough szintn ezzel a megoldssal rukkolt el, aminek az rdekess


ge a mdszer jszersgben rejlett, ahogy ellltotta az egymst kvet szmokat
tartalmaz tblt. Tulajdonkppen az orosz paraszt algoritmus egy msik vltozatt
hasznlta. Vinicius Mello tovbbfejlesztette az eljrst a munkatbla ellltshoz
hasznlt matematikai mveletek tovbbi egyszerstsvel. gy a kvetkez kd
addott megoldsknt:
BEGIN
DECLARE maxszam INTEGER NOT NULL;
DECLARE n-szer INTEGER NOT NULL;
DECLARE nvekmny INTEGER NOT NULL;
INSERT INTO Darabszam_tabla VALUES ((1),

(2));

/* a Darabszam_tabla sorainak szma minden ciklusban megkettzdik


*/
SET maxszam = (SELECT MAX(darabszm) FROM Raktrkszlet);
SET nvekmny = 2;
WHILE nvekmny < maxszam
DO BEGIN
INSERT INTO Darabszam_tabla
SELECT darabszam_ssz + nvekmny FROM Darabszam_tabla;
SET nvekmny = nvekmny + nvekmny;
END;
END;
Ha gy dntnk, hogy a Darabszam_tabla tblt ne egy eljrssal tltsk fel, ha
nem legyen lland tbla, ltnunk kell majd, hogy a munka egy rszt elvgeztk,
de azok az ruk, amelyek darabszma nagyobb a legnagyobb darabszam_ssz r
tknl, vltozatlanul megmaradnak:
SELECT
FROM
WHERE
AND

aru, 1 AS darabszm, darabszam_ssz


Raktrkszlet AS II, Darabszam_tabla AS TI
II.darabszm >= TI.darabszam_ssz
TI.darabszam_ssz BETWEEN 1 AND MAX(II.darabszm);

Egy msik megkzelts alapjn a lekrdezs nem hajtdik vgre, ha van olyan da
rabszmunk, amely nagyobb a darabszam_ssz maximumnl:
SELECT aru, 1 AS darabszm, darabszam_ssz
FROM Raktrkszlet AS II, Darabszam_tabla AS TI

135

136

SQL-fejtrk

WHERE II.darabszm >= TI.darabszam_ssz


AND (SELECT MAX(12.darabszm) FROM Raktrkszlet AS 12)
<= (SELECT MAX(T2.darabszam_ssz) FROM Darabszam_tabla AS T2) ;
Mint tudjuk, a bels lekrdezsek kifejezsei a lekrdezs letciklusa alatt lland
nak tekinthetk, gy az optimalizl vgrehajthatja ket, a Darabszam_tabla ese
tben egy indexre ugrssal, a Raktrkszlet esetben pedig egy tblapsztzssal, mivel ehhez nem valszn, hogy van darabszm alap index.
Egy tovbbi mdja lehet a szmsorozat ellltsnak, ha emlksznk arra, hogyan
mkdik az arab szmok helyirtk-rendszere. 000-tl 999-ig az albbi kddal llt
hatunk el egy listt:
CREATE TABLE Szmjegyek (i INTEGER NOT NULL);
INSERT INTO Szmjegyek
VALUES ((0). (1). (2). (3), (4), (5), (6), (7), (8),
INSERT
SELECT
FROM
WHERE

(9));

INTO Darabszam_tabla
((Dl.i) + (10 * DIO.i) + (100 * D100.)) AS ssz
Szmjegyek AS Dl, Szmjegyek AS D10, Szmjegyek AS Dl00
ssz <= (SELECT MAX(darabszam) FROM Raktrkszlet);

Termszetesen az eljrs brmilyen mret tblra kiterjeszthet. Figyelem! Ne


hasznljuk azt a mdszert, hogy a FROM zradkhoz a biztonsg kedvrt egysze
ren mg hozzrjuk a Szmjegyek tbla jabb msolatait! Brmennyire is a ha
tkonysgra trekszik valaki, olyan okos nem lehet, hogy tudja, mikor kell a le
krdezsnek lellnia, gy az sszes kifejezsbl add szmot ltre fogja hozni.
Hasznljunk egy lekrdezst a darabszmok legnagyobb rtknek meghatrozs
ra, s csak annyi msolatot hozzunk ltre a Szmjegyek tblbl, ami lefedi ezt az
rtket.

46. feladvny - Eszkzgyr


Olyan termelsi jelentst kapunk az egyes termelsi kzpontokbl, amelyen szere
pel a dtum, a kzpont kdja, s azon termkek darabszma, amelyeket az aznap
a kzpontba kldtt egyes nyersanyagadagokbl ellltottak. A tblaszerkezet
a kvetkez:
CREATE TABLE Termeles
(term_kozpont INTEGER NOT NULL,
term_datum DATE NOT NULL,

5. fejezet Adatok csoportostsa

adag_sorszam INTEGER NOT NULL,


eszkoz_db INTEGER NOT NULL,
PRIMARY KEY (term_kozpont, term_datum, adag_sorszam)) ;
Bejn a fnk s egy olyan kimutatst kr, amelybl adagonknt kiderl az adott
napon s termelsi kzpontban gyrtott eszkzk tlagos szma. Erre azt vlaszol
juk, hogy semmi gond, s megoldjuk a feladatot. A kvetkez napon megint bejn
a fnk, s ugyanezeket az adatokat kri, de hrom egyforma nagysg adagcso
portra osztva. Az eredmny felosztsnak ez a fajtja gyakran elfordul a termelsi
statisztikkban.
Ms szavakkal, ha februr 24-n a 42-es szm kzpontban 21 adag nyersanyagot
dolgoztak fel, akkor a jelentsnk megmutatja az els ht adagbl kszlt eszk
zk tlagos szmt, majd a msodik ht s harmadik ht adag tlagt ugyangy. r
junk olyan lekrdezst, ami dtumokra s kzpontokra leosztva megmutatja az
egyes adagcsoportokat s az ezekbl kszlt eszkzk tlagos szmt.

Megolds
Az els lekrdezs nem jelent gondot:
SELECT term_kozpont, term_datum, COUNT(adag_sorszam,
AVG (eszkoz_db)
FROM Termeles
GROUP BY term_kozpont, term_datum;

A msodik lekrdezs megrsa eltt rgztennk kell nhny elfelttelt. Felttele


zem, hogy az adagok 1-tl (n)-ig szmozdnak, s a sorszmozs minden nappal
jraindul. Amennyiben a nyersanyagadagok szma nem oszthat hrommal, v
lasszuk a legjobban illeszked megoldst, amivel az sszes adagot lefedhetjk.
A CASE kifejezs hasznlatval az SQL-92-ben egy nzettblval eldnthetjk, hogy
a hrom csoport kzl melyikbe kerljn az adott sorszm adag:
CREATE VIEW Term3 (term_kozpont, term_datum, harmad, eszkoz_db)
AS SELECT term_kozpont, term_datum,
CASE WHEN adag_sorszam <= MAX(adag_sorszam)/3 THEN 1
WHEN adag_sorszam > (2*MAX(adag_sorszam))/3 THEN 3
ELSE 2
END, eszkoz_db
FROM Termeles;

137

138

SQL-fejtrk
|
i

Ha az ltalunk hasznlt SQL-ben nem mkdik ez a mdszer, prblkozhatunk va


lami ilyesmivel:
CREATE VIEW Term3 (term_kozpont, term_datum, harmad, adag_sorszam,
eszkoz_db,)
AS SELECT term_kozpont, term_datum, 1, adag_sorszam, eszkoz_db
FROM Termeles AS TI
WHERE adag_sorszam <= (SELECT MAX(adag_sorszam)
FROM Termeles AS P2
WHERE TI.term_kozpont =
P2.term_kozpont
AND TI.term_datum =
P2.term_datum)
UNION
SELECT term_kozpont, term_datum, 2, adag_sorszam, eszkoz_db
FROM Termeles AS Tl
WHERE adag_sorszam > (SELECT MAX(adag_sorszam)
FROM Termeles AS P2
WHERE Tl.term_kozpont = P2.term_kozpont
AND Tl.term_datum = P2.term_datum)
AND adag_sorszam <= (SELECT 2 * MAX(adag_sorszam)
FROM Termeles AS P2
WHERE Tl.term_kozpont = T2.term_kozpont
AND Tl.term_datum = T2.term_datum)
UNION
SELECT term_kozpont, term_datum, 3, adag_sorszam, eszkoz_db
FROM Termeles AS Tl
WHERE adag_sorszam > (SELECT 2 * MAX(adag_sorszam)
FROM Termeles AS T2
WHERE Tl.term_kozpont = T2.term_kozpont
AND Tl.term_datum = T2.term_datum);

Brmelyik mdszert vlasztjuk is, a vgeredmnyt szolgltat lekrdezs ugyanaz:


SELECT term_kozpont, term_datum, harmad, COUNT(adag_sorszam),
AVG(eszkoz_db)
FROM Term3
GROUP BY term_kozpont, term_datum, harmad;

li

5. fejezet Adatok csoportostsa

47. feladvny - Hrombl kett


Klnbz cikkrk munkibl szeretnnk egy gyjtemnyes kiadvnyt sszellta
ni. Az egyes cikkrkat a cikkiro_azon mez azonostja. A dolog gy alakul, hogy
szksgnk lenne a knyvben szerepl cikkrk kzl azokra, akik pontosan kett
kategriban szerepelnek a cikkeikkel az ltalunk paramterknt megadott hrom
kategria kzl.
CREATE TABLE Antolgia
(cikkiro_azon INTEGER NOT NULL PRIMARY KEY,
cikkiro_nev CHAR(20) NOT NULL,
kategria INTEGER NOT NULL,
... ) ;

1. megolds
Az els gondolatunk, hogy ez egy egyszer csoportostott lekrdezs az albbi
formban:
SELECT cikkiro_azon, cikkiro_nev, :elso_kat, :masodik_kat,
:harmadik_kat
FROM Antolgia AS Al,
WHERE Al.kategria IN (:elso_kat, :masodik_kat, :harmadik_kat)
GROUP B Y cikkiro_azon, cikkiro_nev
HAVING COUNT(*) = 2;
Ez a megolds sajnos nem mkdik, mert elfordulhat, hogy a cikkr kt cikke
ugyanabba a kategriba tartozik. Szksgnk lenne mg egy ( C O U N T ( D I S T I N C T
<kifejezes>) tpus felttelre is. A lekrdezs mg gy is nagyon egyszer:
SELECT cikkiro_azon, cikkiro_nev, :elso_kat, :masodik_kat,
:harmadik_kat
FROM Antolgia AS Al,
WHERE Al.kategria IN (:elso_kat, :masodik_kat, :harmadik_kat)
GROUP B Y cikkiro_azon, cikkiro_nev
HAVING COUNT(DISTINCT Al.kategria) = 2 ;
Tudnnk tallni olyan megoldst, ami nem hasznlja a GROUP B Y zradkot? Hozz
teszem, hogy nem javaslom az itt kvetkez megoldsok hasznlatt, a gyakorlat
clja, hogy megfelel mdon rtkeljk a GROUP B Y zradk lehetsgeit.

139

SQL-fejtrk

2. megolds
A feladatmeghatrozs nem tr ki arra, hogy a hrom kategria kzl brmelyik
kett vlaszthat-e, vagy meghatrozott sorrendben kell lennik (pldul az l-es s
2-es kategriban szerepel, de a 3-asban nem). Ezzel az utbbi kiktssel knnyen
rhatunk egy lekrdezst:
SELECT Al.cikkiro_azon, Al.kategria, A2.kategria
FROM Antolgia AS Al,
Antolgia AS A2
WHERE Al.cikkiro_azon = A2.cikkiro_azon
-- n-sszekapcsols
AND Al.kategria = :elso_kategoria -- l-es kategria
AND A2.kategria = :masodik_kategoria -- 2-es kategria
AND NOT EXISTS (SELECT *
-- de nincs 3-as kategria
FROM Antolgia AS A3
WHERE Al.cikkiro_azon = A3.cikkiro_azon
AND A3.kategria = :harmadik_kategoria));

3. megolds
Ha olyan lekrdezst keresnk, amely brmely kett kategrit engedi a hrom k
zl, szksgnk van valamilyen programozsi trkkre. Az albbi megolds nem ha
trozza meg, hogy a hrom kzl melyik kett hinyzik:
SELECT cikkiro_azon, cikkiro_nev, :elso_kat, :masodik_kat,
W :harmadik_kat
FROM Antolgia AS Al,
WHERE Al.kategria IN (:elso_kat. :masodik_kat, :harmadik_kat)
AND EXISTS
(SELECT *
FROM Antolgia AS A2,
WHERE A2.kategria IN (:elso_kat. :masodik_kat,
:harmadik_kat)
AND Al.kategria < A2.kategria
AND Al.cikkiro_azon = A2.cikkiro_azon
AND NOT EXISTS
(SELECT *
FROM Antolgia AS A3,
WHERE A3.kategria
IN (:elso_kat, :masodik_kat,
:harmadik kat)

5. fejezet Adatok csoportostsa

AND Al.cikkiro_azon = A3.cikkiro_azon


AND (Al.kategria <> A3.kategria
OR A2.kategria <> A3.kategria)));
Azon cikkrk megtallshoz, akik mindhrom kategriban szerepelnek, elg ki
cserlni a N O T E X I S T S () felttelt az EXISTS () kittelre.
Ha azokat keressk, akik csak egy kategriban szerepelnek, ezt kell tennnk:
SELECT
FROM
WHERE
AND

cikkiro_azon, cikkiro_nev, :elso_kat


Antolgia A S Al,
Al.kategria = :elso_kat
NOT EXISTS (SELECT *
FROM Antolgia AS A2
WHERE A2.kategria = :elso_kat
AND Al.cikkiro_azon = A2.cikkiro_azon
AND Al.kategria <> A2.kategria);

Ez utbbi a hrombl kett" lekrdezs rvidtett vltozata.

48. feladvny - Becslt s tnyleges kltsgek


C. Conrad Cady egy egyszer SQL-krdst kldtt a CompuServe Gupta-frumra.
Az adatokat az Elirnyzat s Jelenlegi_ertek tblk troljk, amelyek tj
koztatnak az adott munka pillanatnyi llapotrl. Az Elirnyzat tbla egy-sok
kapcsolatban ll a Jelenlegi_ertek tblval. A tblk szerkezete az albbi:
CREATE TABLE Elirnyzat
(feladat INTEGER NOT NULL PRIMARY KEY,
kategria INTEGER NOT NULL,
becs_ktg DECIMAL(8,2) NOT NULL);
CREATE TABLE Jelenlegi_ertek
(bizonylati_ertek DECIMAL(8,2) NOT NULL PRIMARY KEY,
feladat INTEGER NOT NULL REFERENCES Elirnyzat(feladat),
tenyleges_ar DECIMAL(8,2) NOT NULL);

Olyan sszehasonltsra lenne szksg, ami megmutatja az egyes kategrikban


a tervezett s eddigi tnyleges rfordtsokat, lehetv tve ezek sszehasonltst.
Egy pldn keresztl knnyebben megrthet a feladat:

141

142

SQL-fejtrk

Elirnyzat
feladat
1
2
3
4
5

kategria
9100
9100
9100
9200
9200

becsktg
100,00
15,00
6,00
8,00
11,00

feladat
1
1
1
2
4
5
5

tenylegesar
10,00
20,00
15,00
32,00
8,00
3,00
4,00

Jelenlegiertek
bizonylatiertek
1
2
3
4
5
6
7

A kvnt kimenet a kvetkez:


Eredmny
kategria
yiuo
9200

becslt
121,00
19,00

elklttt
77,00
15,00

A 121, 00 a 9100-as kategrij hrom feladat becs_ktg mezjnek sszege.


A 7 7, 0 0 az ehhez a hrom feladathoz tartoz ngy knyvelsi bizonylat
tenyleges_ar mezjnek sszege (hrom sszeg tartozik az els ttelhez, egy
a msodikhoz, a harmadikhoz pedig egy sem).
Conrad a kvetkez lekrdezssel prblkozott:
SELECT kategria, SUM(becs_ktg) AS becslt,
SUM(tenyleges_ar) AS elklttt
FROM (Elirnyzat LEFT OUTER JIN Jelenlegi_ertek
ON Elirnyzat.feladat = Jelenlegi_ertek.feladat)
GROUP BY kategria;

5. fejezet Adatok csoportostsa

Az albbi eredmnnyel:
Eredmny
kategria
9100
9200

becslt
32lj>n

30,00

elklttt
77,00
15,00

A g o n d az, hogy a 1 0 0 , 0 0 rtket hromszor szmoljuk b e l e az s s z e g b e a JIN


kapcsolat miatt, e b b l addik a 3 2 1 , 0 0 a l 2 1 , 0 0 helyett, a 1 1 , 00-t pedig ktszer
szmoljuk, ami 3 0 , 0 0 rtket ad a helyes 1 9 , 0 0 helyett.
Ltezik olyan SQL lekrdezs, ami a fenti tblkkal a kvnt eredmnyt adn vissza?

Megolds
Bob Badour egy olyan SQL-89-ben rt nzettblt javasolt, amivel szerinte megkap
hatjuk a kvnt kimenetet:
CREATE VIEW kat_ktg (kategria, becs_ktg, tenyleges_ar)
AS SELECT kategria, becs_ktg, 0.00
FROM Elirnyzat
UNION
SELECT kategria, 0.00, tenyleges_ar
FROM Elirnyzat, Jelenlegi_ertek
WHERE Elirnyzat.feladat = Jelenlegi_ertek.feladat;
A nzettblt a kvetkez lekrdezs kveti:
SELECT kategria, SUM(becs_ktg), SUM(tenyleges_ar)
FROM kat_ktg
GROUP BY kategria;

Az SQL-92 lehetv teszi, hogy az albbi mdon JIN kapcsolatot hozzunk ltre az
egyes feladatokra elklttt teljes sszegek s az Elirnyzat tblban lv kate
gria kztt:
SELECT Bl.kategria, SUM(becs_ktg), SUM(elklttt)
FROM Elirnyzat AS Bl
LEFT OUTER JIN

SQL-fejtrk

(SELECT feladat, SUM(tenyleges_ar) AS elklttt


F R O M Jelenlegi_ertek AS Al
G R O U P BY feladat)

O N Al.feladat = Bl.feladat
G R O U P BY Bl.kategria;

A L E F T O U T E R J I N azokat a helyzeteket is jl kezeli, amikor mg nem kltttnk


semmit az adott feladatra. Ha olyan SQL-t hasznlunk, ami a JOlN-on bell nem
engedi meg a S E L E C T utasts hasznlatt, az itt bemutatott mdszerrel kibonthat
juk a bels lekrdezst, egy nzettblt ltrehozva belle.

49. feladvny - Szemlyzeti krds


Daren Race azzal prblkozott, hogy egy sszestett eredmnyeket tartalmaz hal
mazt tovbb sszestsen a Gupta SQLBase segtsgvel, s ezt mshogy nem tudta
elkpzelni, mint tmeneti tbla vagy nzettbla alkalmazsval. me egy plda az
ltala alkalmazott mdszerre:
Szemlyzet

nev
Dri
Jzsi
Erika
Nikolett
Katalin

Szarni
Szaml
ERT
ERT
ERT

Ezutn az oszt_azon szerint sszestette az adatokat:


SELECT oszt_azon, COUNT(*)
FROM Szemlyzet
GROUP BY oszt_azon;

Az albbi eredmnnyel:
Eredmny

osztjeon

COUNTD

Szaml
ERT

2
3

5. fejezet Adatok csoportostsa

Ezt kveten az osztlyokon dolgozk tlagos szmt szerette volna meghatrozni,


amire a V I E W hasznlatt tallta a legclravezetbbnek:
CREATE VIEW OsztNezet (oszt_azon, fo)
AS SELECT oszt_azon, COUNT(*)
FROM Szemlyzet
GROUP BY oszt_azon;
Majd:
SELECT AVG(fo) FROM OsztNezet;
Ezutn tette fel Daren a krdst a CompuServe Gupta-frumn, hogy tudna-e vala
ki olyan megoldst javasolni, ami nem hasznl tmeneti tblt (vagy nzettblt).
Kt vlasz rkezett, mgpedig a kvetkezk:
SELECT AVG(DISTINCT oszt_azon)
FROM Szemlyzet;

s
SELECT COUNT(*) / COUNT(DlSTINCT oszt_azon)
FROM Szemlyzet;

A feladatunk az, hogy megkeressk ezekben a hibt.

Megolds
Az els megolds fogja az osztlyok azonostit, eldobja a N U L L rtkeket (ebben az
esetben nem is szabad ilyennek lenni benne), ezutn elhajtja a ktszer szereplket,
majd a maradkot tlagolja. Ennek semmi kze az egyes osztlyokon dolgoz alkal
mazottak szmhoz, pldul az (1 + 2/2) = 1,5 eredmnyt kaphatjuk vlaszknt.
A msodik lekrdezs igazbl sokkal jobb, s az adatainknl helyes eredmnyre is ve
zet. Kiszmolja a C O U N T (*) = 5 rtket, majd elosztja a C O U N T (DISTINCT (oszt_azon))
= 2 eredmnnyel, ami valban 2,5-et ad vgeredmnyl, ahogy kvntuk.

SQL-fejtrk

146

De ekkor felvesznk hrom j alkalmazottat (Laci, Mni s Kriszta), akik egyelre


nincsenek osztlyhoz rendelve. Ekkor a tbla az albbi adatokat fogja tartalmazni:
Szemlyzet

nev
Dri
Jzsi
Erika
Nikolett
Katalin
Laci
Mni
Kriszta

Szaml
Szaml
ERT
ERT
ERT
NULL
NULL
NULL

Most a C O U N T (*) = 8 rtket kapjuk, de a C O U N T ( D I S T I N C T (oszt_azon) ) = 2 to


vbbra is, mivel a N U L L rtkek nem szerepelnek ebben az sszestsben, vagyis az
eredmnynk (4) lesz. Az igazi vlasz az lenne, hogy nem tudjuk meghatrozni
a pontos rtket, de annyit tudunk, hogy valahol (8/5 = 1,60) s (8/3 = 2,66) kztt
kell lennie, attl fggen, hogy a hrom j dolgozt melyik osztlyhoz rendeljk.
Ha Race r ragaszkodna az eredeti eljrshoz, a kvetkez eredmnyt kapnnk:
Eredmny
osztazon
Szaml
ERT
NULL

COUNTC)
2
3
3

A vgeredmny pedig a korbbival megegyezen 1,5 lenne, mert ugyan a csopor


tostott nzettblban a N U L L rtkek kln jelennek meg, de a vgs lekrdezs
tlagolsban mr nem vennnek rszt.

5. fejezet Adatok csoportostsa

50. feladvny - Lovi


pp az imnt nyertk el a maffiafnk Eddie A Doktor" Franco Codetti alkalmaz
sban az adatbzisigazgati megbzatst. Statisztikai clbl adatbzisunkban trol
juk a lversenyek eredmnyeit, melynek alaptblja a kvetkez szerkezet:
CREATE TABLE Versenyeredmnyek
(plya CHAR(3) NOT NULL,
verseny_datum DATE NOT NULL,
futam INTEGER NOT NULL,
els CHAR(30) NOT NULL,
msodik CHAR(30) NOT NULL,
harmadik CHAR(30) NOT NULL,
PRIMARY KEY (plya, date, futam));

A plya mez a plya nevt tartalmazza, ahol a versenyt rendezik, a verseny_datum a verseny dtumt, a futam a futam szmt, a maradk hrom oszlop pedig
a nyer, a msodik s harmadik helyezett l nevt trolja.
Egy nap a Doktor azzal fordul hozznk, hogy tudni akarja, az egyes lovak hnyszor
hoztak pnzt a konyhra. Milyen SQL lekrdezst rnnk erre?

1. megolds
A pnzt hoz a konyhra" kifejezs mgtt az ll, hogy a l a hrom helyezs kzl
elrte valamelyiket, most lnyegtelen, hogy melyiket. Az els lps egy VIEW ltre
hozsa az sszegzett adatokkal, vagyis:
CREATE VIEW Fizetsek (lo, alkalom, helyezs) AS
SELECT els, COUNTf*), 'els'
FROM Versenyeredmnyek
GROUP BY els
UNION
SELECT msodik, COUNT(*), 'msodik'
FROM Versenyeredmnyek
GROUP BY msodik
UNION
SELECT harmadik, COUNT(*), 'harmadik'
FROM Versenyeredmnyek
GROUP BY harmadik;

148

SQL-fejtrk

Ezt a nzettblt hasznlhatjuk a vgs sszestshez:


SELECT lo, SUM(alkalom)
FROM Fizetsek
GROUP BY lo;

A szvegllandkat azrt helyeztk el a SELECT mezlistjban, hogy ha Codetti


esetleg arra is kvncsi lenne a jvben, hogy a lovak hnyszor s milyen helyezst
rtek el, a lekrdezst egyszeren mdosthassuk:
SELECT lo, helyezs, SUM(alkalom)
FROM Fizetsek
GROUP BY lo, helyezs;

2. megolds
Ha van egy olyan tblnk, amiben szerepel az sszes l, az albbi mdon is megr
hatjuk a lekrdezst:
SELECT
FROM
WHERE
GROUP

Ll.lo, COUNT(*)
LoNevek AS Ll, Versenyeredmnyek AS El
Ll.lo IN (El.elso, El.msodik, El.harmadik)
BY Ll.lo;

A megolds szpsge az, hogy azokat a lovakat is ltjuk, amelyekbl semmilyen


hasznunk nem szrmazott.

51. feladvny - Szllodai szobk


Ron Hiner kldte el a kvetkez krdst a CompuServe WATCOM-frumra. Egy
olyan adattalakt projektben vett rszt, amelyben automatikusan meg kellett ha
troznia azokat az rtkeket, amelyek egy hotelszobkat trol tbla elsdleges
kulcsnak rszt kpezhettk.
Az elsdleges kulcs emelet nev rsze az pletben tallhat szinteket jelli, ami
egy msik tblhoz tartoz idegen kulcs. A hotelszobhoz tartoz kulcs ltalunk
ellltand rsze a szobaszm; a szobaszmoknak egymst kvet szmoknak kell

5. fejezet Adatok csoportostsa

lennik xO 1-tl kezdden, ahol x az adott szint szma. A szlloda elg kicsi ah
hoz, hogy biztosak lehessnk abban, hogy elegend a hromjegy szmok haszn
lata. A tbla meghatrozsa gy fest:
CREATE TABLE Szlloda
(emelet SMALLINT NOT NULL,
szoba SMALLINT NOT NULL,
PRIMARY KEY (emelet, szoba),
FOREIGN KEY emelet REFERENCES Epulet(emelet);
Pillanatnyilag az albbi adatokat troljuk a tblban:

emelet
1
1
1
2
2
3

NULL
NULL
NULL
NULL
NULL
NULL

A WATCOM SQL - nhny ms termkhez hasonlan - rendelkezik egy


N U M B E R (*) nev fggvnnyel, ami 1-tl kezdden nvekv szmokkal tlti fel
a fggvnyt hv sorokat.
Van-e egyszer lehetsg a N U M B E R (*) fggvny (vagy valamilyen ms mdszer)
hasznlatval arra, hogy nmkden feltltsk a szobaszmok oszlopt? Hiner
azon morfondrozott, hogy a G R O U P B Y zradkot kellene alkalmazni valahogy az
emeletszmokra ahhoz, hogy a szmols 1-tl mindig jrakezddjn.

1. megolds
A WATCOM-ot hasznl programozk a kvetkez megkzeltst vlasztottk. El
szr futtassunk le egy olyan frisstst az egsz adatbzison, ami feltlti a szobasz
mokat. Ez a fogs csak gy mkdhet, ha biztostani tudjuk, hogy a Szlloda tb
la frisstse rendezett sorrendben trtnjen. Trtnetesen a WATCOM egy egyszer
O R D E R B Y zradkkal kpes ezt garantlni az U P D A T E utastsban:

149

150

SQL-fejtrk

UPDATE Szlloda
SET szoba = (emelet*100)+NUMBER(*)
ORDER BY emelet;
Ezzel a kvetkez eredmnyt kapjuk:

emelet
1
1
1
2
2
3

101
102
103
204
205
306

Ha ezt kveten a kvetkez frisstseket is lefuttatjuk, megkapjuk a kvnt


eredmnyt:
UPDATE Szlloda
SET szoba = (szoba - 3)
WHERE emelet = 2;
UPDATE Szlloda
SET szoba = (szoba - 5)
WHERE emelet = 3;

emelet
1
1
1
2
2
3

101
102
103
201
202
301

Sajnos ehhez elg pontosan kell ismerni a szllodban lv szobaszmokat. Tud


nnk esetleg ennl jobb, az ORDER BY zradkot mellz megoldst adni?

5. fejezet Adatok csoportostsa

2. megolds
Az SQL utastsok ltrehozsra magt az SQL-t fogom hasznlni. Ez gyes csel,
amit a gyakorlatban nem igazn hasznlnak ki. Fontos, hogy jl figyeljnk az
aposztrfokra s ne felejtsk a szmokat karakterlncc alaktani.
SELECT DISTINCT
'UPDATE Szlloda SET szoba = ('
II CAST (emelet AS CHAR(l))
II ' * 100)+NUMBER(*) WHERE emelet = '
II CAST (emelet AS CHAR(1)) II
FROM HamisTabla;
Az utasts eredmnye egyetlen szveges oszlop lesz:
UPDATE Szlloda SET szoba = (emelet*100)+NUMBER(*) WHERE emelet = 1;
UPDATE Szlloda SET szoba = (emelet*100)+NUMBER(*) WHERE emelet = 2;
UPDATE Szlloda SET szoba = (emelet*100)+NUMBER(*) WHERE emelet = 3;

Msoljuk a kapott eredmnyt SQL-nk parancsrtelmezjbe vagy egy parancsfjl


ba s futtassuk le. Az eredmny nem fgg a tbla sorainak sorrendjtl.
Azt is megtehetjk, hogy a kapott szveget egy trolt eljrs belsejbe msoljuk, s
az emeletszmot ennek adjuk t paramterknt. Mivel csak egyszer futtatjuk le,
nem rdemes eljrst rni s lefordtani, nem nyernk idt vele.

151

Trgymutat

A
#

Abbott de Rham 118

ltalnos szlsrtk 44

ACCESS 120

altats 11

adatpsg-ellenrzs 50

AND mvelet 55

adatfolyam-diagramok 75

Anilbabu Jaiswal 114

adatformzs 34

ANSI/ISO SQL-92 115

adatkivlaszts 49

aposztrf 51

adatmeghatrozs 1

ruhzi akci 123

adatok csoportostsa 109

tlagfggvny 86

adatok formzsa 17

tlagos kltsg 97

adatszerkezeti problmk 1

tlagszmts 114

adszmts 92

tmeneti tbla 69, 105, 144

adzsi krzet 92

tmeneti tblk 134

AFD75

tmeneti tr 133

Alan Flancman 69

AVGO 86, 115

alapbr 43

azonost 51

alkatrszek 78
ALL felttel 80

lland 8
lland tbla 135
alperes 34
ltalnos skalris alkifejezsek 43

BASIC 33
begyazott n-sszekapcsols 103
begyazott OUTERJOIN kapcsolatok
42

SQL-fejtrk

bels lekrdezs 37, 46


bels lekrdezsekben hasznlhat
kifejezsek 102

CREATE TABLE 129

brleti dj 65

CREATE VIEW 2

Beit Scalzo 7

csillag 8

beszlltk 78

csoportok felbontsa 129

BETWEEN llts 19

csoportostott lekrdezs 46, 139

BETWEEN felttel 31, 125

csoportostott tbla 87, 109

Bipin C. Desai 78

CREATE ASSERTION 2
CREATE TABLE utasts 3

CURRENT_DATE fggvny 90

brsgi kereset 34
biztonsgi azonostk 15
Bob Badour 143

Bob Stearns 128

Daren Race 144

Brendan Campbell 38

DB2 9, 46

Brian K. Buckley 99

Delphi 55

Brian Young 72

DeMorgan-trvny 68

C, Cs

denormalizlt adatbzis 1

C. Conrad Cady 141

Dewey-kd 2

Carl C. Federl 68

diagram-ellenrz eljrs 76

CASE frum 75

Dictionary of Occupational Titles 55

CASE kifejezs 40, 70, 106, 112, 123,


137

dinamikus SQL lekrdezsek 54

CASE kifejezsek 115

diplomaszerzs 115

CASTO 33

DISTINCT zradk 78

CEILING 131

diszjunktv kanonikus forma 56

Cenk Ersoy 31

dntsi tbla 68

CHECKO megszorts 1

DOT 55

CHECKO zradk 19, 128

Dr. Nyrfs 10

Dewey-fle katalogizl rendszer 2

Diosdado Nebres 96

CHECKO zradkban lev bels


lekrdezsek 129
Chris Date 64, 78
COALESCEO fggvny 42, 115
Cobol 17, 33, 66
CONTAINS felttel 78

E,
egyenl halmazok 78
egymsba gyazott halmazok 20
egy-sok kapcsolat 141

157

Trgymutat

egyszeres idzjel 51

FORMAT 33

eleme 78

FORMAT utasts 17

Elmasri 78
elforduls 78

formtumra vonatkoz
megszortsok 17

els normlforma (INF) 70

Fortran 33

els(n) fggvny 44

frissts 149

elsdleges kulcs 3, 53, 134, 148

FROM kifejezs 58

eltelt napok 88

FROM zradk 109, 136

epszilon 78

fggvnyknyvtrak 83

erforrs-igny 120

FULL OUTER JOIN 41, 79

rtkcskkens 96

Full SQL-92 129

rtkestk 60

futsid 78

rzstelents 10
eszkzgyr 136
tterem 27
EXISTSO 141
EXISTSO llts 8
EXISTSO fggvny 68

G,Gy
Gantt-diagram 11
Gerard Manko 49
Gerhard F. Jilovec 96
Gillian Robertson 92
GROUP BY 58
GROUP BY zradk 7, 37, 96, 104,
109, 125, 139, 149

Fabian Pascal 43
feladatazonost 50

Gupta 42

felesleges szkzk 17

Gupta-frum 31, 141, 145

feltteles lltsok 71
frhelyek 26
fizikai brzols 17
fiat table 74
FLOOR 131
folyamatbrk 75
folyamatok 49
folyamattpusok 51
folyiratok 66
FOREIGN KEY 50

H
halmazelmlet 78
halmazok 130
halr 112
halszmlls 112
harmadik genercis nyelvek 43
hrombl kett 139
hatkr 16

158

SQL-fejtrk

HAVING zradk 30, 31, 61, 90, 125,


126

helyirtk 136

kapcsolat nlkli fjlok 66

hivatkozsi psg 50

kapcsolt allekrdezs 58

hivatkozsi megszortsok 66

karakterlnc 51, 151


karakterlnc-lland 39
karakterlncokk trtn talakts 48

IBM 60, 78

karakterlnc-sszefzs 33

idegen kulcs 148

Karn Gallaghar 65

idkezel fggvnyek 5

Keith McGregor 66

ignyls 102

keressi felttel 55

illetk 104

ketts idzjel 51

INO felttel 78

kettztt rekordok 119

INO prediktum 71

kezdet-esemny 13

INNERJOIN 79

kiold 121

INSERT INTO 33

kirts 133

INSERT INTO utasts 19

kdfordt tbla 37

INSERT utasts 75

kdolsi rendszer 2

interpolci 85

kdolsi sma 2

iratok 19

kltsgek 141
kltsgvetsi v 3

ismtelt sorbeszrs 130

kltsgvetsi jelents 110


krhz 10

krkrs hivatkozs 16, 20

J. D. McDonald 126

koszinusz 83

Jack Wells 43

kzelts 85

korrellt allekrdezs 58

jelents 104

kzpkori r templomok 2

jelentskszt nyelv 109

kzvetlen kls hivatkozs 125

jelentskszt program 130

kulccsal rendelkez tbla 130

jelzmez 26

kulcs 122

Jim Armes 104

kulcsmezk 126

Jim Chupella 5
JIN 81, 125

Trgymutat

kulcssz 51

mrfldkvek 72

kls sszekapcsols 41

metszet 81

kurzorelhelyez utasts 43

Mike Conway 47

kszbrtk 68

MINO 39
mintavteli hibk 108

L
LanSoft Inc. 110
Larry Wade 54
LEFT OUTER JIN 48, 51, 66, 111,
115, 118, 144

modellprok 118
mdusz 86
mozg tlag 107
Mr. Shankar 63
MS-ACCESS frum 5, 28, 54, 118

leggyakrabban elfordul rtkek 86

munkaegysgek 97

legnagyobb nem NULL rtk 75

munkahelyi tvollt 5

ler statisztikai fggvny 86

munkakzvett 54

lekrdezs-kszt 90
leltrozs 102
Leonard C. Medl 10, 34, 105
lineris kzelts 85

munkarend 31
munkaviszony 28
mutatlncok 20
mtt 10

Linh Nguyen 101


LISP 49
logikai nzet 17
lverseny 147
lovi 147
Luk Tymowski 28

M
Mark Frontra 110

N Ny
f

Navthe 78
negatv rtkek 70
nem sszefgg llandlista 96
nested sets 20
nzettbla 2, 76, 144
Nigel Blumenthal 104
normalizls 49

Mary Attenborough 135

NOT EXISTSO 141

msols 133

NOT NULL 129

MAXO 39

NOT NULL felttel 3

MAXO fggvny 75, 87, 112

NULL 87, 97, 103, 114, 129, 145

megjelentsi problmk 36

NULL rtk 3

megszorts-ellenrz 129

NUMBERC) 149

SQL-fejtrk

nyomtatk idbeosztsa 24

PowerSoft 99

nyugdjalap 28

Primary 51
PRIMARY KEY 26, 51, 53, 129

0,
oktatk 38

nmagra mutat hivatkozs 129

radin 84

n-sszekapcsols 31, 46, 74, 106, 119

Raymond Petersen 88

OR mvelet 56

REFERENCES zradk 53

Oracle 8, 42, 43, 47, 114

reklmlevl 58

Oracle Corporation 7

relcis oszts 57, 64

Oracle User Group Forum 38

rendezs 104

ORDER BY zradk 149

replgpek 64

orosz paraszt algoritmus 130

rszhalmazok 78

sszegz fggvny paramter 115

rszletes nzettbla 90

sszegz fggvnyek 40

Richard S. Romley 30, 39, 46, 47, 58,


92, 115, 126

sszegz fggvnyt tartalmaz


nzettbla 69

Ron Hiner 148

sszes termk 90

rossz kdolsi rendszerek 2

sszest fggvny 114

Roy Harvey 63

OUTER JOIN 41, 51, 66, 103, 115


OVERLAPS llts 19

S,Sz

Scott Gammans 18
SELECT a SELECT utastsban 104

Paradox 49
patk 78

SELECT utastsban hasznlt CASE


kifejezsek 40

Paul Dong 86

self-join 31

Pepperoni 121

SIGNO fggvny 70

Peter Lawrence 134

SIGN(ABS(fn)) 70

PICTURE 33

Sissy Kubu 129

piltk 64

skalris bels lekrdezs 103, 111

PL/I 1 7 , 3 3

skalris fggvnyek 83

PowerBuilder 55, 104

skalris lekrdezs 111

Trgymutat

Skip Lees 52

szmolgpes karra 83

Software AG 90

szrmaztatott tblk 115

sokszorosan begyazott lekrdezs 91

szlsrtk-fggvnyek 38

Sorin Shtirbu 37

szemlyzet 144

sorltrehoz fggvnyek 71

szinusz 83

sorszmok 20

szobafoglals 18

SQL felsfokon 2

szkvek 9

SQL Hotel 18

szvegllandk 148

SQL3

83

SQL-89

43, 74, 77, 86, 102, 121

SQL-92

7, 16, 17, 28, 30, 39, 46, 51,

53, 58, 61,70, 74, 77,87, 94, 112

T,Ty
tbla elsdleges kulcsa 115

SQL-92 Intermediate 129

tblk ltrehozsa 3

SQL-92 szabvny 43

tblanevek azonossga 16

SQLBase 144

tblzatkezel 84

Steve Roti 72

tblzatkezelk 5

Steve Tilson 19

tblzatos bels lekrdezs 120

SUBSTRINGO 33

tancsadi djazs 99

SUMO 114

trolt eljrs 151

SUMO fggvny 72

TEOR 55

SuperCalc 5

telefon 40

Sybase 42, 69, 70

teljes karakterlnc 17

Sybase-frum 63, 66

teljes kls sszekapcsols 41

Sybase SQL Anywhere 49

teljestmny 47, 53

Syed Kadir 47

tenyrgp 26

SYSTEM R 78

termelsi kltsgek 97

szabad helyek 26

termelsi statisztikk 137

szabvnyos SQL 78
szabvnyos SQL-89 78

termszetes nyelven trtn


lekrdezs 90

szabvnyos SQL-92 83

teszteredmnyek 63

szllodai szobk 148

tzbl egy 69

szmts 83

Tom Bragg 75

szmtsi nyelvek 83

tmb 70

SQL-fejtrk

trl lekrdezs 8

res tbla 103

Trident Data Systems 104

zleti v 4

trigger 121

zleti hnap 4

TRIMO 17

u,

V
valdi rszhalmaz 78

dltulajdonos 65

vsrlsi srsg 88

gyfl-kiszolgl rendszer 109

vg-esemny 13

jranormalizls 2

VTEW2

lhelyszakaszok 128

Vinicius Mello 135

UNION 74, 106, 122


UNION mvelet 13

UNION utasts 45

WATCOM-frum 18, 110, 148

UNIQUE zradk 53

WATCOM SQL 49, 96, 99, 104

UPDATE 108, 149

WATCOM SQL 4.0 31

UPDATE lekrdezs 8

WHERE felttel 99, 109

UPDATE utasts 16

WHERE zradk 13, 65

UNION ALL utasts 46

res halmaz 114


res karakterlnc 18

Y
Yogesh Chacha 24

You might also like