此代码将"除以0和#34;仅运行存储过程时出错,并且不会在独立语句中发生。
我想知道执行存储过程和公共语句之间的区别是什么导致了这种情况。
表PPB_PBExecuteLine
有大约200条记录,有67条记录,数量为0,但只有select才能在指定情况下得到Qty = 0记录
以下是声明:
--exec PPB_P_ReCalcActaulExeSUMToPB 1001603230260241,-1,1001605170110011
Create Procedure PPB_P_ReCalcActaulExeSUMToPB
@Org Bigint,
@CBS Bigint,
@ProjectIDs Nvarchar(max)
with recompile
as
Begin
Declare @SQL Nvarchar(Max)
If Object_ID('tempdb..#Projects') is not null
drop table #Projects;
Create table #Projects (ID bigint null);
If(@ProjectIDs != '')
Begin
Set @SQL = 'insert into #Projects (ID)' + 'select ' + replace(@ProjectIDs,',',' as ID union all select ')
Exec sp_executesql @SQL
End
If object_id('tempdb..#ProjectBudget_Detail_DiffCost') Is Not Null
Drop Table #ProjectBudget_Detail_DiffCost;
--*******this statement
Select
B.ID as ExecuteLine,
SUM(C.ExecuteCost - (B.OutExeCome / B.Qty) * C.Qty) as DiffCost
Into
#ProjectBudget_Detail_DiffCost
From
PPB_PBExecute A
Inner Join
PPB_PBExecuteLine B on A.ID = B.PBExecute
Inner Join
PPB_PBExecuteDetial C on C.PBExecuteLine = B.ID
Where
A.Org = @Org
and (A.CBS = @CBS or @CBS <= 0)
and (A.Project in (select ID from #Projects) or @ProjectIDs = '')
Group by
B.ID
Update A
Set A.DiffCost = B.DiffCost
From PPB_PBExecuteLine as A
Inner Join #ProjectBudget_Detail_DiffCost as B on A.ID = B.ExecuteLine
--and more
End
答案 0 :(得分:1)
从我在你的存储过程中看到的,只有一行导致异常,这是在
SUM(C.ExecuteCost - (B.OutExeCome / B.Qty) * C.Qty ) as DiffCost
当B.Qty
为0时,它将抛出异常。但是,可以通过在CASE
表达式的列中添加额外验证来防止这种情况。
SUM(C.ExecuteCost - (B.OutExeCome / (CASE WHEN B.Qty = 0 THEN 1 ELSE B.Qty END) * C.Qty) as DiffCost
答案 1 :(得分:0)
解释起来相当复杂。首先,使用nullif()
来消除问题的可能性:
Select B.ID as ExecuteLine,
SUM( C.ExecuteCost-(B.OutExeCome/nullif(B.Qty, 0))*C.Qty ) as DiffCost
(或者您可能需要其他一些逻辑。)
一种可能性是,B.Qty
实际上是导致问题的0
。让我推测这不是问题所在,因为你在一个地方看到了错误而在另一个地方看不到。
这导致0
可能会被过滤掉。如何在过滤掉的行上出错?好吧,SQL Server不保证表达式的处理顺序。实际上,它可以在where
。
瞧!错误。
为什么会发生在一个地方而不是另一个地方呢?这可能是由于不同的执行计划。也许存储过程中的版本已缓存,最佳计划已更改。
答案 2 :(得分:0)
数学除以零是未定义的。因此,在SQL Server中,也将是未定义的,这意味着它不是整数也不是NULL。
在您的存储过程中,
SUM(C.ExecuteCost - (B.OutExeCome / B.Qty) * C.Qty) as DiffCost
如果B.Qty = 0,则会抛出错误,因此您需要使用以下方法之一来处理:
使用案例
您可以使用CASE senario并将值Zero替换为数字或NULL。在这里,我将用数字1替换它。
(CASE WHEN B.Qty <> 0 THEN B.Qty ELSE 1 )
使用NULLIF
这是最快的方法,如果值等于零,将返回NULL。
NULLIF(B.Qty, 0)
ARITHABORT和ANSI_WARNINGS
您可以将ARITHABORT和ANSI_WARNINGS设置为OFF,这样,SQL服务器将返回带零分区的NULL。
SET ARITHABORT OFF
SET ANSI_WARNINGS OFF