STDistance: примеры (SQL)

Руководство по работе с функцией STDistance в MS SQL Server
Раздел: Геопространственные функции, Пространственные
STDistance(other_geography geography): float

Описание функции STDistance

Функция STDistance является методом для пространственных типов данных geometry и geography в MS SQL Server. Она вычисляет кратчайшее расстояние между двумя экземплярами пространственных объектов.

Применяется в задачах геоаналитики, логистики, работы с картографическими данными для определения дистанции между точками, линиями, полигонами.

Функция принимает один обязательный аргумент: другой экземпляр пространственного данных того же типа (geometry или geography). Синтаксис: instance1.STDistance(instance2).

Возвращаемое значение имеет тип float. Для типа geography результат возвращается в метрах. Для типа geometry результат выражается в единицах измерения, определенных системой координат (SRID) объектов. Если объекты пересекаются, функция возвращает 0. Если какой-либо из экземпляров пуст, возвращается NULL.

Простые примеры применения

Расстояние между двумя точками в системе geometry (декартовы координаты).

DECLARE @point1 geometry = geometry::STGeomFromText('POINT(0 0)', 0);
DECLARE @point2 geometry = geometry::STGeomFromText('POINT(3 4)', 0);
SELECT @point1.STDistance(@point2) AS Distance;
Distance
5

Расстояние между точками на Земле с использованием типа geography (координаты WGS 84).

DECLARE @geo1 geography = geography::STGeomFromText('POINT(37.61778 55.75583)', 4326); -- Москва
DECLARE @geo2 geography = geography::STGeomFromText('POINT(30.26417 59.89444)', 4326); -- Санкт-Петербург
SELECT @geo1.STDistance(@geo2) AS DistanceInMeters;
DistanceInMeters
633483.437235746

Расстояние от точки до полигона. Функция возвращает 0, если точка внутри.

DECLARE @poly geometry = geometry::STGeomFromText('POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))', 0);
DECLARE @point geometry = geometry::STGeomFromText('POINT(2 2)', 0);
DECLARE @pointOut geometry = geometry::STGeomFromText('POINT(7 7)', 0);
SELECT 
    @poly.STDistance(@point) AS DistanceToPointInside,
    @poly.STDistance(@pointOut) AS DistanceToPointOutside;
DistanceToPointInside DistanceToPointOutside
0                   2.82842712474619

Другие пространственные функции MS SQL

MS SQL Server предлагает набор функций для анализа пространственных данных:

  • STLength() — вычисляет длину линейного объекта или периметр.
  • STArea() — определяет площадь экземпляра geometry или geography.
  • STIntersects() — проверяет факт пересечения объектов, часто используется с пространственными индексами для быстрого фильтрации.
  • STWithin() — определяет, находится ли один объект полностью внутри другого.
  • STBuffer() — возвращает объект, представляющий буферную зону вокруг исходного.

STDistance предпочтительна для точного вычисления дистанции. STIntersects эффективнее для предварительной фильтрации пересекающихся или близких объектов, особенно при использовании с индексами.

Распространенные ошибки

1. Сравнение объектов разных типов (geometry с geography).

DECLARE @g geometry = geometry::Point(0, 0, 0);
DECLARE @geo geography = geography::Point(0, 0, 4326);
SELECT @g.STDistance(@geo);
Сообщение об ошибке: Типы данных geometry и geography несовместимы в операции STDistance.

2. Использование объектов с разными идентификаторами SRID.

DECLARE @g1 geometry = geometry::STGeomFromText('POINT(0 0)', 4326);
DECLARE @g2 geometry = geometry::STGeomFromText('POINT(1 1)', 0);
SELECT @g1.STDistance(@g2);
Сообщение об ошибке: Операция STDistance над экземплярами geometry с разными SRID недопустима.

3. Игнорирование NULL-значений, приводящее к неочевидным результатам.

DECLARE @g1 geometry = geometry::Point(0, 0, 0);
DECLARE @g2 geometry;
SELECT @g1.STDistance(@g2) AS DistanceToNull;
DistanceToNull
NULL

История изменений функции

