Мне пришлось выполнить поиск геолокации, и после долгих исследований я остановился на использовании географии sql2008.Вам нужна таблица почтовых индексов с лат / долг.Таблица должна выглядеть примерно так:
CREATE TABLE [dbo].[PostalCodes](
[ID] [bigint] IDENTITY(1,1) NOT NULL,
[StateID] [bigint] NOT NULL,
[PostalCode] [varchar](10) NOT NULL,
[Latitude] [decimal](16, 12) NULL,
[Longitude] [decimal](16, 12) NULL,
[GeographyLocation] [geography] NULL,
[CreatedOn] [datetime] NOT NULL,
[LastUpdated] [datetime] NOT NULL,
[GeographyLocation_temp] [varchar](100) NULL,
CONSTRAINT [PK_PostalCode] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Я загрузил международный список почтовых индексов из GeoNames.org и импортировал его как tmp_GeoNames.Затем я запустил следующий скрипт, чтобы вставить данные в мою таблицу zipcode и создать пространственный индекс.(Мне пришлось добавить свой собственный столбец StateID и заполнить его, но вы можете пропустить эту часть и удалить ее из скрипта.)
INSERT INTO PostalCodes
(StateID, PostalCode, Latitude, Longitude)
SELECT DISTINCT StateID, PostalCode, Latitude, Longitude FROM temp_GeoNames where stateID is not null
UPDATE PostalCodes
SET GeographyLocation_temp= 'POINT(' + CONVERT(VARCHAR(100),longitude)
+' ' + CONVERT(VARCHAR(100),latitude) +')'
UPDATE PostalCodes
SET GeographyLocation = geography::STGeomFromText(GeographyLocation_temp,4326)
CREATE SPATIAL INDEX SIndx_SpatialTable_geography_col1
ON PostalCodes(GeographyLocation);
Наконец я создал функцию, которая принимает lat / long и возвращает всепочтовые индексы в определенном диапазоне.Поскольку он использует пространственный индекс, он очень быстрый.
CREATE FUNCTION [dbo].[PostalCode_SelectNearest]
(
@Latitude [decimal](16, 12)
,@Longitude [decimal](16, 12)
,@RangeInMiles int
)
RETURNS @PostalCodes Table (PostalCode varchar(10) PRIMARY KEY NOT NULL, DistanceInMiles FLOAT NULL)
AS
BEGIN
--Create geography point based on Lat/Long passed ... careful, the values passed are reversed from normal thinking
DECLARE @g geography;
SET @g = geography::STGeomFromText('POINT(' +
CONVERT(varchar,@Longitude) + ' ' +
CONVERT(varchar,@Latitude) + ')', 4326);
--Select the nearest Postal Codes
INSERT INTO @PostalCodes (PostalCode, DistanceInMiles)
SELECT PostalCode, GeographyLocation.STDistance(@g)/1609.344 as DistanceInMiles
FROM PostalCodes
WHERE GeographyLocation.STDistance(@g)<=(@RangeInMiles * 1609.344)
RETURN;
END
Я понимаю, что это не совсем то, что вы ищете, но оно может быть преобразовано в ваши цели.Я обнаружил, что использование почтовых индексов намного эффективнее и точнее, чем в городах, потому что города могут охватывать множество почтовых индексов и, следовательно, возвращать данные, которые являются ошибочными для конечного пользователя.
Это все очень ориентировано на США, но может быть легко преобразовано в международныйиспользовать.Я планирую сделать это в какой-то момент в будущем, но еще не нуждался в этом.