Você poderia fazer pior do que olhar para a
GEOGRAPHY
tipo de dados, por exemplo:CREATE TABLE Places
(
SeqID INT IDENTITY(1,1),
Place NVARCHAR(20),
Location GEOGRAPHY
)
GO
INSERT INTO Places (Place, Location) VALUES ('Coventry', geography::Point(52.4167, -1.55, 4326))
INSERT INTO Places (Place, Location) VALUES ('Sheffield', geography::Point(53.3667, -1.5, 4326))
INSERT INTO Places (Place, Location) VALUES ('Penzance', geography::Point(50.1214, -5.5347, 4326))
INSERT INTO Places (Place, Location) VALUES ('Brentwood', geography::Point(52.6208, 0.3033, 4326))
INSERT INTO Places (Place, Location) VALUES ('Inverness', geography::Point(57.4760, -4.2254, 4326))
GO
SELECT p1.Place, p2.place, p1.location.STDistance(p2.location) / 1000 AS DistanceInKilometres
FROM Places p1
CROSS JOIN Places p2
GO
SELECT p1.Place, p2.place, p1.location.STDistance(p2.location) / 1000 AS DistanceInKilometres
FROM Places p1
INNER JOIN Places p2 ON p1.SeqID > p2.SeqID
GO
geography::Point
leva a latitude e longitude, bem como um SRID (número de ID de referência especial). Nesse caso, o SRID é 4326, que é latitude e longitude padrão. Como você já tem latitude e longitude, basta ALTER TABLE
para adicionar a coluna de geografia, então UPDATE
para povoá-lo. Mostrei duas maneiras de obter os dados da tabela, mas você não pode criar uma exibição indexada com isso (as exibições indexadas não podem ter autojunções). No entanto, você pode criar uma tabela secundária que seja efetivamente um cache, preenchida com base no acima. Você então só precisa se preocupar em mantê-lo (pode ser feito através de gatilhos ou algum outro processo).
Observe que a junção cruzada fornecerá 250.000.000.000 linhas, mas a pesquisa é simples, pois você só precisa olhar para uma das colunas de lugares (ou seja,
SELECT * FROM table WHERE Place1 = 'Sheffield' AND distance < 100
, o segundo fornecerá significativamente menos linhas, mas a consulta precisará considerar as colunas Place1 e Place2).