Этот «пространственный» запрос mySQL также работает в SQL Server 2008? - PullRequest
1 голос
/ 05 июля 2010

Прежде чем приступить к довольно приличной переработке моего веб-приложения для использования пространственного запроса, я хотел бы знать, работает ли этот запрос MySQL в SQL Server 2008:

SELECT id, ( 3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * 
        cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * 
        sin( radians( lat ) ) ) ) AS distance 
FROM markers HAVING distance < 25 
ORDER BY distance LIMIT 0 , 20;

Или есть ли лучший способ сделать это в SQL Server 2008?

Моя база данных в настоящее время хранит данные о латах и ​​бизнесах рядом с военными базами в Японии. Тем не менее, я запрашиваю таблицу, чтобы найти компании, которые содержат указанный идентификатор базы.

Biz table
----------------------
PK BizId bigint (auto increment)
Name
Address
Lat
Long
**FK BaseId int (from the MilBase table)**

Пространственный запрос, основанный на наличии центрального широты / долготы и заданного радиуса (в км), будет более подходящим для приложения и откроет некоторые новые возможности.

Любая помощь очень ценится!

Ответы [ 2 ]

2 голосов
/ 05 июля 2010

Похоже, вы выбираете расстояние между двумя точками. В SQL Server 2008 вы можете использовать метод STDistance типа данных geography. Это будет выглядеть примерно так:

SELECT   TOP 20
         geography::STGeomFromText('POINT(-122.0 37.0)', 4326).STDistance(p) 
FROM     markers
WHERE    geography::STGeomFromText('POINT(-122.0 37.0)', 4326).STDistance(p) < 25
ORDER BY geography::STGeomFromText('POINT(-122.0 37.0)', 4326).STDistance(p);

Где p будет полем типа geography вместо двух отдельных decimal полей. Возможно, вы также захотите создать пространственный индекс в своем поле p для повышения производительности.

Чтобы использовать тип данных geography, просто укажите свое поле как geography в вашем CREATE TABLE:

CREATE TABLE markers ( 
    id     int IDENTITY (1,1),
    p      geography, 
    title  varchar(100) 
);

Вставка значений в таблицу markers теперь будет выглядеть так:

INSERT INTO markers (id, p, title) 
VALUES (
    1,
    geography::STGeomFromText('POINT(-122.0 37.0)', 4326),
    'My Marker'
);    

Где -122.0 - это долгота, а 37.0 - это широта.

Создание пространственного индекса будет выглядеть примерно так:

CREATE SPATIAL INDEX  ix_sp_markers
                      ON markers(p)
                      USING GEOGRAPHY_GRID
                      WITH ( GRIDS = (HIGH, HIGH, HIGH, HIGH),
                             CELLS_PER_OBJECT = 2,
                             PAD_INDEX = ON);
1 голос
/ 05 июля 2010

Если вас интересует только получение точек в пределах 25 миль, тогда абсолютно не нужно использовать математические вычисления сферической или большой окружности при расчете расстояния ... Более чем достаточно просто использовать стандартную декартову формулу расстояния. .

Where  Square(Delta-X) + Square(Delta-Y) < 225  

Все, что вам нужно сделать, - это преобразовать разницу в широтах и ​​разницу в долготах в мили в любых единицах измерения, которые вы используете (мили в миль, обычные мили в любом месте)

Если вы используете морские мили, то каждый градус широты = 60 нм ...
И каждый градус долготы равен 60 * cos (широта) нм
Здесь, если обе точки находятся в пределах 25 миль друг от друга, вам даже не нужно беспокоиться о разнице между этим фактором от одной точки к другой ...

...