带子查询顺序的随机浮点错误

时间:2013-02-20 15:04:36

标签: sql sql-server sql-server-2008 tsql

我正在运行sql server 2008数据库,我在Web应用程序中使用以下查询,但是为了调试错误,我直接在管理工作室中运行查询。

我收到以下错误 - 发生了无效的浮点运算。运行此查询时。

select p.Id as Id,  p.CatId as CatId, p.MetaName as MetaName ,p.Active as Active,p.HasChildren as HasChildren ,p.Mlevel as Mlevel ,p.ParentId as ParentId ,p.Type as Type, p.VOrder as VOrder, p.UrlOrder as UrlOrder, Count('*') as VCount 
from MetaDataValues as m 
left join MetaData as p on m.MetaDataId = p.Id
left join Adverts as a on m.AdvertId = a.Id
where a.Status = 1
and a.ExpDate > current_timestamp and 
m.AdvertId in 
(select m2.AdvertId from MetaDataValues as m2 left join MetaData as p2 on m2.MetaDataId = p2.Id where p2.MetaName = 'meta1' 
and m.AdvertId in (select m3.AdvertId from MetaDataValues as m3 left join MetaData as p3 on m3.MetaDataId = p3.Id where p3.MetaName = 'meta2' 
and m.AdvertId in (select m4.AdvertId from MetaDataValues as m4 left join MetaData as p4 on m4.MetaDataId = p4.Id where p4.MetaName = 'meta3' 
and m.AdvertId in (select ad9.Id from Adverts as ad9 where dbo.GetDist(ad9.X,ad9.Y,ad9.Z,52.9131514,-2.9313405) < 969))))
group by p.Id, p.CatId, p.MetaName,p.Active,p.HasChildren,p.Mlevel,p.ParentId,p.Type, p.VOrder, p.UrlOrder

要解释导致问题的GetDist函数,如果我将子查询中的这个向上移动到顶层,查询运行正常?这不是理想的,因为构建此查询的代码以某种方式编码,我不想改变它。所以这里的查询是有效的,完全相同但是顺序不同!

select p.Id as Id,  p.CatId as CatId, p.MetaName as MetaName ,p.Active as Active,p.HasChildren as HasChildren ,p.Mlevel as Mlevel ,p.ParentId as ParentId ,p.Type as Type, p.VOrder as VOrder, p.UrlOrder as UrlOrder, Count('*') as VCount 
from MetaDataValues as m 
left join MetaData as p on m.MetaDataId = p.Id
left join Adverts as a on m.AdvertId = a.Id
where a.Status = 1
and a.ExpDate > current_timestamp and 
m.AdvertId in 
(select m2.AdvertId from MetaDataValues as m2 left join MetaData as p2 on m2.MetaDataId = p2.Id where p2.MetaName = 'meta1' 
and m.AdvertId in (select ad9.Id from Adverts as ad9 where dbo.GetDist(ad9.X,ad9.Y,ad9.Z,52.9131514,-2.9313405) < 969)
and m.AdvertId in (select m3.AdvertId from MetaDataValues as m3 left join MetaData as p3 on m3.MetaDataId = p3.Id where p3.MetaName = 'meta2' 
and m.AdvertId in (select m4.AdvertId from MetaDataValues as m4 left join MetaData as p4 on m4.MetaDataId = p4.Id where p4.MetaName = 'meta3' )))
group by p.Id, p.CatId, p.MetaName,p.Active,p.HasChildren,p.Mlevel,p.ParentId,p.Type, p.VOrder, p.UrlOrder



GetDist code

USE [MVC]
GO
/****** Object:  UserDefinedFunction [dbo].[GetDist]    Script Date: 02/20/2013 17:05:00 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER FUNCTION [dbo].[GetDist] 
    (
    @xaxis float,
    @yaxis float,
    @zaxis float,
    @CenterLat float, 
    @CenterLon float
    )
RETURNS float
AS
    BEGIN

declare @CntXAxis float
declare @CntYAxis float
declare @CntZAxis float
declare @EarthRadius float 

set @EarthRadius = 3961
set @CntXAxis = cos(radians(@CenterLat)) * cos(radians(@CenterLon))
set @CntYAxis = cos(radians(@CenterLat)) * sin(radians(@CenterLon))
set @CntZAxis = sin(radians(@CenterLat))

return (@EarthRadius * acos( @XAxis*@CntXAxis + @YAxis*@CntYAxis + @ZAxis*@CntZAxis))


    END

2 个答案:

答案 0 :(得分:1)

看起来GetDist可能正在计算一对纬度/经度值之间的距离。我对此有很多经验。像这样的大多数GetDist函数都使用Arc Cosine函数“ACos”。此函数的参数限制在-1到1的范围内。如果尝试传递超出此范围的值,则SQL Server中将出现域错误。如果您的GetDist函数使用CLR函数,则错误将在您的.net代码中,并且消息会略有不同。

处理花车时,你必须要注意奇怪的四舍五入问题。例如,如果您的计算将返回值1.00000000000001,并将其传递给ACos函数,则会出现错误。

这里有很多猜测,我可能完全偏离基础,但请考虑这个并花几分钟做一些研究。

根据您在上面发布的GetDist功能,我建议进行相对较小的更改:

ALTER FUNCTION [dbo].[GetDist] 
    (
    @xaxis float,
    @yaxis float,
    @zaxis float,
    @CenterLat float, 
    @CenterLon float
    )
RETURNS float
AS
    BEGIN

declare @CntXAxis float
declare @CntYAxis float
declare @CntZAxis float
declare @EarthRadius float 
declare @Temp float

set @EarthRadius = 3961
set @CntXAxis = cos(radians(@CenterLat)) * cos(radians(@CenterLon))
set @CntYAxis = cos(radians(@CenterLat)) * sin(radians(@CenterLon))
set @CntZAxis = sin(radians(@CenterLat))

Set @Temp = @XAxis*@CntXAxis + @YAxis*@CntYAxis + @ZAxis*@CntZAxis
If @Temp > 1
    Set @Temp = 1
Else If @Temp < -1
    Set @Temp = -1

return (@EarthRadius * acos(@Temp))

    END

即使这不能解决您的原始问题,它至少可以保护您免受奇怪的浮动/精度问题。

答案 1 :(得分:0)

问题是无效操作还是更像“将数据类型varchar转换为数字时出错”?当数字数据存储为字符串时,这是一个相当常见的问题。它在字符串看起来正确时起作用,但在其他时候失败。

getDist()的所有参数都是正确的类型吗?返回值是否为数字?

我猜想更高级别的过滤会滤除导致问题的错误值。