我有一个管理应用程序,将数据保存在 SQL Server 数据库中:该应用程序打开一个事务,执行一些操作,执行一个存储过程,然后提交(或回滚)。存储过程是按时间顺序排列的最后一个操作:它在事务中运行,但我无法控制事务。在存储过程中,在完成之前,我需要对插入的内容执行一些检查。由于我要将行插入到两个不同的表中,因此这些表必须具有匹配的余额。如果它们不匹配,则意味着出现问题。现在我将向您展示执行检查的 SQL 脚本,然后解释问题
IF (SELECT Count(*) FROM (
SELECT CGTEMPCONT,
(SELECT Cast(Sum(CASE WHEN CGMOVISEZI='D' THEN IsNull(CGMOVIIMPO, 0) ELSE -IsNull(CGMOVIIMPO, 0) END) As Decimal(20,2)) As saldo
FROM CGMOVI
WHERE CGMOVICONT=CGTEMPCONT
AND CGMOVIDTRE=CGTEMPDTRE
AND CGMOVIESER=CGTEMPESER
AND CGMOVITMOV=CGTEMPTMOV
AND CGMOVINPRO=CGTEMPNPRO
AND CGMOVIBSEZ=CGCAUCBLOC
) As saldoCGMOVI,
(SELECT Cast(Sum(CASE WHEN CGPARTSEZI='D' THEN IsNull(CGPARTIMPO, 0) ELSE -IsNull(CGPARTIMPO, 0) END) As Decimal(20,2)) As saldo
FROM CGPART
WHERE CGPARTCONT=CGTEMPCONT
AND CGPARTDTRE=CGTEMPDTRE
AND CGPARTESER=CGTEMPESER
AND CGPARTTMOV=CGTEMPTMOV
AND CGPARTNPRO=CGTEMPNPRO
AND CGPARTBSEZ=CGCAUCBLOC
) As saldoCGPART
FROM CGTEMP INNER JOIN CGANCF ON CGTEMPCONT=CGANCFCODI
INNER JOIN CGCAUC ON CGTEMPCAUS=CGCAUCCODI
WHERE (CGTEMPUTEN=@UTEN) AND (CGTEMPNOPC=@NOPC)
) T1
WHERE (IsNull(saldoCGMOVI,0)<>IsNull(saldoCGPART,0))
) > 0
BEGIN
RAISERROR ('error', 16, 1)
END
我不会详细介绍 SQL 脚本。这是一个可以正确运行并聚合绝对不为空的数据的脚本,因为这些是必填字段。 脚本执行产生以下错误
通过聚合或其他 SET 操作消除空值
不幸的是,这个错误会中断执行并且事务会回滚。我已经彻底调查了脚本执行的内容:我在外部数据库中创建了一个表以防止事务删除行。在该表中,我附加了要比较的行,并且正如预期的那样,没有任何异常:没有空值。
令我惊讶的是,我注意到如果删除 RAISERROR 指令,则不会生成有关 Null 值聚合的错误。由此,我得出结论,该脚本工作正常,但我无法理解为什么 RAISERROR 会生成此错误。我尝试用 THROW 替换 RAISERROR 但没有任何变化
通过以下方式抑制警告:
SET ANSI WARNINGS OFF
在存储过程结束时重新打开警告
SET ANSI WARNINGS ON