В SQL Server 2012 (версия 11.x) существенно переработаны алгоритмы для типа geography. Расстояние стало рассчитываться по эллипсоидальной модели Земли (референсный эллипсоид WGS 84), что повысило точность по сравнению с прежней сферической моделью.

В SQL Server 2017 добавлена поддержка вычисления STDistance между экземплярами geometry, содержащими криволинейные сегменты (например, CIRCULARSTRING).

На производительность функции также влияют улучшения в работе пространственных индексов в последних версиях СУБД.

Сложные и специальные примеры

Поиск ближайших объектов в таблице с использованием пространственного индекса для ускорения.

Пример sql
-- Создание таблицы с пространственным индексом
CREATE TABLE Places (
    Id INT IDENTITY PRIMARY KEY,
    Name NVARCHAR(100),
    Location geography
);
CREATE SPATIAL INDEX SIndx_Places_Location ON Places(Location);

-- Вставка данных
INSERT INTO Places VALUES 
('Точка A', geography::Point(55.751244, 37.618423, 4326)),
('Точка B', geography::Point(55.754110, 37.620090, 4326)),
('Точка C', geography::Point(55.749580, 37.613839, 4326));

-- Поиск двух ближайших точек к заданной
DECLARE @MyPoint geography = geography::Point(55.752, 37.619, 4326);
SELECT TOP 2 Name, Location.STDistance(@MyPoint) AS DistanceMeters
FROM Places 
ORDER BY DistanceMeters;
Name     DistanceMeters
Точка B  194.836672916677
Точка A  287.847773499339

Вычисление расстояния между объектами разных подтипов: мультиточкой и полигоном.

Пример sql
DECLARE @multiPoint geometry = geometry::STGeomFromText('MULTIPOINT((0 0), (10 10))', 0);
DECLARE @polygon geometry = geometry::STGeomFromText('POLYGON((2 2, 8 2, 8 8, 2 8, 2 2))', 0);
SELECT @multiPoint.STDistance(@polygon) AS Distance;
Distance
0

Расстояние между геометрическими объектами в трехмерном пространстве (Z-координата игнорируется в расчетах STDistance).

Пример sql
DECLARE @point1 geometry = geometry::Parse('POINT(0 0 100)');
DECLARE @point2 geometry = geometry::Parse('POINT(3 4 200)');
SELECT @point1.STDistance(@point2) AS Distance2D;
Distance2D
5

Использование в выражении CASE для классификации расстояний.

Пример sql
DECLARE @source geometry = geometry::Point(0, 0, 0);
DECLARE @target geometry = geometry::Point(15, 0, 0);
SELECT 
    CASE 
        WHEN @source.STDistance(@target) = 0 THEN 'Совпадает'
        WHEN @source.STDistance(@target) < 10 THEN 'Близко'
        ELSE 'Далеко'
    END AS ProximityCategory;
ProximityCategory
Далеко

Аналоги в других системах

PostgreSQL (с PostGIS): Функция ST_Distance. Важное отличие — поддержка разных единиц измерения и эллипсоидов через дополнительный аргумент.

SELECT ST_Distance(
    'SRID=4326;POINT(37.61778 55.75583)'::geography,
    'SRID=4326;POINT(30.26417 59.89444)'::geography
);
633483.437235746

MySQL: Функция ST_Distance. В версиях до 5.7 возвращает расстояние в единицах системы координат, с 5.7 для типа geography — в метрах.

SELECT ST_Distance(
    ST_GeomFromText('POINT(0 0)', 0),
    ST_GeomFromText('POINT(3 4)', 0)
);
5

Oracle: Функция SDO_GEOM.SDO_DISTANCE. Требует задания параметра tolerance.

SELECT SDO_GEOM.SDO_DISTANCE(
    SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(37.61778, 55.75583, NULL), NULL, NULL),
    SDO_GEOMETRY(2001, 4326, SDO_POINT_TYPE(30.26417, 59.89444, NULL), NULL, NULL),
    0.005
) DISTANCE FROM DUAL;
DISTANCE
633483.437

SQLite (с SpatiaLite): Функция ST_Distance. Поведение зависит от загруженных проекций.

MS SQL STDistance function comments

En
STDistance Returns the shortest distance between a point in a geography instance and a point in another geography instance