<<Elöző fejezet | Tartalom | Minta adatok>> |
7.1. Objektum orientált megközelítés
7.1.1 Öröklődés
7.2. Összetett adattípusok
7.3. Grafikus adatok tárolása
7.4. Térbeli indexelés
7.5. PostGIS
7. Újabb irányzatok az adatbáziskezelésben
Ebben a fejezetben - elsősorban a PostgreSQL adatbáziskezelő rendszer alapján - még nem standard, de egyre szélesebb körben támogatott adatbázis fejlesztéseket mutatok be, a teljesség igénye nélkül. Elsősorban a térinformatikai alkalmazás lehetőségét szem előtt tartva.
7.1 Objektumorientált megközelítés
Számos az objektum orientált megközelítés paradigmáira épülő úgynevezett objektum adatbáziskezelő rendszert (ODBMS) fejlesztettek, fejlesztenek. Az objektum orientált adatbázisokról itt találhat további cikkeket. Az SQL 1999 is objektum orientált megközelítést alkalmaz, de megtartja az SQL-92 kompatibilitást. Ezért ez az objektum modell nem felel meg az objektum orientált programnyelveknek. A relációs és az objektum orientált megközelítést egyesítő megoldásokat objektum relációs adatbáziskezelőknek (ORDBMS) nevezzük.
A relációs adatbáziskezelők többféle objektumot használnak, pl. adatbázis, tábla, index stb. Ezen objektumok közül a táblák esetén kezdenek a relációs adatbáziskezelők az objektum orientált megközelítés felé nyitni. A PostgreSQL esetén az objektum orientált megközelítéstől elvárható elzártság (encapsulation), többértelműség (polymorfizmus) és öröklés (inheritance) hármas közül az öröklődést valósították meg.
Adatbázisainkban gyakran hasonló szerkezetű táblákat használunk, gyakran egyes táblák oszlopai között nagy az átfedés. Ezekben a táblák definiciójának egymásra építésével (örököltetésével) egyszerűbben kezelhető szerkezetet kapunk.
Egy példán keresztűl nézzük meg, hogyan alkalmazható PostgreSQL esetén az öröklődés. Az adatbázisunkban személy- és teherautó típusok adatait szeretnénk nyílvántartani. Ehhez a hagyományos megközelítés szerint a következő két táblát hoznánk létre:
Create Table szemely ( gyarto text, tipus text, kobcenti int ); |
Create Table teher ( gyarto text, tipus text, kobcenti int, maxteher int ); |
Amennyiben egy gyártó valamennyi típusát szeretnénk megkapni, függetlenül attól, hogy személy vagy teher, akkor egy unio segítségével állíthatjuk elő az eredményt.
Select tipus From szemely Where gyarto = "Opel" Union Select tipus From teher Where gyarto = "Opel";
Egy nézet tábla létrehozásával kényelmesebbé tehetjük a két tábla használatát.
Create View jarmu As Select gyarto, tipus, kobcenti From szemely Union Select gyarto, tipus, kobcenti From teher; Select tipus From jarmu Where gyarto = "Opel";
Ez a forma azonban az tábla aktualizálása (Update) során már nehézségeket okoz.
Ennél jobb megoldás a két tábla egymásból származtatása.
Create Table szemely ( gyarto text, tipus text, kobcenti int ); |
Create Table teher ( maxteher int, ) Inherits(szemely); |
A teher tábla sorai öröklik a szemely tábla oszlopait (gyarto, tipus, kobcenti). A típusokra vonatkozó lekérdezést ezután egyszerűbben leírhatjuk.
Select tipus From szemely Where gyarto = "Opel";
A fenti lekérdezés nem csak a személy táblára vonatkozik, hanem az abból származtatottakra is. Olyan lekérdezést is kiadhatunk, mely a származtatott táblákat nem veszi figyelembe.
Select tipus From Only szemely Where gyarto = "Opel";
Az "Only" kulcsszó jelzi, hogy a lekérdezés nem terjed ki a származtatott táblákra. Az Update és Delete SQL utasításokban is használható az Only kulcsszó. Az objektum orientált és hagyományos megközelítés között még nagyobb a különbség, ha többszörös származtatást használunk, például újabb járműtípusok bevezetésével (busz, motorkerékpár, stb.). Egy tábla akár több táblából származtatható, de az öröklödési fa csak hurok nélküli irányított gráf lehet.
A fenti probléma más (kevésbé elegáns, hatékony) megoldása is elképzelhető a relációs adatbázisokban.
a., Definiálhatnánk egy olyan táblát, mely tartalmazza a két tábla minden oszlopát. Személyautok esetén a "maxteher" oszlopot nem töltjük ki. Ez a megoldás egyrészt feleslegesen növeli az adatbázis méretét, másrészt pedig az oszlopok kitöltésére, üresen hagyására vonatkozó szabályrendszert kell használni (személyautók esetén nem szabad, teherautók esetén pedig kötelező kitölteni).
b., Hozzunk létre egy táblát, mely csak az egymásból származtatott táblák oszlopainak közös halmazát tartalmazza. Az alap táblából kimaradt oszlopokhoz objektum típusonként hozzunk létre egy új táblát. Ebben az esetben az új rekordok beillesztése, meglévő rekordok aktualizálása két táblára terjedhet ki, a lekérdezésekhez a két táblát össze kell kapcsolni.
A relációs adatbázisokban már megszoktuk, hogy az első normál forma feltétele nem mindig teljesül, például a nagy bináris objektumok (BLOB) esetén. Az objektum orientált megközelítés összetett, komplex adattípusok megvalósítását is igényli. A PostgreSQL újabb verzióban az egyes oszlopokban fix vagy változó méretű, akár több indexes tömböket is tárolhatunk. A tömb elemeinek típusa a beépített vagy a felhasználó által definiált típusok bármelyike lehet. A tömbök alkalmázára nézzük a következő példát.
Create Table fizetés (név text, havi_bér integer[]);
Az adattípus után megjelenő [] egy változó méretű tömböt jelent, a fix méretű tömböknél a méretet a zárójelek között adhatjuk meg.
A tömb típusú elemek kezelése eltér az egyszerű típusú elemekétől. Tömb feltöltése értékekkel:
INSERT INTO fizetés VALUES('Kovács', '{125000, 125000, 132000}');
INSERT INTO fizetés VALUES('Nagy', '{92000, 87000, 92000, 98000}');
Ezután nézzünk néhány lekérdezést:
SELECT név FROM fizetés WHERE havi_bér[1] > havi_bér[2];
SELECT név, havi_bér[2] FROM fizetés;
SELECT havi_bér[1:3] FROM fizetés;
Az első lekérdezés azoknak a nevét adja vissza, akiknek a második havi fizetése kisebb mint az első havi. A második lekérdezés a második havi béreket listázza. Végül a harmadik lekérdezés segítségével a tömb egy tartományát (1-3) elemét kérdezzük le. A tömb kezdő elemének indexe 1.
A tömb elemek módosítása vonatkozhat a teljes tömbre vagy annak csak egy részére, de a tömb indexeinek folytonosnak kell lennie, nem maradhatnak ki indexek.
UPDATE fizetés SET havi_bér = '{140000, 150000}' WHERE név='Kovács';
UPDATE fizetés SET havi_bér[3] = 145000 WHERE név='Kovács;
UPDATE fizetés SET havi_bér[3:4] = '{145000, 155000}';
Az első példa a teljes tömbelem tartalmát lecseréli. A második példában egy elemmel bővítettük a tömböt. A harmadik példában a tömb egy tartományt aktualizáltuk.
Fix méretű tömbök esetén a tábla definicióban a tömb maximális méretét adhatjuk meg a "[" "]" jelek között. Jelenleg a Postgres nem korlátozza a fix méretű tömbök indexeit sem, így a változó méretű (dinamikus) tömbökkel azonos módon használható. Több indexes tömbök is használhatók. A tömbök méretét az array_dims függvénnyel kérdezhetjük le.
SELECT array_dims(havi_bér) FROM fizetés;
A tömbök fenti módon bemutatott használata az első normál forma szabályát sérti. A normalizált, két táblára bontott megoldás egyszerűbben kezelhető (pl. keresés). A grafikus adatok, koordinátalisták tárolására viszont hatékonyan használhatók a tömbök.
Az egyes tömbelemek nem vehetik fel a NULL értéket, de az egész tömb igen.
7.3. Grafikus adatok tárolása
Egyre több relációs adatbáziskezelő (Oracle Spatial Cartridge, PostgreSQL, MySQL, stb.) teszi lehetővé a grafikus elemek koordinátáinak tárolását és térbeli indexelését. Ezeket azonban nem a normalizált formában tárolják, hanem inkább változó hosszúságú rekordokat=tömböket használnak. Erre elsősorban a hatékony grafikus megjelenítés miatt van szükség.
Normalizált törtvonal tárolás | Változó hosszúságú rekord | |||||||||||||||||||||||||||||||||||||||||||||
Pontok
Egy törtvonal lekérdezése: Select x,y From Pontok, Törtvonalak Where Pontok.pont_id = Törtvonalak.pont_id and vonal_id = 1 Order By sorszam; |
Törtvonalak
Egy törtvonal lekérdezése: Select * From Törtvonalak Where vonal_id = 1; |
A PostgreSQL a tömb típusú mezők segítségével valósítja meg a grafikus adatok tárolását. A következő speciális adattípusokat használhatjuk térképi 2D-s grafikus elemek tárolására.
Grafikus elem | Méret (Byte) | Megjelenés | Megjegyzés |
pont (point) | 16 | (x,y) | Pont elem |
egyenes (line) | 32 | ((x1,y1),(x2,y2)) | Végtelen egyenes |
szakasz (lseg) | 32 | ((x1,y1),(x2,y2)) | Véges vonalszakasz |
téglalap (box) | 32 | ((x1,y1),(x2,y2)) | Koordinátatengelyekkel párhuzamos téglalap |
zárt törtvonal (path) | 16+16n | ((x1,y1),...) | Zárt törtvonal (poligonnal azonos) |
nyitott törtvonal (path) | 16+16n | [(x1,y1),...] | Nyitott törtvonal |
poligon (polygon) | 40+16n | ((x1,y1),...) | Poligon (zárt törtvonallal azonos) |
kör (circle) | 24 | <(x,y),r> | Kör, középpont, sugár |
A PostgreSQL a "Simple Features for SQL" szabványt követi, melyet az OpenGIS Consortium dolgozott ki. A szabvány fő jellemzői
A Postgres számos geometriai operátort definiál, melyeket az alábbi táblázat tartalmaz.
Operátor | Leírás | Példa | Eredmény |
---|---|---|---|
+ | Eltolás | SELECT box '((0,0),(1,1))' + point '(2.0,0)'; | (3,1),(2,0) |
- | Eltolás | SELECT box '((0,0),(1,1))' - point '(2.0,0)'; | (-1,1),(-2,0) |
* | Skálázás, forgatás | SELECT box '((0,0),(1,1))' * point '(2.0,0)'; | (2,2),(0,0) |
/ | Skálázás, forgatás | SELECT box '((0,0),(2,2))' / point '(2.0,0)'; | (1,1),(0,0) |
# | Metszéspont | SELECT lseg '((1,-1),(-1,1))' # lseg '((1,1),(-1,-1))'; | (0,0) |
# | Pontok száma (path vagy polygon) | SELECT # path '((1,1),(3,2),(4,0))'; | 3 |
## | Elem legközelebbi pontja | SELECT point '(0,0)' ## lseg '((2,0),(0,2))' | (1,1) |
&& | Átfedés? | SELECT box '((0,0),(5,5))' && box '((4,4),(7,7))' | t (igaz) |
&< | Átfedés balra? | SELECT box '((0,0),(1,1))' &< box '((0,0),(2,2))' | t (igaz) |
&> | Átfedés jobbra? | SELECT box '((0,0),(3,3))' &> box '((0,0),(2,2))' | t (igaz) |
<-> | Távolság | SELECT circle '((0,0),1)' <-> circle '((5,0),1)' | 3 |
<< | Balra? | SELECT circle '((0,0),1)' << circle '((5,0),1)' | t (igaz) |
<^ | Alatta? | SELECT circle '((0,0),1)' <^ circle '((0,5),1)' | t (igaz) |
>> | Jobbra? | SELECT circle '((0,0),1)' >> circle '((5,0),1)' | f (hamis) |
>^ | Felette? | SELECT circle '((0,0),1)' >^ circle '((0,5),1)' | f (hamis) |
?# | Metszés vagy átfedés? | SELECT lseg '((-1,0),(1,0))' ?# box '((-2,-2),(2,2))' | t (igaz) |
?- | Vízszintes? | SELECT point '(1,0)' ?- point '(0,0)' | t (igaz) |
?-| | Merőleges? | SELECT lseg '((0,0),(0,1))' ?-| lseg '((0,0),(1,0))' | t (igaz) |
@-@ | Hossz vagy kerület | SELECT @-@ path '((0,0),(2,0),(2,2),(0,2))' | 8 |
?| | Függőleges? | SELECT point '(0,1)' ?| point '(0,0)' | t (igaz) |
?|| | Párhuzamos? | SELECT lseg '((-1,0),(1,0))' ?|| lseg '((-1,2),(1,2))' | t (igaz) |
@ | Tartalmaz vagy rajta? | SELECT point '(1,1)' @ circle '((0,0),2)' | t (igaz) |
@@ | Középpont | SELECT @@ circle '((0,0),10)' | (0,0) | >
~= | Azonos? | SELECT polygon '((0,0),(1,1))' ~= polygon '((1,1),(0,0))' | t (igaz) |
Az operátorok mellett a geometriai elemekhez számos függvény is kapcsolódik. Ezeket az alábbi táblázat foglalja össze.
Függvény | Visszaadott érték | Leírás | Példa | Eredmény |
---|---|---|---|---|
area(objektum) | duplapontos (double) | az objektum területe | area(box '((0,0),(1,1))') | 1 |
box(box,box) | téglalap (box) | téglalapok közös része | box(box '((0,0),(1,1))',box '((0.5,0.5),(2,2))') | |
center(objektum) | pont (point) | az objektum középpontja | center(box '((0,0),(1,2))') | (0.5,1) |
diameter(circle) | duplapontos (double) | kör átmérője | diameter(circle '((0,0),2.0)') | 4 |
height(box) | duplapontos (double) | téglalap magassága | height(box '((0,0),(1,1))') | 1 |
isclosed(path) | logikai (bolean) | zárt törtvonal? | isclosed(path '((0,0),(1,1),(2,0))') | t (igaz) |
isopen(path) | logikai (bolean) | nyitott törtvonal? | isopen(path '[(0,0),(1,1),(2,0)]') | t (igaz) |
length(object) | duplapontos (double) | az objektum hossza | length(path '((-1,0),(1,0))') | 4 |
npoints(path) | egész (integer) | pontok száma | npoints(path '[(0,0),(1,1),(2,0)]') | 3 |
npoints(polygon) | egész (integer) | pontok száma | npoints(polygon '((1,1),(0,0),(1,0))') | 3 |
pclose(path) | zárt törtvonal (path) | törvonal zárt törtvonallá konvetálása | pclose(path '[(0,0),(1,1),(2,0)]') | ((0,0),(1,1),(2,0)) |
popen(path) | nyitott törtvonal (path) | törtvonal nyitott törtvonallá konvertálása | popen(path '((0,0),(1,1),(2,0))') | [(0,0),(1,1),(2,0)] |
radius(circle) | duplapontos (double) | kör sugara | radius(circle '((0,0),2.0)') | 2 |
width(box) | duplapontos (double) | téglalap szélessége | width(box '((0,0),(1,1))') | 1 |
A különböző geometriai elemre több típus konverzió függvény is létezik. ezeket az alábbi táblázat foglalja össze.
Függvény | Visszaadott érték | Leírás | Példa | Eredmény |
---|---|---|---|---|
box(circle) | téglalap (box) | körbe illesztett téglalap | box(circle '((0,0),2.0)') | (1.41,1.41),(-1.41,-1.41) |
box(point,point) | téglalap (box) | téglalap két átellenes pontból | box(point '(0,0)', point '(1,1)') | (1,1),(0,0) |
box(polygon) | téglalap (box) | polygon befoglaló téglalapja | box(polygon '((0,0),(1,1),(2,0))') | (2,1),(0,0) |
circle(box) | kör (circle) | téglalapba illesztett kör | circle(box '((0,0),(1,1))') | <(0.5,0.5),0.71> |
circle(point, double precision) | kör (circle) | pont és sugár alapján kör | circle(point '(0,0)', 2.0) | <(0,0),2> |
lseg(box) | szakasz (lseg) | téglalap átlója | lseg(box '((-1,0),(1,0))') | [(1,0),(-1,0)] |
lseg(point, point) | szakasz (lseg) | pontokat összekötő szakasz | lseg(point '(-1,0)', point '(1,0)') | [(-1,0),(1,0)] |
path(polygon) | törtvonal (path) | poligon átalakítás törtvonallá | path(polygon '((0,0),(1,1),(2,0))') | ((0,0),(1,1),(2,0)) |
point(circle) | pont (point) | kör középpontja | point(circle '((0,0),2.0)') | (0,0) |
point(lseg, lseg) | pont (point) | metszéspont | point(lseg '((-1,0),(1,0))', lseg '((-2,-2),(2,2))') | |
polygon(box) | poligon (polygon) | téglalapból poligon | polygon(box '((0,0),(1,1))') | ((0,0),(0,1),(1,1),(1,0)) |
polygon(circle) | poligon (polygon) | körből 12 pontból álló poligon | polygon(circle '((0,0),2.0)') | ((-2,0),(-1.7,1.0),(-1.0,1.7),(0.,2),(1.0,1.7),(1.7,1.0),(2,0.0),(1.7,-1.0),(1.0,-1.7),(0.0,-2),(-1.0,-1.7),(-1.7,-1.0)) |
polygon(n, circle) | poligon (polygon) | körből n pontból álló poligon | polygon(12, circle '((0,0),2.0)') | ((-2,0),(-1.7,1.0),(-1.0,1.7),(0.,2),(1.0,1.7),(1.7,1.0),(2,0.0),(1.7,-1.0),(1.0,-1.7),(0.0,-2),(-1.0,-1.7),(-1.7,-1.0)) |
polygon(path) | poligon (polygon) | törtvonalból poligon | polygon(path '((0,0),(1,1),(2,0))') | ((0,0),(1,1),(2,0)) |
A térinformatikai adatok relációs adatbázisban tárolásához egy önálló modult is készítettek a Postgres objektum relációs adatbáziskezelőhöz. Ez a PostGIS modul. A PostGIS modul relációs táblákba tudja konvertálni az elterjedtebb térinformatikai adatformátumokat, többféle vetületet kezel és térkép megjelenító programokkal (pl. Mapserver) biztosítja a kapcsolatot.
...
A PostGIS a PostgreSQL adatbáziskezelő térinformatikai alkalmazásához tovább bővített változata. Az Oracle Spatial Cartridge vagy ESRI ARCSDE téradatszervereknek megfelelő funkcionalítást biztosít a nyíltforrású ingyenes (GPL) szoftverek körében.
<<Elöző fejezet | Tartalom | Minta adatok>> |