Vill du ha det här bättre förklarat så skall du kika på filmerna från PostGIS Day i St.Louis som du kan hitta listade på https://info.crunchydata.com/stl-postgis-day-2019-presentations. Kika speciellt på Paul Ramseys presentationer.
Även små enkla kommandon kan ta dig väldigt långt.
Om du sedan arbetar med GIS som enkelt integrerar SQL i programmet, så blir det så mycket enklare. Men SQL kan faktiskt användas helt utan GIS, eller ens ett grafiskt gränssnitt.
Med PostgreSQL och PostGIS så kan man använda psql för att logga in på servern.
psql -d databasnamn -U användare -W
Tillägget -W tvingar dig att ange ett lösenord för att ansluta, vilket är lämpligt om din användare har ett lösenord…
I PostGIS kan man sedan lista alla tabeller i alla scheman med kommandot
\dt *.*
Det kan vara på sin plats att nämna att SQL är ett standardiserat språk med många dialekter. Anslutningar till databaserna är däremot helt beroende av vilken ”databasmotor” som används. Kommandona ovan är relevanta för PostgreSQL. För MS SQL, Oracle m.fl. så kopplar man upp sig på andra sätt.
Åter till SQL. Jag kommer här att använda PostGIS SQL, vilket skiljer sig något från exempelvis MS SQL och ännu lite mera mot Oracle SQL (lyssna på vad Paul Ramsey tycker om Oracle SQL).
När man använder SQL så är man ofta beroende av vilken version av databas man använder, och i fallet med PostGIS så använder man externa bibliotek för att hantera väldigt mycket funktionalitet. Det kan därför vara bra att kolla vilka versioner av olika bibliotek man har i sin databas.
geodata=# SELECT postgis_full_version();
Min lokala PostGIS databas som jag kör på datorn jag skriver detta inlägg på är inte den senaste, så jag har exempelvis PROJ 5.2 och GDAL 2.4, vilket innebär en del begränsningar.
geodata=# SELECT namn FROM testdata.punkter; namn -------------- adam bertil adam bertil cesar (5 rader)
Ovanstående kommando listar alla värden i kolumnen ”namn” i min tabell ”punkter” som finns i schemat ”testdata”. Det är en punkttabell med bara fem punkter, vilket kan vara en lämplig storlek att börja experimentera lite med för att testa grundläggande funktioner.
geodata=# select avg(antal) from testdata.punkter; avg ----------------------- 6.2000000000000000 (1 rad)
Ovanstående kommando beräknar medelvärdet i kolumnen ”antal” från samma tabell. Observera att det inte spelar någon roll om du använder stora eller små bokstäver för dina SQL kommandon, men det blir lite tydligare i text om du gör det.
geodata=# SELECT avg(antal) FROM testdata.punkter WHERE namn='adam'; avg ------------------- 3.5000000000000000 (1 rad)
Man kan även lägga till villkor av olika slag. I kommandot ovan beräknas medelantal för alla rader med namnet ”adam”.
geodata=# \dt testdata.* Lista med relationer Schema | Namn | Typ | Ägare ----------+-----------+--------+-------- testdata | polygoner | tabell | klakar testdata | punkter | tabell | klakar (2 rader)
I mitt schema testdata så har jag även en tabell med polygoner som praktiskt heter just ”polygoner”. Med SQL så kan jag kontrollera hur många av mina punkter som ligger i någon av dessa polygoner.
geodata=# SELECT count(*) FROM
geodata-# testdata.punkter AS pt,
geodata-# testdata.polygoner AS po
geodata-# WHERE st_intersects(pt.geom, po.geom);
count
3
(1 rad)
I takt med att uttrycken blir mer komplicerade så kan man strukturera kommandona en del, och exempelvis dela upp dessa på flera rader. Ett kommando är nämligen inte avslutat förrän man matar in ett semikolon.
I uttrycket ovan så använder jag data från två tabeller och för att göra det lite enklare att skriva uttrycken så ”döper” jag referenserna till de båda tabellerna med kommandot ”AS”. Det blir sedan lite enklare att referera till dessa båda tabeller i uttrycket senare. Eller tidigare i uttrycket för den delen…
geodata=# SELECT pt.namn, po.namn FROM testdata.punkter AS pt, testdata.polygoner AS po WHERE st_intersects(pt.geom, po.geom); namn | namn --------+------ adam | röd bertil | blå cesar | blå (3 rader)
Det går nämligen att referera till dessa namn innan de är deklarerade. I uttrycket ovan så hämtar jag värdet från namnkolumnen i punktlagret och värdet i namnkolumnen för de polygoner som de finns i till en tabell.
Det går att göra det här betydligt mycket mera komplext och för PostGIS så finns det hundratals kommandon och funktioner man kan använda. Om det sedan inte räcker så kan man lägga till extensions som pgRouting, för att skapa beräkningar med nätverk.
En del svar man är ute efter är dock inte naturliga att presentera i tabellform vid en terminalprompt. Om jag exempelvis vill se var tusenmetersbufferten runt mina punkter finns, så blir det enklare i QGIS.

