7 Harjoitus 6: Spatiaaliset relaatiot
Harjoituksen sisältö - Harjoitellaan PostGISin spatiaalisiin relaatioihin liittyvien funktioiden käyttöä.
Harjoituksen tavoite - Harjoituksen jälkeen opiskelija tuntee PostGISin spatiaalisen relaatioihin liittyvät funktiot ja osaa niiden avulla tehdä yksinkertaisia analyysejä.
7.0.1 Valmistautuminen
Avaa pgAdmin selaimeen ja kirjaudu sisään. Avaa Query Tool (Valitse trainingdatabase -> Ylhäältä Tools -> Query Tool).
7.0.2 Käytettäviä funktioita
Tässä harjoituksessa hyödynnetään ainakin näitä funktioita:
| PostGIS-funktio | Toiminta |
|---|---|
| ST_Contains(geometry A, geometry B) | Palauttaa “TOSI”, jos A sisältää B:n |
| ST_Crosses(geometry A, geometry B) | Palauttaa “TOSI”, jos A leikkaa B:tä |
| ST_Disjoint(geometry A , geometry B) | Palauttaa “TOSI”, jos geometriat eivät leikkaa toisiaan |
| ST_Distance(geometry A, geometry B) | Palauttaa geometrioiden välisen minimietäisyyden |
| ST_DWithin(geometry A, geometry B, radius) | Palauttaa “TOSI”, jos A on lähempänä B:tä kuin annettua etäisyyttä |
| ST_Equals(geometry A, geometry B) | Palauttaa “TOSI”, jos A on sama kuin B |
| ST_Intersects(geometry A, geometry B) | Palauttaa “TOSI”, jos A leikkaa B:tä |
| ST_Overlaps(geometry A, geometry B) | Palauttaa “TOSI”, jos A ja B ovat päällekkäin, mutteivät kuitenkaan toistensa sisäpuolella |
| ST_Touches(geometry A, geometry B) | Palauttaa “TOSI”, jos A:n reuna koskettaa B:tä |
| ST_Within(geometry A, geometry B) | Palauttaa “TOSI”, jos A on B:n sisäpuolella |
7.1 Harjoitus 6.1
Etsitään ne kunnat, joissa on lentokenttä:
SELECT
a.kunta_ni1
FROM
nlsfi.hallintoalue a, nlsfi.lentokenttapiste b
WHERE
ST_Contains(a.wkb_geometry, b.wkb_geometry);Huomaa kuinka kirjaimia a ja b käytetään kyselyssä aliaksina, eli sarakkeiden korvaavina niminä. Aliasten käyttö helpottaa varsinkin pitkien kyselyiden tulkitsemista ja kirjoittamista. Voit lukea lisää aliaksista esimerkiksi täältä: postgresql-alias.
Montako lentokenttää Suomessa on?
SELECT
...
FROM
...-- Millä funktiolla voit laskea tietueiden määrän?
SELECT
funktio(id)
FROM
nlsfi.taulu;
-- Täydennä oikea tauluSELECT
count(ogc_fid)
FROM
nlsfi.lentokenttapiste;Jos lisäät SELECT-komentoon parametrin DISTINCT, saat selville kuinka monta lentokentällistä kuntaa Suomessa on.
SELECT
FROM
(SELECT DISTINCT
FROM
WHERE
ST_Contains(..., ...));-- käytä sisäkkäistä kyselyä
-- sisäkkäiselle kyselyllä annetaan alias
SELECT
funktio(kunta_distinct)
FROM
(SELECT DISTINCT
a.kunta_ni1 as kunta_distinct
FROM
nlsfi.hallintoalue a, nlsfi.lentokenttapiste b
WHERE
sisältää(... , ... ));
-- Millä PostGIS- funktiolla voit tarkastaa onko geometria b geometrian a sisällä?SELECT
count(kunta_distinct)
FROM
(SELECT DISTINCT
a.kunta_ni1 as kunta_distinct
FROM
nlsfi.hallintoalue a, nlsfi.lentokenttapiste b
WHERE
ST_Contains(a.wkb_geometry, b.wkb_geometry)) as DistincKunta;7.2 Harjoitus 6.2
Missä Suomen kunnissa on kaksi lentokenttää?
SELECT ...-- Vaihtoehto 1
-- Käytä CTE:tä
WITH apm AS (
SELECT DISTINCT
a.kunta_ni1, COUNT(...) OVER(PARTITION BY ...) AS CountAirports
FROM
nlsfi.hallintoalue a, nlsfi.lentokenttapiste b
WHERE
sisältää(a.wkb_geometry, b.wkb_geometry)
ORDER BY
CountAirports DESC
)
-- tarkastele tuloksia:
SELECT
kunta_ni1 as "Municipality", countairports AS "Count of Airports"
FROM
apm
WHERE
CountAirports = 2;-- Vaihtoehto 2
SELECT
a.kunta_ni1 as "Kunta", count(...) as "Lkm"
FROM
nlsfi.hallintoalue a, nlsfi.lentokenttapiste b
WHERE
sisältää(a.wkb_geometry, b.wkb_geometry)
GROUP BY
a.kunta_ni1
HAVING count(...) = ...;
-- täydennä tyhjät kohdat. Valitse oikea PostGIS- funktioPerusteellinen ratkaisuvaihtoehto:
WITH apm AS (
SELECT DISTINCT
a.kunta_ni1, COUNT(a.kunta_ni1) OVER(PARTITION BY a.kunta_ni1) AS CountAirports
FROM
nlsfi.hallintoalue a, nlsfi.lentokenttapiste b
WHERE
ST_Contains(a.wkb_geometry, b.wkb_geometry)
ORDER BY
CountAirports DESC
)
SELECT
kunta_ni1 as "Municipality", countairports AS "Count of Airports"
FROM
apm
WHERE
CountAirports = 2;Pelkistetympi ratkaisuvaihtoehto:
SELECT
a.kunta_ni1 as "Kunta", count(*) as "Lkm"
FROM
nlsfi.hallintoalue a, nlsfi.lentokenttapiste b
WHERE
ST_Contains(a.wkb_geometry, b.wkb_geometry)
GROUP BY
a.kunta_ni1
HAVING count(*) = 2;Suorita ao. SQL-lause. Mitä sillä saadaan selville?
SELECT
ST_ASText(a.wkb_geometry), a.ogc_fid
FROM
nlsfi.lentokenttapiste a, nlsfi.lentokenttapiste b
WHERE
ST_Equals(a.wkb_geometry,b.wkb_geometry) AND a.ogc_fid <> b.ogc_fid;SQL- kysely palauttaa ne tietueet, joiden geometria on identtinen, mutta id eri.
7.3 Harjoitus 6.3
Etsitään ne kunnat, joissa ei ole rautatietä:
SELECT
b.kunta_ni1
FROM
(SELECT
ST_union(wkb_geometry) as wkb_geometry
FROM
nlsfi.rautatieviiva) as a, nlsfi.hallintoalue b
WHERE
ST_Disjoint(a.wkb_geometry, b.wkb_geometry);7.4 Harjoitus 6.4
Etsitään kolme lähintä lentokenttää.
K Nearest Neighbours -menetelmällä (KNN) voidaan hakea kolme lähimpänä jonkin kunnan keskustaa sijaitsevaa lentokenttää.
WITH forssa AS
(SELECT
wkb_geometry
FROM
nlsfi.hallintoalue
WHERE
kunta_ni1 = 'Forssa')
SELECT
*, round(ST_Distance(forssa.wkb_geometry, a.wkb_geometry)/1000) as "km"
FROM
nlsfi.lentokenttapiste a, forssa
ORDER BY
forssa.wkb_geometry <-> a.wkb_geometry
LIMIT 3;Sama ongelma voidaan ratkaista myös ilman KNN-algoritmia:
SELECT
*, round(ST_Distance(wkb_geometry,(
SELECT ST_Centroid(wkb_geometry)
FROM
nlsfi.hallintoalue
WHERE
kunta_ni1 ='Forssa'))/1000) as etaisyys
FROM
nlsfi.lentokenttapiste
ORDER by
etaisyys
LIMIT 3;Miksi saadut tulokset poikkeavat toisistaan?
7.5 Harjoitus 6.5
Mitkä ovat Kuopion naapurikunnat?
SELECT
b.kunta_ni1
FROM
(SELECT
kunta_ni1, wkb_geometry
FROM
nlsfi.hallintoalue
WHERE
kunta_ni1 = 'Kuopio') a, nlsfi.hallintoalue b
WHERE
ST_Touches(a.wkb_geometry, b.wkb_geometry);7.6 Harjoitus 6.6
Etsitään ne tieviivat, jotka leikkaavat kuntarajoja:
SELECT
a.tienumero, a.wkb_geometry
FROM
nlsfi.tieviiva a, nlsfi.hallintoalue b
WHERE
ST_Crosses(a.wkb_geometry, b.wkb_geometry);Tulosten visualisoimiseksi, voit muodostaa uuden skeeman (tmp). Voit luoda uuden taulun, johon viet tuloksen. Visualisointiin voit käyttää esimerkiksi QGIS-ohjelmistoa. Voit muodostaa tuloksesta myös näkymän (view), mutta muista kuitenkin lisätä mukaan yksilöivä tunnus (id) sekä myös DISTINCT, jotta yksilöivät tunnukset pysyvät yksilöivinä.
CREATE SCHEMA IF NOT EXISTS tmp;DROP TABLE IF EXISTS tmp.crossroads;
CREATE TABLE tmp.crossroads AS
(
SELECT
a.tienumero, a.wkb_geometry
FROM
nlsfi.tieviiva a, nlsfi.hallintoalue b
WHERE
ST_Crosses(a.wkb_geometry, b.wkb_geometry)
);DROP VIEW IF EXISTS tmp.view_crossroads;
CREATE VIEW tmp.view_crossroads AS
(
SELECT DISTINCT
a.tienumero, a.wkb_geometry, a.ogc_fid
FROM
nlsfi.tieviiva a, nlsfi.hallintoalue b
WHERE
ST_Crosses(a.wkb_geometry, b.wkb_geometry)
);Kumman luominen oli nopeampaa: taulun vai näkymän?
Entä käyttö QGISissä? Miksi?
7.7 Harjoitus 6.7
Lasketaan minimietäisyydet lentoasemilta lähimmälle rautatielle:
SELECT
a.ogc_fid, MIN(ST_Distance(a.wkb_geometry, b.wkb_geometry)) as "dist"
FROM
nlsfi.lentokenttapiste a, nlsfi.rautatieviiva b
GROUP BY
a.ogc_fid
ORDER BY
dist;