📖 Planeta u bazi podataka
SQL Server nije samo za brojeve i tekst. On podržava Spatial Data (prostorne podatke) koji se koriste u GPS aplikacijama, sistemima za dostavu (pronalaženje najbližeg kurira) ili u arhitekturi. Svi ovi podaci se zasnivaju na objektno-orijentisanim tipovima koji dolaze iz OGC (Open Geospatial Consortium) standarda.
🧩 Geography vs Geometry
1. GEOGRAPHY (Okrugla zemlja)
Koristi Latituda/Longituda koordinate. Uzima u obzir zakrivljenost zemlje (ellipsoidal model). Kada računate udaljenost Sarajevo-London, Geography će dati tačan rezultat "preko horizonta".
2. GEOMETRY (Ravna površina)
Koristi X/Y koordinate na ravni (planar model). Idealno za tlocrte zgrada, mape igara ili bilo šta što staje na ravan list papira.
📏 Well-Known Text (WKT)
Podatke u bazu unosimo pomoću standardizovanog tekstualnog formata:
POINT(18.413 43.856)- Čvor (npr. lokacija grada).LINESTRING(0 0, 5 5, 10 0)- Putanja ili granica.POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))- Površina (npr. granica države ili objekta).
DECLARE @Sarajevo GEOGRAPHY = geography::STGeomFromText('POINT(18.413 43.856)', 4326);
DECLARE @Mostar GEOGRAPHY = geography::STGeomFromText('POINT(17.807 43.343)', 4326);
-- Udaljenost u metrima
SELECT @Sarajevo.STDistance(@Mostar) / 1000.0 AS Udaljenost_km;
Napomena: 4326 je SRID (Spatial Reference ID) za WGS 84 standard koji koristi GPS.
🔍 Ključne Metode za Prostorne Podatke
SQL Server pruža bogat set metoda za rad sa prostornim podacima. Evo najvažnijih:
Metode za Mjerenje i Računanje
- STDistance(): Računa udaljenost između dva prostorna objekta
- STArea(): Izračunava površinu poligona (u kvadratnim metrima za Geography)
- STLength(): Računa dužinu linije ili perimetar poligona
- STBuffer(metri): Pravi "krug" oko tačke ili proširuje objekat za određenu udaljenost
Metode za Provjeru Relacija
- STIntersects(): Provjerava da li se dva objekta dodiruju ili preklapaju
- STContains(): Provjerava da li jedan objekat sadrži drugi
- STWithin(): Provjerava da li je jedan objekat unutar drugog
- STTouches(): Provjerava da li se objekti dodiruju (ali ne preklapaju)
- STOverlaps(): Provjerava da li se objekti preklapaju
Metode za Konverziju i Konstrukciju
- STGeomFromText(): Kreira prostorni objekat iz WKT stringa
- STAsText(): Konvertuje prostorni objekat u WKT format
- STPoint(): Kreira tačku (POINT) iz koordinata
- STPolygon(): Kreira poligon iz niza tačaka
-- 1. STBuffer - Kreiranje zone oko tačke
DECLARE @Restaurant GEOGRAPHY = geography::STGeomFromText('POINT(18.413 43.856)', 4326);
DECLARE @DeliveryZone GEOGRAPHY = @Restaurant.STBuffer(2000); -- 2km zona
-- @DeliveryZone je sada poligon koji predstavlja krug od 2km oko restorana
-- 2. STIntersects - Provjera da li se objekti preklapaju
DECLARE @UserLocation GEOGRAPHY = geography::STGeomFromText('POINT(18.415 43.857)', 4326);
SELECT
CASE
WHEN @UserLocation.STIntersects(@DeliveryZone) = 1
THEN 'U zoni dostave'
ELSE 'Izvan zone dostave'
END AS StatusDostave;
-- 3. STArea - Računanje površine
DECLARE @CityBoundary GEOGRAPHY = geography::STGeomFromText(
'POLYGON((18.0 43.7, 18.5 43.7, 18.5 44.0, 18.0 44.0, 18.0 43.7))', 4326
);
SELECT @CityBoundary.STArea() / 1000000 AS PovrsinaKm2; -- Površina u km²
-- 4. STContains - Provjera da li grad sadrži tačku
SELECT
CASE
WHEN @CityBoundary.STContains(@Restaurant) = 1
THEN 'Restoran je u gradu'
ELSE 'Restoran je izvan grada'
END AS Lokacija;
-- 5. Kombinovanje metoda - Pronalaženje tačaka u zoni
SELECT
Name,
Location.STDistance(@Restaurant) AS UdaljenostMetri,
Location.STIntersects(@DeliveryZone) AS UZoni
FROM Restaurants
WHERE Location.STIntersects(@DeliveryZone) = 1
ORDER BY Location.STDistance(@Restaurant);
GO
🚀 Spatial Indeksi: Ubrzanje Prostornih Upita
Prostorni upiti mogu biti ekstremno spori na velikim tabelama jer zahtijevaju kompleksne geometrijske izračune. Spatial Index koristi grid sistem (tesselation) da ubrza pretrage.
Kako Spatial Index Radi?
Spatial Index dijeli prostor u grid (mrežu) kvadrata različitih nivoa:
- Level 1: Najgrublji nivo - veliki kvadrati
- Level 2-4: Finiji nivoi - manji kvadrati
- Index čuva: Koji grid kvadrati se preklapaju sa prostornim objektom
-- Kreiranje Spatial Index-a na Geography koloni
CREATE SPATIAL INDEX IX_Restaurants_Location
ON Restaurants(Location)
USING GEOGRAPHY_GRID
WITH (
GRIDS = (LEVEL_1 = MEDIUM, LEVEL_2 = MEDIUM, LEVEL_3 = MEDIUM, LEVEL_4 = MEDIUM),
CELLS_PER_OBJECT = 16
);
GO
-- GRIDS opcije:
-- LOW, MEDIUM, HIGH - gustoća grid-a (HIGH = više kvadrata, precizniji ali veći indeks)
-- CELLS_PER_OBJECT - koliko grid ćelija može jedan objekat zauzeti (default 16)
-- Provjera Spatial Index-a
SELECT
name AS IndexName,
type_desc AS IndexType,
is_spatial AS IsSpatial
FROM sys.indexes
WHERE object_id = OBJECT_ID('Restaurants')
AND is_spatial = 1;
GO
🔑 Best Practices za Spatial Indekse
- Koristite za velike tabele: Spatial indeksi su najkorisniji na tabelama sa 1000+ redova
- GEOGRAPHY_GRID vs GEOMETRY_GRID: Koristite odgovarajući tip ovisno o tipu kolone
- CELLS_PER_OBJECT: Povećajte ako imate velike objekte (npr. države, provincije)
- Grid nivoi: Viši nivoi = precizniji ali veći indeks
🎯 Praktične Vježbe
Vježba 1: Filter za Dostavu Hrane
Imate tabelu Restaurants sa geografskom kolonom Location.
Korisnik se nalazi na koordinati @UserLoc. Pronađite sve restorane u krugu od 2km.
-- Kreiranje tabele sa prostornim podacima
CREATE TABLE Restaurants (
RestaurantID INT PRIMARY KEY IDENTITY(1,1),
Name NVARCHAR(100) NOT NULL,
Location GEOGRAPHY NOT NULL,
CuisineType NVARCHAR(50),
Rating DECIMAL(2,1)
);
GO
-- Kreiranje Spatial Index-a (KRITIČNO za performanse!)
CREATE SPATIAL INDEX IX_Restaurants_Location
ON Restaurants(Location)
USING GEOGRAPHY_GRID
WITH (
GRIDS = (LEVEL_1 = MEDIUM, LEVEL_2 = MEDIUM, LEVEL_3 = MEDIUM, LEVEL_4 = MEDIUM),
CELLS_PER_OBJECT = 16
);
GO
-- Umetanje test podataka
INSERT INTO Restaurants (Name, Location, CuisineType, Rating)
VALUES
('Restoran A', geography::STGeomFromText('POINT(18.413 43.856)', 4326), 'Bosanska', 4.5),
('Restoran B', geography::STGeomFromText('POINT(18.420 43.860)', 4326), 'Italijanska', 4.8),
('Restoran C', geography::STGeomFromText('POINT(18.400 43.850)', 4326), 'Azijska', 4.2);
GO
-- Pronalaženje restorana u krugu od 2km
DECLARE @UserLoc GEOGRAPHY = geography::STGeomFromText('POINT(18.413 43.856)', 4326);
DECLARE @SearchRadius GEOGRAPHY = @UserLoc.STBuffer(2000); -- 2km = 2000 metara
SELECT
Name,
CuisineType,
Rating,
Location.STDistance(@UserLoc) AS UdaljenostMetri,
Location.STDistance(@UserLoc) / 1000.0 AS UdaljenostKm
FROM Restaurants
WHERE Location.STIntersects(@SearchRadius) = 1
ORDER BY Location.STDistance(@UserLoc);
GO
Vježba 2: Pronalaženje Najbližeg Restorana
Pronađite najbliži restoran korisniku bez kreiranja buffer zone.
-- Pronalaženje najbližeg restorana
DECLARE @UserLoc GEOGRAPHY = geography::STGeomFromText('POINT(18.413 43.856)', 4326);
SELECT TOP 1
Name,
CuisineType,
Rating,
Location.STDistance(@UserLoc) / 1000.0 AS UdaljenostKm
FROM Restaurants
ORDER BY Location.STDistance(@UserLoc);
GO
Vježba 3: Provjera da li je Tačka u Poligonu
Kreirajte poligon koji predstavlja granice grada i provjerite da li su restorani u gradu.
-- Kreiranje poligona grada (Sarajevo približno)
DECLARE @CityBoundary GEOGRAPHY = geography::STGeomFromText(
'POLYGON((
18.3 43.8, -- Jugozapad
18.5 43.8, -- Jugoistok
18.5 43.9, -- Sjeveroistok
18.3 43.9, -- Sjeverozapad
18.3 43.8 -- Zatvaranje poligona (mora biti ista kao prva tačka)
))', 4326
);
-- Provjera da li su restorani u gradu
SELECT
Name,
Location.STWithin(@CityBoundary) AS UGradu,
Location.STDistance(@CityBoundary) AS UdaljenostOdGraniceMetri
FROM Restaurants
WHERE Location.STWithin(@CityBoundary) = 1;
GO
✅ Zaključak
Spatial podaci otvaraju vrata za "Location-aware" aplikacije:
- ✅ Razlikujte Geography od Geometry ovisno o skali.
- ✅ SRID 4326 je vaš najbolji prijatelj za rad sa Google Maps koordinatama.
- ✅ Spatial Indexes koriste grid-sistem (tesselation) za ubrzanje pretrage.
📚 Sljedeća Lekcija
U Lekciji 4.4 zaključujemo ovaj modul pričom o BLOB-ovima. Naučićete kako pravilno čuvati slike i dokumente koristeći FILESTREAM.