Notatka
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Microsoft SQL udostępnia dwa typy danych przestrzennych, które można wykorzystać za pomocą sterownika mssql-python. Wybierz typ na podstawie tego, co reprezentują twoje współrzędne:
| Typ | Opis | Przypadek użycia |
|---|---|---|
geography |
Układ współrzędnych kulistej Ziemi | Współrzędne GPS, mapy, wszystko na powierzchni Ziemi. Odległości są w metrach. SRID 4326 (WGS 84) jest standardem dla GPS. |
geometry |
Układ współrzędnych płaskich | Plany pięter, rysunki CAD, światy gier lub dowolny kartezjański układ współrzędnych. Odległości są w jednostkach twojego układu współrzędnych. |
Wstaw dane przestrzenne
Użyj funkcji konstruktora Microsoft SQL, takich jak geography::Point(), lub przekaż ciągi Well-Known Text (WKT).
Dane geograficzne (punkty)
Wstaw punkty geograficzne za pomocą konstruktora punktów z szerokością geograficzną, długością geograficzną i SRID.
import mssql_python
connection_string = "Server=<server>.database.windows.net;Database=AdventureWorks2022;Authentication=ActiveDirectoryDefault;Encrypt=yes"
conn = mssql_python.connect(connection_string)
cursor = conn.cursor()
# Insert a geographic point (longitude, latitude)
# Note: Microsoft SQL uses (longitude, latitude) order
cursor.execute("CREATE TABLE #Locations (Name NVARCHAR(100), GeoLocation GEOGRAPHY)")
cursor.execute("""
INSERT INTO #Locations (Name, GeoLocation)
VALUES (%(name)s, geography::Point(%(lat)s, %(lon)s, 4326))
""", {"name": "Seattle", "lat": 47.6062, "lon": -122.3321})
conn.commit()
Geografia z WKT (Well-Known Text)
Wstaw dane geograficzne w formacie Well-Known Text, który obsługuje punkty, linie łamane i wielokąty.
# Well-Known Text format
wkt_point = "POINT(-122.3321 47.6062)"
wkt_line = "LINESTRING(-122.3321 47.6062, -122.4194 37.7749)"
wkt_polygon = "POLYGON((-122.40 47.60, -122.30 47.60, -122.30 47.65, -122.40 47.65, -122.40 47.60))"
cursor.execute("DROP TABLE IF EXISTS #Locations")
cursor.execute("CREATE TABLE #Locations (Name NVARCHAR(100), GeoLocation GEOGRAPHY)")
cursor.execute("""
INSERT INTO #Locations (Name, GeoLocation)
VALUES (%(name)s, geography::STGeomFromText(%(wkt)s, 4326))
""", {"name": "Route", "wkt": wkt_line})
conn.commit()
Dane geometryczne
Wstaw dane geometrii płaskiej za pomocą punktów i wielokątów do rysunków CAD lub planów pięter.
# Insert a geometry point (flat coordinate system)
cursor.execute("CREATE TABLE #FloorPlan (RoomName NVARCHAR(100), RoomShape GEOMETRY)")
cursor.execute("""
INSERT INTO #FloorPlan (RoomName, RoomShape)
VALUES (%(name)s, geometry::Point(%(x)s, %(y)s, 0))
""", {"name": "Office 101", "x": 50.0, "y": 100.0})
# Insert a geometry polygon
room_wkt = "POLYGON((0 0, 0 10, 20 10, 20 0, 0 0))"
cursor.execute("""
INSERT INTO #FloorPlan (RoomName, RoomShape)
VALUES (%(name)s, geometry::STGeomFromText(%(wkt)s, 0))
""", {"name": "Conference Room", "wkt": room_wkt})
conn.commit()
Zapytanie o dane przestrzenne
Użyj metod przestrzennych takich jak STAsText() i Lat/Long właściwości, aby uzyskać współrzędne w czytelnym formacie.
Pobierz jako tekst
Pobierz współrzędne przestrzenne w formacie Well-Known Text wraz z właściwościami szerokości i długości geograficznej.
cursor.execute("""
SELECT
City,
SpatialLocation.STAsText() AS LocationWKT,
SpatialLocation.Lat AS Latitude,
SpatialLocation.Long AS Longitude
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
""")
for row in cursor.fetchall()[:5]:
print(f"{row.City}: {row.Latitude}, {row.Longitude}")
print(f" WKT: {row.LocationWKT}")
Pobierz jako GeoJSON
Microsoft SQL obsługuje konwersję GeoJSON. W SQL Server 2017+ możesz używać funkcji łańcuchowych do bezpośredniego budowania GeoJSON lub konwertować w Python, jak pokazano poniżej:
cursor.execute("""
SELECT
City,
SpatialLocation.STAsText() AS WKT
FROM Person.Address
WHERE SpatialLocation IS NOT NULL AND City = %(city)s
""", {"city": "Seattle"})
for row in cursor:
print(f"{row.City}: {row.WKT}")
Znajdź pobliskie punkty
Znajdź wszystkie lokalizacje w określonej odległości od punktu odniesienia za pomocą funkcji odległości przestrzennej.
# Find locations within 10 km of Seattle
cursor.execute("""
DECLARE @seattle geography = geography::Point(47.6062, -122.3321, 4326);
SELECT
City,
SpatialLocation.STDistance(@seattle) / 1000 AS DistanceKM
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
AND SpatialLocation.STDistance(@seattle) < 50000 -- 50 km in meters
ORDER BY SpatialLocation.STDistance(@seattle)
""")
for row in cursor.fetchall()[:5]:
print(f"{row.City}: {row.DistanceKM:.2f} km away")
Znajdź punkty wewnątrz wielokąta
Znajdź wszystkie punkty, które przecinają się z lub znajdują się w obrębie danego obszaru wielokąta geograficznego.
# Find all addresses within a region
cursor.execute("""
DECLARE @region geography = geography::STPolyFromText(
'POLYGON((-122.5 47.5, -122.2 47.5, -122.2 47.7, -122.5 47.7, -122.5 47.5))',
4326
);
SELECT City, SpatialLocation.STAsText() AS Location
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
AND @region.STIntersects(SpatialLocation) = 1
""")
Obliczanie odległości
Metoda Microsoft SQL STDistance() zwraca odległości w metrach dla typów geografii.
Odległość między dwoma punktami
Stwórz funkcję pomocniczą do obliczania odległości w kilometrach między dwoma punktami geograficznymi.
def get_distance_km(cursor, point1: tuple, point2: tuple) -> float:
"""Calculate distance between two points in kilometers."""
cursor.execute("""
DECLARE @point1 geography = geography::Point(%(lat1)s, %(lon1)s, 4326);
DECLARE @point2 geography = geography::Point(%(lat2)s, %(lon2)s, 4326);
SELECT @point1.STDistance(@point2) / 1000 AS DistanceKM;
""", {
"lat1": point1[0], "lon1": point1[1],
"lat2": point2[0], "lon2": point2[1]
})
return cursor.fetchval()
# Seattle to San Francisco
distance = get_distance_km(cursor, (47.6062, -122.3321), (37.7749, -122.4194))
print(f"Distance: {distance:.2f} km")
Oblicz powierzchnię
Oblicz powierzchnię danego regionu geograficznego w kilometrach kwadratowych.
cursor.execute("""
DECLARE @region geography = geography::STPolyFromText(
'POLYGON((-122.5 47.5, -122.2 47.5, -122.2 47.7, -122.5 47.7, -122.5 47.5))',
4326
);
SELECT
'Seattle Region' AS Name,
@region.STArea() / 1000000 AS AreaSqKm
""")
row = cursor.fetchone()
print(f"{row.Name}: {row.AreaSqKm:.2f} sq km")
Operacje przestrzenne
Microsoft SQL obsługuje operacje zbiorowe na obiektach przestrzennych, w tym union, intersection i buffer.
Zjednoczenie kształtów
Połącz dwa wielokąty geograficzne w jeden kształt i oblicz całkowity obszar.
cursor.execute("""
DECLARE @parcel1 geography = geography::STPolyFromText(
'POLYGON((-122.35 47.60, -122.33 47.60, -122.33 47.62, -122.35 47.62, -122.35 47.60))',
4326
);
DECLARE @parcel2 geography = geography::STPolyFromText(
'POLYGON((-122.34 47.61, -122.32 47.61, -122.32 47.63, -122.34 47.63, -122.34 47.61))',
4326
);
DECLARE @combined geography = @parcel1.STUnion(@parcel2);
SELECT @combined.STAsText() AS CombinedWKT,
@combined.STArea() / 1000000 AS TotalAreaKM
""")
row = cursor.fetchone()
print(f"Combined area: {row.TotalAreaKM:.2f} sq km")
Skrzyżowanie
Znajdź nakładający się obszar, gdzie dwa regiony geograficzne się przecinają.
polygon1_wkt = "POLYGON((-122.35 47.60, -122.33 47.60, -122.33 47.62, -122.35 47.62, -122.35 47.60))"
polygon2_wkt = "POLYGON((-122.34 47.61, -122.32 47.61, -122.32 47.63, -122.34 47.63, -122.34 47.61))"
cursor.execute("""
DECLARE @region1 geography = geography::STPolyFromText(%(wkt1)s, 4326);
DECLARE @region2 geography = geography::STPolyFromText(%(wkt2)s, 4326);
SELECT
@region1.STIntersection(@region2).STAsText() AS IntersectionWKT,
@region1.STIntersection(@region2).STArea() / 1000000 AS AreaKM
""", {"wkt1": polygon1_wkt, "wkt2": polygon2_wkt})
Bufor (rozszerzenie obszaru)
Stwórz strefę buforową wokół punktu geograficznego i znajdź wszystkie lokalizacje w promieniu bufora.
# Find all addresses within 5km buffer of a point
cursor.execute("""
DECLARE @center geography = geography::Point(47.6062, -122.3321, 4326);
DECLARE @buffer geography = @center.STBuffer(5000); -- 5 km buffer
SELECT City
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
AND @buffer.STIntersects(SpatialLocation) = 1
""")
Integracja z Pythonem
Pobierz ciągi WKT z Microsoft SQL i analizuj je za pomocą biblioteki Shapely do przetwarzania geometrii po stronie klienta.
Dzięki bibliotece Shapely
Zainstaluj, uruchamiając pip install shapely.
from shapely import wkt
from shapely.geometry import Point, Polygon
# Retrieve spatial data from Person.Address
cursor.execute("""
SELECT City, SpatialLocation.STAsText() AS WKT
FROM Person.Address
WHERE SpatialLocation IS NOT NULL AND City IN ('Seattle', 'Redmond')
""")
for row in cursor:
# Parse WKT into Shapely geometry
geom = wkt.loads(row.WKT)
if isinstance(geom, Point):
print(f"{row.City}: Point at ({geom.x}, {geom.y})")
elif isinstance(geom, Polygon):
print(f"{row.City}: Polygon with area {geom.area}")
Tworzenie danych przestrzennych za pomocą Shapely
Twórz obiekty geometryczne za pomocą biblioteki Shapely i konwertuj je do formatu WKT do wstawienia do Microsoft SQL.
from shapely.geometry import Point, Polygon, LineString
from shapely import wkt
# Create geometries in Python
seattle = Point(-122.3321, 47.6062)
seattle_wkt = wkt.dumps(seattle)
route = LineString([(-122.3321, 47.6062), (-122.4194, 37.7749)])
route_wkt = wkt.dumps(route)
# Insert into a temp table
cursor.execute("CREATE TABLE #Routes (Name NVARCHAR(100), Path NVARCHAR(MAX))")
cursor.execute("""
INSERT INTO #Routes (Name, Path)
VALUES (%(name)s, %(wkt)s)
""", {"name": "Seattle to SF", "wkt": route_wkt})
cursor.execute("SELECT Name, Path FROM #Routes")
row = cursor.fetchone()
print(f"{row.Name}: {row.Path[:40]}...")
Przekonwertowanie na GeoJSON
Konwertowanie danych przestrzennych z formatu WKT do GeoJSON dla aplikacji internetowych i usług mapowych.
import json
from shapely import wkt
from shapely.geometry import mapping
cursor.execute("""
SELECT City, SpatialLocation.STAsText() AS WKT
FROM Person.Address
WHERE SpatialLocation IS NOT NULL AND City = 'Seattle'
""")
row = cursor.fetchone()
geom = wkt.loads(row.WKT)
geojson = {
"type": "Feature",
"properties": {"name": row.City},
"geometry": mapping(geom)
}
print(json.dumps(geojson, indent=2))
Integracja z GeoDataFrame
Załaduj dane przestrzenne z Microsoft SQL do GeoPandas GeoDataFrame do zaawansowanej analizy geoprzestrzennej.
import geopandas as gpd
from shapely import wkt
import pandas as pd
cursor.execute("""
SELECT AddressID, City, SpatialLocation.STAsText() AS WKT
FROM Person.Address
WHERE SpatialLocation IS NOT NULL AND City = 'Seattle'
""")
# Build DataFrame
rows = cursor.fetchall()
df = pd.DataFrame(
[(r.AddressID, r.City, r.WKT) for r in rows],
columns=['id', 'city', 'wkt']
)
# Convert to GeoDataFrame
df['geometry'] = df['wkt'].apply(wkt.loads)
gdf = gpd.GeoDataFrame(df, geometry='geometry', crs="EPSG:4326")
# Now use GeoPandas operations
print(gdf.head())
Indeksy przestrzenne
Twórz indeksy przestrzenne w Microsoft SQL, aby przyspieszyć zapytania na dużych zbiorach danych przestrzennych.
-- Geography index on Person.Address
CREATE SPATIAL INDEX SIX_Address_SpatialLocation
ON Person.Address(SpatialLocation)
USING GEOGRAPHY_GRID
WITH (
GRIDS = (LEVEL_1 = MEDIUM, LEVEL_2 = MEDIUM, LEVEL_3 = MEDIUM, LEVEL_4 = MEDIUM),
CELLS_PER_OBJECT = 16
);
-- Geometry index (example with custom table)
CREATE SPATIAL INDEX SIX_FloorPlan_RoomShape
ON dbo.FloorPlan(RoomShape)
USING GEOMETRY_GRID
WITH (
BOUNDING_BOX = (0, 0, 1000, 1000),
GRIDS = (LEVEL_1 = HIGH, LEVEL_2 = HIGH, LEVEL_3 = HIGH, LEVEL_4 = HIGH)
);
Porady dotyczące wydajności
Stosuj te techniki, aby zapytania przestrzenne były wydajne na dużą skalę.
Używaj podpowiedzi indeksu przestrzennego
Używaj indeksów przestrzennych do przyspieszania zapytań na dużych zbiorach danych przestrzennych.
cursor.execute("""
DECLARE @region geography = geography::STPolyFromText(
'POLYGON((-122.5 47.5, -122.2 47.5, -122.2 47.7, -122.5 47.7, -122.5 47.5))',
4326
);
SELECT City
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
AND SpatialLocation.STIntersects(@region) = 1
""")
Najpierw filtruj, potem obliczaj
Zoptymalizuj zapytania przestrzenne, najpierw stosując szybki filtr prostokąta ograniczającego, a następnie wykonując precyzyjne obliczenia odległości.
# Approximate filter with bounding box, then precise calculation
cursor.execute("""
DECLARE @center geography = geography::Point(47.6062, -122.3321, 4326);
SELECT City, SpatialLocation.STDistance(@center) AS Distance
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
AND SpatialLocation.Filter(@center.STBuffer(10000)) = 1 -- Fast bounding box filter
AND SpatialLocation.STDistance(@center) < 10000 -- Precise distance check
ORDER BY Distance
""")
Zmniejsz precyzję na potrzeby wyświetlania
Uproszczenie geometrii przestrzennych do prezentacji poprzez zmniejszenie precyzji współrzędnych.
cursor.execute("""
SELECT
City,
SpatialLocation.Reduce(100).STAsText() AS SimplifiedWKT -- 100 meter tolerance
FROM Person.Address
WHERE SpatialLocation IS NOT NULL AND City = 'Seattle'
""")
Układy odniesienia współrzędnych
SRID określa układ współrzędnych i wpływa na sposób, w jaki Microsoft SQL oblicza odległości i powierzchnie.
Wspólne wartości SRID
SRID (Spatial Reference Identifier) definiuje układ współrzędnych dla Twoich danych. Użycie niewłaściwego SRID powoduje nieprawidłowe obliczenia odległości i powierzchni.
| SRID | Nazwa | Przypadek użycia |
|---|---|---|
| 4326 | WGS 84 | Współrzędne GPS, mapowanie internetowe |
| 4269 | NAD 83 | Badania w Ameryce Północnej |
| 0 | Brak SRID | Geometria płaska, współrzędne lokalne |
Konwertowanie między SRID-ami
Pobierz dane przestrzenne i sprawdź jego SRID, aby zweryfikować układ współrzędnych.
cursor.execute("""
-- Geography is always round-earth, but SRID defines datum
SELECT SpatialLocation.STAsText() AS WKT,
SpatialLocation.STSrid AS SRID
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
""")
Najlepsze rozwiązania
Stosuj te wytyczne, aby prawidłowo i efektywnie pracować z danymi przestrzennymi.
Walidacja geometrii
Sprawdź dane przestrzenne pod kątem poprawności i zidentyfikuj wszelkie problemy geometryczne przed przetworzeniem.
cursor.execute("""
SELECT
City,
SpatialLocation.STIsValid() AS IsValid,
SpatialLocation.IsValidDetailed() AS InvalidReason
FROM Person.Address
WHERE SpatialLocation IS NOT NULL
AND SpatialLocation.STIsValid() = 0
""")
for row in cursor:
print(f"Invalid: {row.City} - {row.InvalidReason}")
Uczyń geometrię poprawną
Użyj MakeValid() tej metody do automatycznej korekty nieprawidłowych kształtów geometrycznych.
# Example with a temp table
cursor.execute("""
CREATE TABLE #SpatialFix (Name NVARCHAR(100), GeoLocation GEOGRAPHY);
INSERT INTO #SpatialFix VALUES ('Test', geography::STGeomFromText('POLYGON((0 0, 0 1, 1 0, 0 0))', 4326));
UPDATE #SpatialFix
SET GeoLocation = GeoLocation.MakeValid()
WHERE GeoLocation.STIsValid() = 0
""")
Wybierz odpowiedni typ
Wybór między geography i geometry decyduje o tym, jak Microsoft SQL oblicza odległości i obszary:
- Geografia: Rzeczywiste lokalizacje (punkty GPS), obliczenia powierzchni Ziemi, odległości w metrach.
- geometria: płaskie powierzchnie (plany pięter, CAD), układy współrzędnych kartezjańskich lub gdy SRID nie ma znaczenia.