HELSINGIN YLIOPISTO HELSINGFORS UNIVERSITET UNIVERSITY OF HELSINKI Paikkatiedon käsittely 3. Kyselyt paikkatietokannasta Antti Leino antti.leino@cs.helsinki.fi 22.1.2007 Tietojenkäsittelytieteen laitos
SQL Kieli relaatiotietokantojen käsittelyyn: tietokannan tietosisällön määrittelyyn tietojen päivitykseen tietojen hakuun käyttäjien ja käyttöoikeuksien määrittelyyn Tuoreimmat standardin versiot SQL-92 SQL:1999 SQL:2003 Tällä kurssilla käytössä PostgreSQL 7.4, jossa toteutettuna valtaosa standardi-sql:stä
Taulun luominen Esimerkiksi kurssiaineistona oleva koulutus-taulu: CREATE TABLE koulutus ( kunta VARCHAR(25) NOT NULL, tutkinnot NUMERIC(4,2), opiskelijat NUMERIC(1), PRIMARY KEY (kunta) ); Avaimena kunnan nimi Numeerisia tietoja korkeakoulututkinnon suorittaneiden osuus opiskelijoiden osuus
Taulussa olevan tiedon muuttaminen Tietojen lisääminen INSERT INTO koulutus VALUES ( Helsinki, 22.6, 4); Tietojen muuttaminen UPDATE koulutus SET opiskelijat = 4 WHERE kunta = Helsinki ; Tietojen poistaminen DELETE FROM koulutus WHERE kunta = Helsinki ;
Tietokantahaku Perushaku: kunnat, joissa korkeakoulututkinto yli 18 % aikuisväestöstä SELECT kunta, tutkinnot FROM koulutus WHERE tutkinnot > 18 ORDER BY tutkinnot DESC; kunta tutkinnot -------------+----------- Kauniainen 44.40 Espoo 28.60 Helsinki 22.60 Oulu 20.89 Kirkkonummi 20.39 Jyväskylä 19.80 Kaarina 18.89 (7 rows)
Tietokantahaku Kunnat, joissa keskitulo yli 90 000 mk SELECT kunta, tulot_hlo AS keskitulot FROM elintaso WHERE tulot_hlo > 90000 ORDER BY tulot_hlo DESC; kunta keskitulot ---------------+------------ Kauniainen 136578 Espoo 97752 Maarianhamina 94658 Helsinki 94355 (4 rows)
Hakuehtojen yhdistäminen Käytettävissä loogiset operaatiot AND, OR, NOT Kunnat, joissa paljon sekä tutkinnon suorittaneita että opiskelijoita SELECT * FROM koulutus WHERE tutkinnot > 16.66 AND opiskelijat > 5; kunta tutkinnot opiskelijat -----------+-----------+------------- Joensuu 17.30 7 Jyväskylä 19.80 7 Rovaniemi 17.00 6 Turku 17.10 6 (4 rows)
Hakuehtojen yhdistäminen Kunnat, joissa pienet tulot tai suuret sosiaalimenot SELECT kunta, tulot_hlo AS keskitulot, sosiaali FROM elintaso WHERE tulot_hlo < 47000 OR sosiaali > 12000 ORDER BY tulot_hlo; kunta keskitulot sosiaali ------------+------------+---------- Merijärvi 45656 9451 Pylkönmäki 46696 10301 Piippola 50731 12034 Ristijärvi 51559 12421 Kesälahti 56891 12619 Porvoo 78003 12265 Helsinki 94355 12363 (7 rows)
Kyselyt useasta taulusta Valtuustojen voimasuhteet korkeasti koulutetuissa kunnissa SELECT vaalit96.* FROM koulutus, vaalit96 WHERE vaalit96.kunta = koulutus.kunta AND koulutus.tutkinnot > 18; kunta keskusta kokoomus sdp sfp vasemmistoliitto vihreat -------------+----------+----------+-------+-------+------------------+--------- Espoo 2.94 35.29 20.58 11.76 4.41 11.76 Helsinki 3.48 27.90 24.41 9.30 6.97 18.60 Jyväskylä 13.33 23.33 35.00 0.00 10.00 10.00 Kaarina 6.81 31.81 29.54 2.27 11.36 13.63 Kauniainen 0.00 30.55 2.77 50.00 0.00 5.55 Kirkkonummi 4.54 27.27 25.00 22.72 4.54 9.09 Oulu 21.66 20.00 20.00 0.00 16.66 11.66 (7 rows)
Kyselyt useasta taulusta Suurimpien kuntien väkiluku ja muutokset SELECT vakiluku.kunta, vakiluku.v70 AS vakiluku_70, kunnat01.yht-vakiluku.v70 AS muutos_01, vakiluku.v10-kunnat01.yht AS muutosennuste_10 FROM kunnat01, vakiluku WHERE kunnat01.nimi=vakiluku.kunta AND vakiluku.v70 > 100000 ORDER BY vakiluku.v70 DESC; kunta vakiluku_70 muutos_01 muutosennuste_10 ----------+-------------+-----------+------------------ Helsinki 483036 72438 31701 Tampere 166228 29240 11461 Turku 163680 8881 3787 Espoo 137409 75862 11886 Vantaa 132050 46421 10157 (5 rows)
Yhteenvetokyselyt Kyselytuloksessa voi käyttää operaatioita MIN, MAX, AVG, COUNT ja SUM Yhteenlaskettu väkiluku kunnissa, joissa on korkein tulotaso SELECT SUM(kunnat01.yht) FROM kunnat01, elintaso WHERE kunnat01.nimi = elintaso.kunta AND elintaso.tulot_hlo > 85000; sum -------- 837364 (1 row)
Yhteenvetokyselyt Kunnat, joissa yleisiä teitä > 500 km SELECT COUNT(kunta) FROM autoilu WHERE tiet > 500; count ------- 14 (1 row) Lintujen pesimäaineiston ruutujen lukumäärä ja keskimääräinen maan osuus SELECT COUNT(x) AS ruutuja, AVG(maaosuus) AS maata FROM linnut; ruutuja maata ---------+---------------------- 3813 805.6981379491214267 (1 row)
Luokittelu Kyselytuloksen voi luokitella Läänien väkiluku SELECT laani, SUM(yht) AS vakiluku, SUM(ulkom_yht) AS ulkomaalaiset FROM kunnat01 GROUP BY laani ORDER BY laani; laani vakiluku ulkomaalaiset -------+----------+--------------- 1 2081507 55248 2 1835836 24404 3 591093 5140 4 455135 3442 5 191768 1715 6 25776 1125 (6 rows)
Luokittelu Ruutujen lukumäärä ja maan osuus silkkiuikun pesimävarmuuden mukaan SELECT silkkiuikku, COUNT(x) AS ruutuja, AVG(maaosuus) AS maata FROM linnut GROUP BY silkkiuikku; silkkiuikku ruutuja maata -------------+---------+---------------------- 0 2257 843.1187416925121843 1 192 781.5833333333333333 2 177 763.2485875706214689 3 1187 744.7759056444818871 (4 rows)
Alikyselyt Hakuehdossa voi käyttää mukana alikyselyn tuloksia Ahvenanmaan keskimääräistä suuremmat kunnat SELECT nimi, yht FROM kunnat01 WHERE laani = 6 AND yht > (SELECT AVG(yht) FROM kunnat01 WHERE laani = 6) ORDER BY yht DESC; nimi yht ---------------------------+------- Maarianhamina 10488 Jomala 3328 Finström 2299 Saltvik 1679 (4 rows)
Alikyselyt Kunnat, joissa keskitulo korkeintaan 50 000 mk pienempi kuin suurituloisimmassa SELECT kunta, tulot_hlo AS keskitulot FROM elintaso WHERE tulot_hlo > (SELECT MAX(tulot_hlo) FROM elintaso) - 50000 ORDER BY tulot_hlo DESC; kunta keskitulot ---------------+------------ Kauniainen 136578 Espoo 97752 Maarianhamina 94658 Helsinki 94355 Sipoo 87129 Sottunga 86684 (6 rows)
Paikkatietoa käyttävä haku Tampereen naapurikuntien väkiluku SELECT b.nimi, b.yht FROM kunnat01 AS a, kunnat01 AS b WHERE a.nimi = Tampere AND TOUCHES(a.wkb_geometry, b.wkb_geometry) ORDER BY b.nimi; nimi yht ---------------------------+------- Kangasala 22276 Kuru 2839 Lempäälä 16331 Nokia 26905 Orivesi 8886 Pirkkala 12736 Ruovesi 5683 Ylöjärvi 20518 (8 rows)
Etäisyys hakuehtona Ulkomaalaisten osuus kunnan väkiluvusta 20 km säteellä Joensuun keskustasta SELECT b.nimi AS kunta, 100.0*b.ulkom_yht/b.yht AS ulkom_osuus FROM kunnat01 AS a, kunnat01 AS b WHERE a.nimi= Joensuu AND DISTANCE(CENTROID(a.wkb_geometry), b.wkb_geometry) < 20000; kunta ulkom_osuus ---------------------------+------------------------ Joensuu 1.7543181730360524 Kiihtelysvaara 0.59970014992503748126 Kontiolahti 0.55570026916731787792 Liperi 0.50527049394546563289 Polvijärvi 0.46202180742931066346 Pyhäselkä 0.64791838985387372484 Rääkkylä 0.53543307086614173228 (7 rows)
Etäisyys esimerkkitietokannassa Suomessa vanhastaan käytössä KKJ-koordinaattijärjestelmä Peruskoordinaatisto Gauß Krüger-projektio: poikittainen Mercator, mutta»päiväntasaajana» valittu keskimeridiaani Neljä projektiokaistaa, keskimeridiaanit 21,24,27,30 Pohjoiskoordinaatti metrejä päiväntasaajalta Itäkoordinaatti metrejä niin, että keskimeridiaani on 1 500 000 / 2 500 000 / 3 500 000 / 4 500 000
Etäisyys esimerkkitietokannassa Yhtenäiskoordinaatisto Peruskoordinaatiston kaista 3 jatkettu koko Suomen alueelle Vanhastaan käytössä pienimittakaavaisissa kartoissa Vääristyy itä- ja länsireunoillaan pahemmin kuin peruskoordinaatisto Toisaalta yhtenäinen koko alueella Taulun kunnat01 sijaintitieto ja taulun linnut koordinaatit yhtenäiskoordinaatistossa
Kohteiden välinen raja Vierekkäisten alueiden leikkaus on rajaviiva Helsingin ja sen naapurikuntien välisen rajan pituus SELECT b.nimi, LENGTH(INTERSECTION(a.wkb_geometry, b.wkb_geometry)) AS raja FROM kunnat01 AS a, kunnat01 AS b WHERE a.nimi = Helsinki AND TOUCHES(a.wkb_geometry, b.wkb_geometry) ORDER BY b.nimi; nimi raja ---------------------------+------------------ Espoo 10501.3961662369 Sipoo 2544.35931429806 Vantaa 19034.0488094046 (3 rows)
Sijainti- ja ominaisuustiedon yhdistäminen Helsinkiä lähin keskustaenemmistöinen kunta SELECT b.nimi, DISTANCE(a.wkb_geometry, b.wkb_geometry)/1000 AS etäisyys, vaalit96.keskusta FROM kunnat01 AS a, kunnat01 AS b, vaalit96 WHERE a.nimi = Helsinki AND b.nimi = vaalit96.kunta AND vaalit96.keskusta > 50 AND DISTANCE(a.wkb_geometry, b.wkb_geometry) = (SELECT MIN(DISTANCE(a.wkb_geometry, b.wkb_geometry)) FROM kunnat01 AS a, kunnat01 AS b, vaalit96 WHERE a.nimi = Helsinki AND b.nimi = vaalit96.kunta AND vaalit96.keskusta > 50); nimi etäisyys keskusta ---------------------------+-----------------+---------- Artjärvi 66.399075294766 55.55 (1 row)
Laskentaa ominaisuus- ja sijaintitiedoilla Kunnat, joissa eniten julkisia teitä (tie-m / km2) SELECT kunnat01.nimi, autoilu.tiet / AREA(kunnat01.wkb_geometry)*1e9 AS tietiheys, tiet, area(kunnat01.wkb_geometry)/1e6 AS km2 FROM kunnat01, autoilu WHERE kunnat01.nimi = autoilu.kunta AND autoilu.tiet/area(kunnat01.wkb_geometry) > 7.5e-7 ORDER BY autoilu.tiet/area(kunnat01.wkb_geometry) DESC; nimi tietiheys tiet km2 ---------------------------+------------------+------+------------------ Piikkiö 929.445534809963 73 78.54145 Vantaa 903.257125077235 222 245.777192160004 Lemu 880.881351154542 30 34.0568 Merimasku 870.754860737831 26 29.85915 Mietoinen 844.530290806328 66 78.14995 Kiikoinen 774.420378614123 90 116.21595 Nurmijärvi 767.768637204936 277 360.785771360002 Sipoo 759.266316190912 219 288.436343519991 (8 rows)
Laskentaa ominaisuus- ja sijaintitiedoilla Kuinka tiheään riviin Ylihärmän puukkojunkkari-ikäiset miehet saisi naapurikuntien vastaisille rajoille SELECT b.nimi, LENGTH(INTERSECTION(a.wkb_geometry, b.wkb_geometry))*100 / (a.miehet*(100-alle15-yli65)) AS vali FROM kunnat01 AS a, kunnat01 AS b, vaesto WHERE TOUCHES(a.wkb_geometry, b.wkb_geometry) AND a.nimi=vaesto.kunta AND a.nimi= Ylihärmä ORDER BY b.nimi; nimi vali ---------------------------+------------------ Alahärmä 12.9419119118252 Isokyrö 2.12696549439192 Kauhava 9.45753479978232 Lapua 7.74199407374424 Vöyri 14.7589267421131 Ylistaro 18.3319565482419 (6 rows)
Paikkakohteen luominen Piste: koordinaatit PointFromText( POINT(X Y), SRID) Murtoviiva: pääte- ja kulmapisteet LinestringFromText( LINESTRING(X Y, X Y... ), SRID) Monikulmio: reunaviiva ja reiät AreaFromText( POLYGON((X Y, X Y... )... ), SRID) Yhtenäiskoordinaatiston SRID-tunniste 2393 Peruskoordinaatiston kaistojen 1 4 SRID 2391 2394
Pistekohteen luominen Lintujen pesimävarmuus ruuduissa, jotka ovat 10 km säteellä Oulun keskustasta SELECT x, y, silkkiuikku, hernekerttu FROM linnut, kunnat01 WHERE DISTANCE(POINTFROMTEXT( POINT( x y ), 2393), CENTROID(wkb_geometry)) < 10000 AND nimi= Oulu ; x y silkkiuikku hernekerttu -----------+-----------+-------------+------------- 3435000.0 7205000.0 0 2 3445000.0 7205000.0 3 2 3435000.0 7215000.0 3 2 3445000.0 7215000.0 1 1
Monikulmion luominen Oulun sen osan pinta-ala, joka osuu silkkiuikun varmoihin pesimäruutuihin SELECT SUM(AREA(INTERSECTION(POLYFROMTEXT( POLYGON(( x-5000 y-5000, x-5000 y+5000, x+5000 y+5000, x+5000 y-5000, x-5000 y-5000 )), 2393), wkb_geometry)))/1000000 AS km2 FROM linnut, kunnat01 WHERE silkkiuikku=3 AND nimi= Oulu ; km2 ------------------ 236.754539348138 (1 row)
Sijainti- ja ominaisuustiedon yhdistäminen, osa 2 Väkiluvultaan suurimmat kunnat, joiden keskipisteen lähellä silkkiuikku pesii SELECT nimi, yht AS vakiluku FROM kunnat01, linnut WHERE DISTANCE(CENTROID(wkb_geometry), POINTFROMTEXT( POINT( x y ), 2393)) < 5000 AND silkkiuikku=3 ORDER BY vakiluku DESC LIMIT 5; nimi vakiluku ---------------------------+---------- Espoo 213271 Tampere 195468 Turku 172561 Oulu 120753 Lahti 96921 (5 rows)
Indeksit tietokannassa Tietokantahaku voi olla raskas operaatio Tehostamiseen indeksirakenteita Teksti- ja numeromuotoisen tiedon indeksointi CREATE INDEX nimi_i ON kunnat01 USING BTREE(nimi); Sijaintitiedon indeksointi CREATE INDEX sijainti_i ON kunnat01 USING GIST(wkb_geometry); Indeksin poistaminen DROP INDEX nimi_i;
Muuta hyödyllistä Hakutulos uuteen tauluun SELECT sarakkeet INTO uusi taulu WHERE... ; Hakutulos olemassaolevaan tauluun INSERT INTO taulu (SELECT... ); Hakutulokset tiedostoon \o tiedosto.txt Komennot tiedostosta \i tiedosto.sql Apua SQL-komennoista: \h komento PostgreSQL:n komentotulkista: \?