距离公式中的tsql case语法

时间:2012-03-20 20:11:25

标签: tsql

acos函数在区间-1< = x< = 1。

中工作

有时,由于四舍五入,我得到1.00001来计算acos,然后以下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 

但是,听起来不是很好(它会导致计算距离3x,对吧?)。

我有其他想法,比如子查询或outerapply,但因为entiry查询非常复杂并且相同的字段用于其他目的,我试图在不改变整个查询的情况下解决它。

ps:我尝试使用point.distance函数,但它对null值不起作用,所以我选择保持这种方式。

有什么想法吗?

1 个答案:

答案 0 :(得分:0)

我建议将您传递到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