SQL Server中一个奇怪的操作问题:-100 / -100 * 10 = 0


106
  • 如果执行SELECT -100/-100*10,结果为0
  • 如果执行SELECT (-100/-100)*10,结果为10
  • 如果执行SELECT -100/(-100*10),结果为0
  • 如果执行SELECT 100/100*10,结果为10

BOL指出:

当表达式中的两个运算符具有相同的运算符优先级时,将根据它们在表达式中的位置从左到右进行评估。

Level   Operators
  1     ~ (Bitwise NOT)
  2     * (Multiplication), / (Division), % (Modulus)
  3     + (Positive), - (Negative), + (Addition), + (Concatenation), - (Subtraction), & (Bitwise AND), ^ (Bitwise Exclusive OR), | (Bitwise OR)

BOL是错误的,还是我缺少什么?似乎-取消(预期)优先顺序。


7
你有什么问题?
Ilyes

14
为什么您认为必须使用位,而使用整数。和整数/整数=整数。所以-100 / -1000是0
sepupic

5
好的,我同意,这-似乎确实导致流程“错误”。如果尝试,-100/(-100)*10将得到结果10。似乎将/应用于-方程中的值,然后100*10确定了方程。我不确定这是BOL的错误,但更多的是SQL Server的行为不符合预期。在sql-docs上提出一个问题并查看其响应可能是值得的。也许可以在有关“功能”的文档建议中添加注释。
拉努

3
SELECT -100/(-100)*10也返回10.它看起来像-被视为-只应之后施加操作者100*10的计算
帕纳约蒂斯Kanavos

7
A / -B * CA <div> <negate> B <multiply> C。根据文档,Negate的优先级比乘法低,因此结果为A / -(B * C)。您可以通过使用浮动常数更清楚地看到这一点:12e / -13e * 14e12e / (-13e) * 14eVS 12e / 13e * 14e。其原因,这将引发我们送行,因为我们普遍预期一元负成为文本的一部分,或至少具有很高的优先级,但是这并不怎么T-SQL作品。
Jeroen Mostert

Answers:


96

根据优先级表,这预期的行为。优先级较高的运算符(/*)优先级较低的运算符(一元-)。所以这:

-100 / -100 * 10

评估为:

-(100 / -(100 * 10))

注意,这种行为不同于大多数编程语言,在这些语言中,一元求反的优先级高于乘法和除法,例如VBJavaScript


38
哇,T-SQL中的另一个gem特性:)我想我现在必须审核我的所有代码以搜索错误。
usr

14
天啊。这甚至比各种PHP 三元运算符 bugs.php.net/bug.php?id=61915更糟。有什么理智的人认为一元运算符的优先级必须低于二元运算符的优先级?
phuclv

12
真正的区别可能在于是否-将视为的运算符-100。在某些语言中,它是整数语法的一部分。
Barmar

7
因此,这是他们优先使用一元代码的一个错误-
凯文

4
反直觉设计的赢家是...:微软–再一次
rexkogitans

34

BOL是正确的。-的优先级低于*,因此

-A * B

被解析为

-(A * B)

乘法是它是什么,你通常不会注意到这一点,在优先级相同的其他两个二元运算混合时除外:/%(和%在复合表达式很少使用这样的)。所以

C / -A * B

被解析为

C / -(A * B)

解释结果。这是违反直觉的,因为在大多数其他语言中,一元减号的优先级高于*/,但在T-SQL中则没有,并且已被正确记录。

一种很好的(?)说明方式:

SELECT -1073741824 * 2

产生算术溢出,因为-(1073741824 * 2)产生2147483648为中间值,不适合INT,但

SELECT (-1073741824) * 2

产生预期的结果-2147483648


“减”是二进制。一元-是“负数”。人们在说“负10”时说“负10”之类的话是不准确的。
累积

11
@积累:不精确不是我的。将-运算符应用于单个操作数时,将MINUS在SQL查询计划中调用该运算符。其二进制副本称为SUB。如果愿意,可以将“一元减号”解释为“由减号表示的一元运算符”的简写-一种语法而不是语义名称。
Jeroen Mostert

3
“负10”是美国的标准用法(我相信),但在英国却不是标准用法。
Alchymist

12

请注意,在文档中(可能是违反直觉的)优先级为- (Negative)第三。

因此,您可以有效地获得:

-(100/-(100*10)) = 0

如果将它们放入变量中,则不会发生这种情况,因为在乘法之后不会发生一元运算。

因此,这里的A和B相同,而C,D,E显示的是您看到的结果(其中E带有完整的包围)

DECLARE @i1 int, @i2 int, @i3 int;

SELECT @i1 = -100,
       @i2 = -100,
       @i3 = 10;

SELECT @i1/@i2*@i3      [A],
       -100/(-100)*10   [B],
       -100/-100*10     [C],
       -100/-(100*10)   [D],
       -(100/-(100*10)) [E];

A - 10
B - 10
C - 0
D - 0
E - 0
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.