I databashanteraren i QGIS så kan man öppna ett SQL-fönster när man anslutit till en databas.
Här kan man skriva in samma SQL kommandon som tidigare och få svar i tabellform precis som tidigare. Här skall man däremot av någon anledning inte avsluta kommandot med semikolon…
Skillnaden är att här kan man även läsa in ett resultat som ett lager i QGIS. Ange bara vad som är geometrikolumnen och ge lagret ett namn, sedan läser man in det med knappen ”Load”.
Jag avslutar med ett kommando som skapar polygoner som representerar den del av polygonlagret som ligger inom 3’000 meter från en av punkterna.
SELECT st_intersection( ST_BUFFER(pt.geom,3000), po.geom) FROM testdata.punkter AS pt, testdata.polygoner AS po WHERE st_intersects(pt.geom, po.geom)
I kommandot så hämtas den överlappande (st_intersection) delen av polygoner och 3’000 meters buffrade punkter, men bara för punkter som redan från början ligger i en polygon. Resultatet i bilden nedan.

Om jag nu skulle få för mig att flytta in en punkt i en polygon genom att redigera punktlagret i databasen. Så kommer SQL lagret att känna av detta och beräkna om resultatet vid nästa uppdatering av kartan (panorera eller zooma).
En av fördelarna med SQL i PostGIS är att många beräkningar är extremt snabba. Långt ifrån allt går fort, men att exempelvis fråga databasen efter en specifik polygon som uppfyller ett specifikt villkor är väldigt snabbt.
select * from testdata.polygoner order by st_area(geom) desc limit 1
Ovanstående skapar ett dynamiskt urvalslager som hela tiden kommer att visa mig vilken av mina polygoner som har störst area.

Ett annat exempel på en mycket snabb databasfråga är att lista Sveriges tre största (till ytan) kommuner, från ett polygonlager i databasen.
geodata=# \timing Tidtagning är på. geodata=# SELECT k.namn_kom, st_area(k.geom) geodata-# FROM testdata.kommuner AS k geodata-# ORDER BY st_area(k.geom) DESC geodata-# LIMIT 3; namn_kom | st_area -----------+------------------ Kiruna | 20703223744.383 Jokkmokk | 19466420026.4287 Gällivare | 16946118322.6018 (3 rader) Tid: 12,411 ms
Här har jag ”slagit på” tidtagning i psql programmet med ”\timing”, vilket ger mig en indikation på hur snabbt svaret beräknades. 12 millisekunder är inte så tokigt.
Mer komplicerade kommandon kan ta lite längre tid. Varför inte beräkna de tre ”rundaste” kommunerna i landet? (Jag väljer att jämföra arean för kommunerna med arean på den minsta omslutande cirkeln.)
geodata=# SELECT k.namn_kom AS namn, (st_area(k.geom)/st_area(st_minimumboundingcircle(k.geom))) AS rundhet geodata-# FROM testdata.kommuner AS k geodata-# ORDER by (st_area(k.geom)/st_area(st_minimumboundingcircle(k.geom))) DESC geodata-# LIMIT 3; namn | rundhet ------------+------------------- Halmstad | 0.698577790563087 Ulricehamn | 0.673303342866772 Tidaholm | 0.672182134126454 (3 rader) Tid: 32465,911 ms (00:32,466)
Här tog det lite tid bland annat eftersom jag inte skapat ett rumsligt index för kommuntabellen. Det som tar mest tid är dock sorteringen och där hjälper inte ett index speciellt mycket. Index är däremot väldigt viktiga för att skapa snabbhet för väldigt många funktioner. Det går även att köra ett motsvarande kommando i QGIS för att skapa ett polygonlager med alla kommuners ”cirklar” så att det blir mera visuellt att jämföra dessa, och då behöver jag inte ”sortera”.
Ju snabbare funktionerna är desto mer lämpliga är de att använda som dynamiska lager i exempelvis QGIS. Om ett kommando börjar ta många sekunder att beräkna så kommer man snabbt att bli otålig när man behöver vänta på att kartan skall ritas ut så fort man panorerar kartan lite. I dessa fall är det bättre att spara det genererade lagret som ett nytt permanent lager. Speciellt om man skall skapa en mer permanent kartprodukt…

Om du sedan inte har tillgång till en PostGIS databas, då skulle jag nog rekommendera att du fixar det. Med Linux är det enkelt, men jag vet att många använder Windows och då kan det krävas lite mera, men det borde inte vara allt för krångligt. Om man har en server online eller en egen fysisk dator så kan det vara en väg att snabbt ”snurra upp” en PostgreSQL databas och köra SQL kommandot ”CREATE EXTENSION postgis;”. Svårare än så behöver det inte vara med en modern PostgreSQL installation. Sedan är det förstås mer som behöver fixas med användare, scheman, databaser och tabeller, men det är en del av det roliga med databaser.