tsql регистр синтаксиса в формуле расстояния - PullRequest
0 голосов
/ 21 марта 2012

Функция acos работает в интервале -1 <= x <= 1. </p>

Иногда, из-за округления, я получаю 1.00001, чтобы вычислить акос, тогда в следующем предложении where дается ошибка с плавающей точкой:

    where
        (6371 * acos(cos(radians(@ga_where)) * cos(radians(thing_geolocation.ga_thing)) * cos(radians(thing_geolocation.go_thing) - radians(@go_where)) + sin(radians(@ga_where)) * sin(radians(thing_geolocation.ga_thing)))) < 1.5

Итак, мне придется изменить этот пункт where на что-то вроде этого:

    where
        (
            6371 *
            acos
            (
                case
                    when cos(radians(@latitude)) * cos(radians(thing_geolocation.ga_thing)) * cos(radians(thing_geolocation.go_thing) - radians(@longitude)) + sin(radians(@latitude)) * sin(radians(thing_geolocation.ga_thing)) > 1 then 1
                    when cos(radians(@latitude)) * cos(radians(thing_geolocation.ga_thing)) * cos(radians(thing_geolocation.go_thing) - radians(@longitude)) + sin(radians(@latitude)) * sin(radians(thing_geolocation.ga_thing)) < -1 then -1
                    else cos(radians(@latitude)) * cos(radians(thing_geolocation.ga_thing)) * cos(radians(thing_geolocation.go_thing) - radians(@longitude)) + sin(radians(@latitude)) * sin(radians(thing_geolocation.ga_thing))
                end
            )
        ) < 1.5 

Но разве это не звучит хорошо (это приведет к вычислению расстояния 3х, верно?).

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

ps: я пытался использовать функцию point.distance, но она не работает с нулевыми значениями, поэтому я выбрал keep this.

Есть идеи?

1 Ответ

0 голосов
/ 21 марта 2012

Я бы предложил изменить все, что вы передаете в acos, в определяемую пользователем скалярную функцию. В рамках этой функции вы можете учитывать значения больше 1,0 или меньше -1,0.

При этом вам не нужно будет выполнять какие-либо математические вычисления больше, чем необходимо.

Я думаю, что ваша функция будет выглядеть примерно так:

CREATE FUNCTION [dbo].[udf_GetACOSInputValueByLatLong]
(
    @LatStart DECIMAL(10,6),
    @LongStart DECIMAL(10,6),
    @LatEnd DECIMAL(10,6),
    @LongEnd DECIMAL(10,6)
)
RETURNS DECIMAL(10,6) AS 
BEGIN

DECLARE @Result DECIMAL(10, 6)
SET @Result = ( 
    cos( radians( @LatStart ) ) * 
    cos( radians( @LatEnd ) ) * 
    cos( radians( @LongEnd ) - radians(@LongStart) ) + sin( radians(@LatStart) ) * 
    sin( radians( @LatEnd ) ) 
)

IF @Result > 1.0
    SET @Result = 1.0
ELSE IF @Result < -1.0
    SET @Result = -1.0

RETURN (@Result)

END

Что может быть использовано следующим образом:

where
    (
        6371 * acos (YourDatabase.dbo.udf_GetACOSInputValueByLatLong(
            @latitude, 
            @longitude, 
            thing_geolocation.ga_thing, 
            thing_geolocation.go_thing))
    ) < 1.5
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...