SQL Academy · Lektion

Avstånd och närmaste grannar

Hitta det som finns nära.

Lektion 2 av 413 steg

Avstånd och närmaste grannar är en gratis lektion i SQL Academy på CoddyKit. Detta är lektion 2 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för SQL Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i SQL Academy innehåller totalt 4 lektioner.

Vad är spatialt avstånd

I geodatabaser är avstånd den uppmätta separationen mellan två geografiska platser. PostGIS tillhandahåller kraftfulla funktioner för att beräkna avstånd mellan punkter, linjer, polygoner och andra geometrityper.

Genom att förstå avståndsfrågor kan ni besvara frågor som: Vilken restaurang ligger närmast mig? eller Vilka kunder finns inom 5 km från vårt lager?

Funktionen ST_Distance

ST_Distance(geom_a, geom_b) returnerar det minsta avståndet mellan två geometry-objekt. Som standard är resultatet, när vanliga geometry-typer används, uttryckt i samma enheter som koordinatreferenssystemet (vanligtvis grader för EPSG:4326).

För att få meningsfulla resultat i meter bör ni använda geography-typer eller projicera om era data.

SELECT ST_Distance(
  ST_MakePoint(28.9784, 41.0082)::geography,
  ST_MakePoint(29.0100, 41.0200)::geography
) AS distance_meters;

Skapa en exempeltabell

Vi skapar en enkel tabell över platser med geografiska koordinater. Vi använder typen geography så att alla avståndsberäkningar automatiskt returnerar meter — ingen manuell projektion behövs.

Tabellen ska innehålla kaféer i en stad, där varje kafé har ett namn och en plats som lagras som en punkt.

CREATE TABLE cafes (
  id SERIAL PRIMARY KEY,
  name TEXT NOT NULL,
  location GEOGRAPHY(Point, 4326)
);

INSERT INTO cafes (name, location) VALUES
  ('Cafe Alpha',   ST_MakePoint(28.9784, 41.0082)::geography),
  ('Cafe Beta',    ST_MakePoint(28.9900, 41.0150)::geography),
  ('Cafe Gamma',   ST_MakePoint(29.0100, 41.0200)::geography),
  ('Cafe Delta',   ST_MakePoint(28.9650, 40.9980)::geography),
  ('Cafe Epsilon', ST_MakePoint(29.0250, 41.0350)::geography);

Hitta avståndet från en fast punkt

När ni har platsdata kan ni beräkna avståndet från varje rad till en referenspunkt. Här beräknar vi hur långt varje kafé ligger från en användare som befinner sig vid koordinaterna (28.9800, 41.0100).

Resultatet anges i meter eftersom vi använde typen geography.

SELECT
  name,
  ROUND(
    ST_Distance(
      location,
      ST_MakePoint(28.9800, 41.0100)::geography
    )::NUMERIC
  ) AS distance_m
FROM cafes
ORDER BY distance_m;

Hitta närmaste granne

Om ni vill hitta den enda närmaste platsen till en given punkt sorterar ni efter avstånd och hämtar endast en rad med LIMIT 1. Detta är den klassiska frågan för närmaste granne.

Detta mönster är mycket vanligt i platsbaserade applikationer: för att hitta närmaste butik, läkare eller hållplats.

SELECT
  name,
  ROUND(
    ST_Distance(
      location,
      ST_MakePoint(28.9800, 41.0100)::geography
    )::NUMERIC
  ) AS distance_m
FROM cafes
ORDER BY location <-> ST_MakePoint(28.9800, 41.0100)::geography
LIMIT 1;

Operatorn <-> för närmaste granne

PostGIS tillhandahåller operatorn <-> (KNN — K närmaste grannar), som kan använda index. Till skillnad från ST_Distance i en ORDER BY-sats kan <-> använda ett GiST-spatialt index för att slippa genomsöka varje rad.

Föredra alltid <-> i ORDER BY när ni behöver hämta närmaste grannar effektivt. Skapa ett index som detta för att stödja operatorn:

CREATE INDEX ON cafes USING GIST (location);

SELECT
  name,
  ROUND(
    ST_Distance(
      location,
      ST_MakePoint(28.9800, 41.0100)::geography
    )::NUMERIC
  ) AS distance_m
FROM cafes
ORDER BY location <-> ST_MakePoint(28.9800, 41.0100)::geography
LIMIT 5;

Filtrera efter avstånd (ST_DWithin)

ST_DWithin(geom_a, geom_b, distance) returnerar TRUE när två geometrier ligger inom ett angivet avstånd från varandra. För geography-typer anges avståndet i meter.

Detta är effektivare än ST_Distance(...) < radius i en WHERE-sats eftersom ST_DWithin kan använda index och avslutar tidigt så snart villkoret är uppfyllt.

SELECT
  name,
  ROUND(
    ST_Distance(
      location,
      ST_MakePoint(28.9800, 41.0100)::geography
    )::NUMERIC
  ) AS distance_m
FROM cafes
WHERE ST_DWithin(
  location,
  ST_MakePoint(28.9800, 41.0100)::geography,
  2000
)
ORDER BY distance_m;

De N närmaste med en radiebegränsning

