Érettségi feladatok analízise tanároknak adatbázis-kezelésből
Ezt már olvastam, ugorgyunk a lekérdezésekhez!Ez a (stílszerűen adatbázis-lekérdezésekkel dolgozó) összeállítás azért született, mert kerestem egy olyan segédletet, amely alapján áttekinthetném a közismereti érettségin előforduló feladattípusokat, és végül jobb híján kénytelen voltam magam megcsinálni. Szeretettel ajánlom kedves kollégáimnak a földszinten, az első emeleten és az Informatika levelezőlistán. Az összeállítás elsősorban tanároknak szól, és a felkészítést segíti. (De azért persze használhatják diákok is.) A feltöltés folyamatosan zajlik, és szerintem hamarabb kész lesz, mint a Tisza-tóé. Pár tanács és tudnivaló, valamint stiláris megjegyzések:
- Ebben az áttekintésben és a feladatokhoz fűzött megjegyzésekben is többször linkeltem
az Informatika levelezőlista archívumára , mert az ottani levélváltások fontos hozzáadott értéket tartalmaznak, és éltem a mesterelme erejével. Kb. 2012 és 2013 fordulóján, egy pontosan meg nem határozott időpontban az Educatio Kft. a lista archívumát zárttá, azaz csak a tagok számára olvashatóvá tette. Így aki el szeretné olvasni a leveleket, annak a http://lista.sulinet.hu/mailman/listinfo/informatika címen fel kell iratkoznia a listára (beállíthat nomailt is, hogy ne kapjon leveleket, de a kollégák iratkozzanak csak fel rendesen), és a kapott jelszóval egyszer belépni az archívumba. Onnantól fogva, amíg a sütije megvan, a többi linket is el fogja tudni olvasni újabb procedúra nélkül. - A bal oldali legördülő menüben van az, amiért hozzákezdtem az egészhez: a
típusfeladatok és megoldási eszközök keresése. Természetesen csak a már feldolgozott feladatsorokban! A jobb oldaliban a feladat egészét érintő, ill. speciális lekérdezések vannak. Ezekből olyan kérdésekre kaphatunk választ, mint Adtak-e már fel összetett kulcsot középszinten?, Volt-e olyan feladadsor, amelyikben egyáltalán nem volt egytáblás lekérdezés? vagy Mennyi volt a legtöbb tábla egy feladatban? avagy Melyik középszintű feladatban találok akkora táblát, amiben egy tanítványom sem képes szabad szemmel megkeresni a legnagyobb értéket? Különösen ajánlom amegjegyzések kiíratása menüpontot; megjegyzést ugyanis csak indokolt esetben tettem, és így ezekből kiguberálható, hol vannak a felkészítés során különös figyelmet igénylő trükkök, kritikus pontok, érdekességek. Végül az alsó menü egy kiválasztott feladat teljes elemzését adja, megkönnyítve az órára készülést. - Néhány nagyon gyakran előforduló
triviális feladat nincs jelezve. Nem lehet keresni a lekérdezéses feladatokra általában, mivel ezek minden feladatsorban alkotmánymódosító arányban hemzsegnek; az importálásra, mert az mindig az első feladat; nincsenek továbbá feltüntetve az egyszerű lekérdezési feltételek (WHERE
), a tábla új mezővel való bővítését és a nem megjelenítendő mezőt tartalmazó feladatok. Az első két feladat, az import és a típusok/kulcsok beállítása az utóbbi évek feladatsoraiban összemosódik, voltaképpen egy esetlegesen megbontott feladat a kettő, ezért lehet, hogy a típus és a megjegyzés hol az egyikhez, hol a másikhoz került. Sag schon. :-) Hívjuk fel a tanulók figyelmét, hogy importálás közben csak az egyszerű kulcsot lehet beállítani az Accessben! Ha összetett kulcs van, hagyjuk ezt a lépést az importálás utánra.- Egy feladatra nem feltétlenül jellemző az összes felsorolt tulajdonság egyszerre; az is lehet, hogy
különböző megoldási módokhoz tartoznak. Az allekérdezés és a segédlekérdezés jellemzően egymás alternatívái, ezért egy típusként vettem fel őket. Tehát az allekérdezésnél megjelenő feladatok nagy száma nem azt jelenti, hogy ennyiszer kellett használni, hanem hogy ennyiszer lehetett. - Bizonyos ismétlődő
típusfeladatok mindig többféle módon megközelíthetők, ezért akkor is érdemes lehet olyan típusú feladatokat keresni a jellemző csoportnál, ha a módszert kifelejtettem az összerendelésből.- Például a
„legkisebb/legnagyobb” feladatoknak nekieshetünk az Access-specifikus „SELECT TOP 1 ORDER BY
” módszerrel is vagy a „WHERE ... = (SELECT MAX())
” jellegű allekérdezésekkel. (Fontos ezzel kapcsolatban! [1] [2] [3]) (Megjegyzés: a pályák nem egyformák. Accessben aTOP 1
hármas holtverseny esetén mind a hármat kiválasztja. SQL-szabvány szerint aLIMIT 1
-et használhatjuk, de az tényleg csak egyet ír ki. OO Base-ben mind a kettő működik, de csak trükközéssel (direkt SQL-mód), és mind a kettő csak egy rekordot ad ki holtverseny esetén is.) - Az egyik gyakran ismétlődő összetett feladattípus, az
„azonos csoport többi eleme” (ld. pl. a Pizza vagy a Barlang feladatnál) mindig megoldható allekérdezéssel, segédlekérdezéssel vagy bátrabbaknak egyetlen lekérdezéssel, a tábla duplikálásával („SELECT ... FROM tábla, tábla AS tábla1
”). [NOT] BETWEEN és [NOT] IN. Nélkülözhető dolgok, ÉS/VAGY kapcsolatokkal kiválthatók. (Az IN kulcsszó esetén itt a felsorolt halmazokra gondolok, nem az allakérdezésekre!) Két okból érdemes mégis használni őket, ahol lehet. Az egyik, hogy tisztábbá, átláthatóbbá teszik a kódot, könnyebb megérteni belőle, mit miért csináltunk. (S ez nemcsak filozófiai kérdés, hanem a vizsgázónak is érdeke, hogy a javító tanár könnyebben megtalálja a részpontokat a nem tökéletes megoldásában.) A másik, hogyOR
kapcsolatokat lehet kiváltani velük. Az ÉS kapcsolatot ott egye a fene, annak magas a precedenciája, nem ellenfél. De a VAGY könnyen problémát okozhat a műveleti sorrendnél! Főleg, ha először magában áll, és nincs is jelentősége a sorrendnek, aztán utólag egészítjük ki egy ÉS feltétellel, de már nem jut eszünkbe foglalkozni vele. Egy érettségiző egy stresszes szituációban igazán könnyen beleszaladhat ebbe a hibába. (Lásd pl. a Notebook.5vasarlas feladatnál.) Rövidebb egész intervallumok esetén a BETWEEN helyett mindig jó az IN, de megint nem segíti a kód olvashatóságát. Inkább akkor stílszerű az alkalmazása, ha nem összefüggő intervallumban keresünk vagy szövegek között.
- Például a
SQL-használat az Accessben (középszinten sehol nem kötelező, de hasznos és nem szégyen):DISTINCT vagy GROUP BY?
ADISTINCT
(szerintem) könnyebben előáll az SQL-kód manipulálásával, mint az Access tervezőrácsán, ahol a mező vagy érték tulajdonságait kell a jobb egérgombbal kiválasztani, és ott az „egyedi értékek” tulajdonságot igenre állítani; azért gyűjtöttem ilyeneket is. Aki ilyet akar gyakoroltatni, az aGROUP BY
-os feladatok közül is válogathat, és megfordítva, ezek aGROUP BY
használatával is megoldhatóak. Akármelyik utat választjuk, könnyebb aDISTINCT
záradékot beállítani, mint aGROUP BY
esetleges útvesztőibe, hibajelzéseibe belemenni. (Ha az összesítő beállításoknál túl sok attribútumnál hagyjuk meg aGROUP BY
opciót, és nem cseréljük pl.WHERE
-re, akkor kaphatunk hibajelzést is, de ha az eredményen nem változtat ez a csoportosítás, akkor lehet az eredmény egy bonyolultabb kód isHAVING
záradékkal, miközben a megoldás helyes.)
Egy kis keresgéléssel a következő kép alakult ki bennem:- A
GROUP BY
igazi felhasználási területe az összegző függvények használata. (Természetesen csak ott, ahol az összegzendő mezővel együtt másikat is ki kell írni – ha csak egy átlagot kérnek magában, akkor nem kell.) Indokolt még akkor is, ha több mező szerint csoportosítunk. (Bár hirtelen nem találok példát olyan esetre, amikor nagyon hasznos egy nem megjelenített mező szerint is csoportosítani, növelve a sorok számát és látszólag egyforma értékeket kiírva.) - Ha csak annyi a feladat, hogy egyetlen mező különböző értékeit írassuk ki, akkor az eredményt tekintve
ekvivalens a
SELECT DISTINCT érték FROM tábla
és aSELECT érték FROM tábla GROUP BY érték
. - Más kérdés, hogy algoritmikusan is ekvivalensek-e. A
DISTINCT
mellett szól, hogy tisztább, átláthatóbb kódot eredményez, amely a szándékainkat jobban kifejezi (a programozás tanításánál súlyt fektetünk az ilyesmire – akkor miért ne tennénk ugyanezt az adatbázis-kezelésnél is?), és gyorsabb lehet. Az adatbázis-kezelő rendszerünk optimalizálási képességeitől függ, hogy ténylegesen is gyorsabb-e. Többen beszámoltak róla, hogy az SQL Server elvégzi ezt az optimalizálást, azaz felismeri az ekvivalenciát. ([1] [2]) A sebesség persze nem kritérium az érettségin, de a szemléletformázáshoz hozzátartozik. Az Access ezen a ponton nem támogatja a gondolati tisztaságot azzal, hogy aGROUP BY
elérhető egyetlen kattintással, aDISTINCT
pedig nem. - Érdekesség, hogy beágyazott lekérdezéseknél (allekérdezéseknél) egyes esetekben a
GROUP BY
lehet a gyorsabb. ([1] [2]) Olyan állítás is van, miszerint aDISTINCT
gyorsabb, ha az azonos értékekhez kevés rekord tartozik, és aGROUP BY
, ha sok. (Mindez nyilván függ az implementációtól is.) - Egy olyan esetet találtam, ahol kifejezetten csak a
GROUP BY
oldja meg a feladatot, és aDISTINCT
nem alkalmas. Ez is roppant tanulságos eset, az Opera.6wagner lekérdezés elemzésénél látható a magyarázat több részletben. Gyanítom, hogy kevés vizsgázónak sikerült hibátlanul vennie az akadályt... (Az átverős feladattól eltekintve arról van szó, hogy egy nem megjelenítendő mezőt kéne különbözővé tenni, és ilyenkor aDISTINCT
nem használható.)
- A
- Maga a
HAVING
nem igazán fontos dolog, amíg nem akarunk SQL-ben dolgozni, hiszen a tervezőrácson meglehetősen nehéz egyWHERE
feltételtől megkülönböztetni, és jól elboldogulhat, aki nem tudja a különbséget. Ha középszinten megjelenik a kódban, érdemes ellenőrizni, jól állítottuk-e be az összegző feltételeket. (Van-eWHERE
-re cserélhetőGROUP BY
.)
Az ELTE 2007-2012.4kezdes feladat javítási útmutatója jól mutatja, hogyan használhatjuk hibásan a HAVING záradékot. A jó megoldás:
SELECT ev, SUM(felvett) AS kezdok FROM jelentkezes WHERE forma="A" OR forma="O" GROUP BY ev;
A szerencsétlen megoldás:
SELECT ev, SUM(felvett) AS kezdok FROM jelentkezes GROUP BY ev, forma HAVING forma="A" OR forma="O";
Hangsúlyozom, hogy az eredmény azonos lesz! Az első kód szűr a keresett rekordokra, és csak ezekre fog összegezni, míg a második lekérdezés elvégzi a csoportosítást és az összegzést az összes rekordra, majd a feltételnek meg nem felelőket eldobja. Nem nehéz látni, hogy ez pazarolja az erőforrásokat, és nagy adatbázisnál lassabb lehet. Ugyanaz a kérdés, mint fent: az azonos eredményt adó lekérdezések algoritmikusan is ekvivalensek-e? Egyformán tükrözik-e a szándékainkat? Ha nem, akkor didaktikai szempontból melyiket szerencsésebb ajánlani? - Az Access a QBE-rácson csak az oszlopok sorrendjében tudja felvenni a rendezőkulcsokat, tehát ha több kulcs szerint rendezünk, lehet, hogy meg kell az oszlopokat is cserélnünk. De mi van, ha a feladat előírja, hogy milyen sorrendben legyenek, vagy egyszerűen csak úgy logikus, mert más sorrendben szörnyen nézne ki? Ilyenkor felvehetjük másodszor is az első oszlopot nem megjelenőként, de aki nem ismeri ezt a trükköt, annak egyszerűbb SQL-ben átírni.
- Az „SQL-piszkálással könnyebb” típusú feladatok közé tartozik még az, ahol az
INNER JOIN LEFT JOIN
-ra módosításával érhetünk el eredményt – ezt Accessben igazából a kapcsolat típusának módosításával is megtehetnénk. Ilyenek a „nincs a másik táblában” típusú feladatok két táblával. (Ezeknél tényleg indokoltan jön be aHAVING
. Kettőnél több tábla, kapcsolótábla esetén ez már nem egyszerűsíti a megoldást, de lehet kísérletezni a Forint.10nikkel vagy a Tánc.7kardos feladaton.) - Idetartoznak az allekérdezések is; ezek elkerülhetők segédlekérdezéssel vagy olykor TOP típusú lekérdezéssel vagy a tábla duplikálásával.
- Nem is kell SQL-nézet, a tervezőrácson is használhatjuk az IN /NOT IN operátort felsorolásokkal; ez nemcsak egyszerűsítheti a megoldást, hanem az OR feltétellel járó buktatókat is elkerülhetjük a műveleti sorrendnél. Hármas OR kapcsolat esetén, mint az Opera.6wagner feladatban, már érdemes alkalmazni. De vigyázzunk a szintaxisra, az SQL-kódban vesszővel kell elválasztani az elemeket, a QBE-rácson pedig pontosvesszővel, és egyik helyett sem jó a másik! Sajnos ilyenkor csak konstans elemeket sorolhatunk fel, tehát a Barlang.3regies feladatban nem használható a módszer.
Tanítsunk-e egyáltalán SQL-t a középszintű felkészítés során? Azt hiszem, a fentiekben már benne van a válasz egy része: érdemes megismertetni vele a tanulókat. Ha több időnk nincs, arra szoktassuk rá őket, hogy az elkészült lekérdezéseket minden esetben nézzék meg SQL-nézetben is, nem fog fájni, és szokják az érzést. :-) A többi már jön magától. A törekvőbbek sokan szeretnének MySQL+PHP alapú weblapot készíteni, és ha már van egy kis lövésük a programozáshoz, akkor ezzel megadhatjuk nekik a kezdőlökést az önálló továbblépéshez. Azonban nem árt felhívni a figyelmet, hogy ezek a generált lekérdezések olykor bonyolultabbak a kelleténél.
- A 0/1 vagy 0/-1
logikai értékként való használata az importálásnál jelenik meg, az ehhez tartozó lekérdezésekben is gyakoroltassuk, hogy ne pánikoljon be a vizsgázó, amikor (hacsak a megjelenítést át nem állította) nem logikai értéket lát, illetve az 1-ek -1-ekké válnak. - A
karakterkódolást a régebbi feladatokban nem adták meg és nem kérték kifejezetten számon, de ahol jelentősége van, feltüntettem az importnál. - Érdemes egy pillanatra elmélázni a
is. Az útmutatókban szinte üzemszerűen aCOUNT()
függvény lelkivilágánCOUNT(*)
megoldással, azaz komplett rekordok megszámlálásával találkozunk. Ez csak nulladik közelítésben ekvivalens az érintett mezők megszámlálásával. Egyes források szerint gyorsabb konkrét mezőt (különösen indexattribútumhoz tartozó mezőt) számlálni, mint egész rekordokat. (Az „egyes források szerint” arra utal, hogy nem akarok itt bizonyítatlan állításokat tényként közölni, a diszkusszió pedig meghaladja ennek az oldalnak a kereteit. Legalább ezt érdemes mindenkinek elolvasnia áttekintésként.) Van azonban elvi különbség is a két megközelítés között, amely aForma–1.5hiba feladatban válik gyakorlativá és okozhat problémát a vizsgázóknak. A Microsoft ezt írja (természetesen az Accessről): „A GROUP BY mezők Null értékei nem maradnak ki a csoportosításból. Az összesítő SQL-függvények azonban nem veszik figyelembe a Null értékeket.” Vagyis ha az összesítendő mező NULL értékeket tartalmaz, akkor ezek automatikusan kimaradnak; ha azonban komplett rekordokat számlálunk meg vagy adunk össze, akkor nem élvezhetjük ezt az előnyt (mivel nem minden mező NULL értékű a rekordban), és ilyenkor további szűrés kell a helyes eredményhez. A fent említett feladathoz fűzött megjegyzésben látható, miként hozza magával a helytelenül alkalmazottCOUNT(*)
a NULL értékre való szűrés előírását a javítási útmutatóban, és az indokolatlan pontlevonást azoktól a vizsgázóktól, akik a megfelelő mezőre („hiba”) végezték el a számlálást. Az adatbázis-kezelési szemlélet alakítását tekintve is szerencsésebbnek tartanám, ha az útmutatók aCOUNT(mező)
(választási lehetőség esetén aCOUNT(elsődleges kulcs)
) típusú összegzéseket preferálnák. Műveleti sorrend alatt nem a számtani alapműveletek sorrendjét értem, mert az alsó tagozatos probléma, hanem a logikai műveletekét a feltételben. Például a Vízvezetékszerelők.5aznap feladatban Barackfalva és Kőváros nevét egymás alá, s nem mellé írjuk a rácson, akkor figyelnünk kell, hogy a javdatum=bedatum feltétel is mind a két sorban megjelenjék. Nagyon érdekes viszont az Érettségi.9dombi lekérdezés. Ha egymás alá írjuk a „11/C” és a „nem 11-ikes” feltételeket az OR két ágaként, majd mind a kettő mellé a matematikát (talán így is helyes a közbenső ellenőrzés eredménye), akkor az összegző sor bekapcsolása után az előbbi aGROUP BY
záradék alá, vagyis az SQL-kódHAVING
sorába kerül, a tantárgy pedig aWHERE
után marad, s így (már nem lévén egy művelet operandusai) az a furcsa helyzet áll elő, hogy a kódban aWHERE vizsgatargy.nev="Matematika" Or vizsgatargy.nev="Matematika"
sor áll majd, illetve a rácson is önmagával lesz VAGY kapcsolatban. (Lásd még fent.)Azonos típusú feladatokhoz érdemes különböző feladatsorok javítási útmutatóit, illetve mintamegoldásait nézegetni, mert esetenként más-más megoldási módszert találunk bennük.- Pár szó a
feladatkitűzőknek szánt lekérdezésekről: az analízis melléktermékeiről, azértelmezési problémás , afeladatkitűzéstől eltérően értékelt és ahibás vagy fölösleges bemenő adatokra épülő feladatsorok listájáról van szó. Senkit nem szándékom bántani ezekkel, mert ha nekem kéne feladatot gyártani, talán én is követnék el hasonlókat. Különben is, ezek már kimúlt, békés feladatsorok, nem bántanak senkit. A legmélyebb tisztelettel tárom őket kollégáim elé, akiket igen nagyra tartok. A cél a problémák kimutatása olyan ember szemével, aki kívülállóként oldotta meg a feladatsorokat. Tisztában kell lennünk vele, hogy a vizsgázók általában stresszhelyzetben és időzavarban vannak. Olyan értelmezést, utánajárást, ami más körülmények között logikus lenne, a vizsgán nem várhatunk el, és nem hozhatjuk olyan helyzetbe őket, hogy elmenjen egy csomó idejük a diszkusszióra vagy egy bonyolultabb megoldásra, amiért nem jár pont. Ők is ismerik a javítási útmutatók stílusát, és ezért kétség esetén nem mernek egyszerűsítésekbe belemenni. Az egyértelműség ideálisan azt is jelenti, hogy az évek során kialakul egy olyan kánon, amit a felkészülés során az útmutatókból el lehet sajátítani, és ugyanaz az értelmezés nem kap eltérő értékelést a különböző feladatsorokban. Általánosabb, „filozófiai jellegű” hibaként merülhetnek felaz adatbázis tervezésével, a szemlélet alakításával kapcsolatos kérdések: milyen adatbázist szeretnénk a tanulók elé mintaként állítani? Hiszen az érettségi feladatsor egyfajta ideált, informatikai szemléletet is közvetít az iskolák felé. Maximálisan meg vagyok győződve róla, hogy ezt a feladatkitűzők is így gondolják, ezért szeretném segítségként az általam felismert vagy a levelezőlistán olvasott buktatókat megmutatni.
Ezek a lekérdezések egyben is futtathatóak a Lehetséges problémák (GYŰJTŐ) típus kiválasztásával az általános lekérdezések csoportjából.- Néhány technikai tipp:
- Kapcsoljuk ki az Access beállításainál a lekérdezésekben az
automatikus illesztést . (A táblák felvételekor összeköti az azonos nevű, más rendeltetésű kulcsokat, és ez alkalmas a vizsgázó teljes összezavarására.) - Access 2007-ben, ha már létező adatbázist nyitunk meg újra, és megjelenik felül a
biztonsági figyelmeztetés , miszerint egyes részeket a rendszer letiltott, feltétlenül kattintsunk a beállításokra, majd az engedélyezésre. Ennek hiányában többször előfordult, hogy jól megírt lekérdezések nem futottak le, és hajtépve kereshettük a nem létező hibát. Sajnos a Microsoft újabb termékei oly végtelenül paranoiássá váltak a potenciális fenyegetések ügyében, hogy a saját maguk által létrehozott tartalmat is veszélyesnek nyilvánítják. Be lehet állítani megbízható forrásokat, de hálózati meghajtót nekem nem fogadott el, az adatbázisoknak meg ott kellett lenniük. A 2010-es változattal nincs tapasztalatom. - Az
ANSI 92- (MS SQL Server-) kompatibilitást semmiképpen ne állítsuk be, ha nem akarunk tényleg csatlakozni a Microsoft SQL Serverhez, mert galibákat okozhat.
- Nem biztos, hogy a lista teljes (lehet, hogy egy megoldási mód nem jutott eszembe, és az útmutatóban sem volt leírva), és nem helyettesíti a vizsgakövetelmények tüzetes tanulmányozását.
- Néhány megjegyzést csak egyszer írtam le, de vonatkozik más azonos típusú vagy sorszámú (1-2.) feladatokra is.
- Lősséget nem vállalok sem a rendeltetésszerű, sem a rendeltetésellenes használatból vagy annak elmulasztásából származó károkért és kórokért, valamint az adatbázist borzoló mágneses zavarokért. Háromnegyed lősséget sem. Felelősséget sem. A
kiegészítések, alternatív megoldások, hibák és hiányosságok jelzését e-mailben ide vagy a 64.hu Facebook-oldalára várom. - Néhány technikai tipp:
Szívből ajánlom még az infoerettsegi.blog.hu-t, ahol a kolléga ugyanezen feladatok közül a középszintűeket
oldja
meg videón, többféle programmal.
Az eddig feldolgozott közismereti feladatsorok száma: 18 középszintű (37%), 18 emelt szintű (38%).
A csillaggal jelölt lekérdezések minden feladatsort listáznak, ezek a metaadatok 100%-ban fel vannak dolgozva. | ||