为何未更新任何行的UPDATE语句部分触发INT溢出错误?
为什么同样是不会更新行的UPDATE语句,一个触发INT溢出另一个却不会?
最近碰到一个SQL Server里特别反直觉的问题,来跟大家拆解下:
首先我创建了临时表并插入了测试数据:
CREATE TABLE #t(col1 int) INSERT INTO #t VALUES(1)
之后用两种方式尝试模拟INT溢出:
方式1:
UPDATE #t SET col1 = 999999*999999 WHERE col1 = 2这条语句不会更新任何行(因为表中只有col1=1的数据),但会触发INT溢出错误。
方式2:
UPDATE #t SET col1 = 999999*999999 WHERE 1 = 2同样不会更新任何行,但完全不会触发溢出错误。
核心原因:SQL Server的表达式求值逻辑
这背后的关键在于SQL Server对表达式的求值时机判断:
- 对于第一个语句的
WHERE col1 = 2,SQL Server没办法在编译阶段就确定绝对不会有匹配的行(虽然我们知道当前表没有,但它会考虑未来可能有符合条件的数据),所以会提前计算999999*999999这个赋值表达式,结果超出了INT的范围(INT最大值是2147483647,而999999*999999=999998000001),自然触发溢出。 - 而第二个语句的
WHERE 1 = 2是恒假条件,SQL Server在编译阶段就能直接判断出这个条件永远不会匹配任何行,所以会跳过赋值表达式的计算步骤,也就不会触发溢出。
生产环境的隐患
这种问题在包含数值列和分类列的生产表执行UPDATE时会更棘手:比如你写了一个带分类筛选条件的UPDATE,本来以为筛选条件会过滤掉所有行,但如果SQL Server无法提前识别出这是恒假条件,就可能先计算赋值的复杂表达式,导致溢出错误——哪怕实际根本不会修改任何数据。
内容的提问来源于stack exchange,提问作者a4194304
相关产品推荐
相关产品推荐

