我正在执行以下查询:
Select guiPolygonID, dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318)
From [vPolygonSegments]
Where dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318) > 0
函数fn_Yval的重要部分(所有参数都是float类型):
set @m = (@p2Y - @p1Y)/(@p2X - @p1X)
set @b = @p1Y - (@m*@p1X)
set @result = (@m*@xval+@b)
视图vPolygonSegments不包含p1X = p2X的记录(不包括那些记录)。但是,当我执行查询时,SQL Server会返回错误:“遇到零除错误”。奇怪的是,如果我只执行前两行(没有where子句),查询返回结果就好了。
如何解决此问题,和/或导致此行为的原因是什么?
修改 以下是我的观点:
Select P1.guiPolygonID,
P1.decX as p1X, P1.decY as p1Y,
P2.decX as p2X, P2.decY as p2Y
From PolygonPoints P1, PolygonPoints P2
Where P1.guiPolygonID = P2.guiPolygonID
and (
P1.lPointNumber - P2.lPointNumber = 1
or (
-- Some other unimportant code
)
)
and P1.decX <> P2.decX
答案 0 :(得分:3)
这里的问题是在评估where子句中的函数之前评估select原因中的函数。这种情况非常罕见,但它是可能的,因此您需要对其进行编码。我建议您修改该功能,以便它可以安全地处理除零情况。改变这一行:
set @m = (@p2Y - @p1Y)/(@p2X - @p1X)
对此:
set @m = (@p2Y - @p1Y)/NullIf((@p2X - @p1X), 0)
当@ p2x - @ p1x = 0时,NULLIF函数将返回NULL。随后,@ m将为null,所有其他值也将为null。最有可能的是,该函数将返回NULL。
在你的where子句中,你有......
Where dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318) > 0
当函数返回NULL时,它不会与0进行比较,最终会被过滤掉。
答案 1 :(得分:2)
正如Joel Coehoorn指出的那样,这是可能的问题。下面的查询应该避免这个问题,但问题最好在函数本身内修复:
Select guiPolygonID, dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318)
From [vPolygonSegments]
Where p2X <> p1X and dbo.fn_Yval(p1X, p1Y, p2X, p2Y, 4.003318) > 0
答案 2 :(得分:2)
我怀疑它与如何为查询实现视图有关。将该函数添加到where子句本质上将其添加到视图的源查询中,以便优化器可以选择在P1.decX <> P2.decX
之前将此过滤器应用于源数据。
无论如何,你不知道什么时候你想要在没有相同约束的其他地方重用那个函数。最好有一个如何预先处理坏数据的计划。在这种情况下,NullIf
建议似乎很好。
答案 3 :(得分:1)
@ p2X = @ p1X时出现问题。在那种情况下你期望发生什么?
答案 4 :(得分:0)
我不知道这会以任何方式回答这个问题,但你会为每条记录评估fn_Yval两次。为什么不在视图中将函数的结果作为列?然后,你的where子句可能是“yval&gt; 0”。
编辑:出于好奇,fn_Yval没有任何副作用,是吗?
答案 5 :(得分:0)
我发现在涉及连接或视图时尝试删除可能导致使用where子句的零错误的数据是有问题的。过滤join子句中的数据或在函数中过滤掉它。
更新:仅仅因为“G Mastros”写道的原因。