Ett vanligt produktionsmönster kombinerar ST_DWithin som förfilter med sortering med <->. Kontrollen med ST_DWithin använder det spatiala indexet för att snabbt sortera bort rader långt bort. Därefter sorteras de återstående kandidaterna efter exakt avstånd.

På så sätt får ni mycket effektivt fram de N närmaste platserna inom en maximal radie.

SELECT
  name,
  ROUND(
    ST_Distance(
      location,
      ST_MakePoint(28.9800, 41.0100)::geography
    )::NUMERIC
  ) AS distance_m
FROM cafes
WHERE ST_DWithin(
  location,
  ST_MakePoint(28.9800, 41.0100)::geography,
  5000
)
ORDER BY location <-> ST_MakePoint(28.9800, 41.0100)::geography
LIMIT 3;

Avstånd mellan två tabeller

Ni kan beräkna avstånd mellan rader i två olika tabeller med hjälp av en JOIN i kombination med ST_Distance. Det är användbart för matchning, till exempel när varje kund ska kopplas till sitt närmaste lager eller varje incident till närmaste sjukhus.

Nedan hittar vi det närmaste kaféet för varje användare i en tabell med namnet users med hjälp av en lateral join — ett kraftfullt PostgreSQL-mönster för underfrågor per rad.

SELECT
  u.username,
  c.name AS nearest_cafe,
  ROUND(ST_Distance(u.location, c.location)::NUMERIC) AS distance_m
FROM (
  VALUES
    ('alice', ST_MakePoint(28.9810, 41.0095)::geography),
    ('bob',   ST_MakePoint(29.0200, 41.0300)::geography)
) AS u(username, location)
CROSS JOIN LATERAL (
  SELECT name, location
  FROM cafes
  ORDER BY location <-> u.location
  LIMIT 1
) c;

Formatera avståndsresultat

Råa avstånd i meter kan vara svåra att läsa. Ni kan formatera dem som kilometer eller lägga till lättbegripliga etiketter med hjälp av CASE-uttryck och strängformatering. Här är en fråga som visar avstånd i meter för korta avstånd och kilometer för längre avstånd.

SELECT
  name,
  CASE
    WHEN ST_Distance(location, ST_MakePoint(28.9800, 41.0100)::geography) < 1000
    THEN ROUND(ST_Distance(location, ST_MakePoint(28.9800, 41.0100)::geography)::NUMERIC)
         || ' m'
    ELSE ROUND((ST_Distance(location, ST_MakePoint(28.9800, 41.0100)::geography) / 1000.0)::NUMERIC, 2)
         || ' km'
  END AS formatted_distance
FROM cafes
ORDER BY location <-> ST_MakePoint(28.9800, 41.0100)::geography;

Tilldela en rangordning baserat på avstånd

Fönsterfunktioner som RANK() och ROW_NUMBER() passar perfekt ihop med avståndsfrågor. Ni kan tilldela varje plats en närhetsrankning i förhållande till en användare, vilket är användbart när ni bygger rangordnade rekommendationslistor eller sökresultat sorterade efter närhet.

SELECT
  name,
  ROUND(
    ST_Distance(
      location,
      ST_MakePoint(28.9800, 41.0100)::geography
    )::NUMERIC
  ) AS distance_m,
  ROW_NUMBER() OVER (
    ORDER BY location <-> ST_MakePoint(28.9800, 41.0100)::geography
  ) AS proximity_rank
FROM cafes;

Kunskapskontroll

Kontrollera er förståelse av avståndsfrågor och sökningar efter närmaste grannar i PostGIS.

Sammanfattning av lektionen

I den här lektionen har ni lärt er att arbeta med spatiala avstånd och frågor för närmaste granne i PostGIS:

  • ST_Distance beräknar det exakta avståndet mellan två geometrier. Använd typen geography för att automatiskt få resultat i meter.
  • ST_DWithin filtrerar effektivt rader inom en radie med hjälp av det spatiala indexet — föredra den framför ST_Distance < radius i WHERE-satser.
  • <->-operatorn (KNN) i ORDER BY kan använda index och är det snabbaste sättet att hämta de N närmaste grannarna.
  • Kombinera ST_DWithin som förfilter med sortering med <-> för de effektivaste frågorna av typen top-N inom en radie.
  • CROSS JOIN LATERAL gör det möjligt att hitta den närmaste matchningen från en annan tabell rad för rad.
  • Fönsterfunktioner som ROW_NUMBER() kan tilldela närhetsrankningar till era avståndssorterade resultat.

Dessa mönster utgör grunden för platsbaserade funktioner i verkliga applikationer.

Gratis att börja

Lär dig SQL med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
46
Lektioner
183

Vanliga frågor

Är lektionen ”Avstånd och närmaste grannar” gratis?

Ja – hela texten till ”Avstånd och närmaste grannar” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i SQL Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i SQL Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Avstånd och närmaste grannar”?

Hitta det som finns nära. Ni övar på SQL Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig SQL Academy?

Du behöver inga förkunskaper. Utbildningen i SQL Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 2 av 4.

Hur lång tid tar lektionen ”Avstånd och närmaste grannar”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här SQL Academy-lektionen?

Ja. Varje SQL Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Spatiala datatyper
  2. Avstånd och närmaste grannar
  3. Spatiala joiner och inneslutning
  4. Spatiala index (GiST)
← Tillbaka till SQL Academy