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

cui*_*zhe 95 sql t-sql sql-server operator-precedence

  • 如果你执行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)
Run Code Online (Sandbox Code Playgroud)

BOL是错的,还是我错过了什么?似乎-正在抛弃(预期)优先权.

Sal*_*n A 85

根据优先级表,这预期的行为.具有较高优先级(/*)的运算符在具有较低优先级(一元-)的运算符之前进行求值.所以这:

-100 / -100 * 10
Run Code Online (Sandbox Code Playgroud)

被评估为:

-(100 / -(100 * 10))
Run Code Online (Sandbox Code Playgroud)

请注意,这种行为与大多数编程语言不同,其中一元否定的优先级高于乘法和除法,例如VB,JavaScript.

  • 哇,T-SQL中的另一个宝石功能:)我想我现在必须审核我的所有代码来搜索错误. (38认同)
  • 天啊.这甚至比各种PHP [三元运算符错误](/sf/ask/1584355041/)https://bugs.php.net/bug.php?id=61915更糟糕.人们认为一元运算符的优先级必须低于二元运算符? (14认同)
  • 真正的区别可能是`-`在`-100`中是否被视为运算符.在某些语言中,它是整数语法的一部分. (12认同)
  • 所以这是他们优先考虑一元`-`的错误. (7认同)
  • 反直觉设计的赢家是......:微软 - 再一次 (4认同)

Jer*_*ert 30

BOL是对的.-具有比优先级低*,所以

-A * B
Run Code Online (Sandbox Code Playgroud)

被解析为

-(A * B)
Run Code Online (Sandbox Code Playgroud)

乘法就是这样,你通常不会注意到这一点,除非在另外两个具有相同优先级的二元运算符中混合:/%(%很少在像这样的复合表达式中使用).所以

C / -A * B
Run Code Online (Sandbox Code Playgroud)

被解析为

C / -(A * B)
Run Code Online (Sandbox Code Playgroud)

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

一个很好的(?)方式来说明它:

SELECT -1073741824 * 2
Run Code Online (Sandbox Code Playgroud)

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

SELECT (-1073741824) * 2
Run Code Online (Sandbox Code Playgroud)

产生预期的结果-2147483648,这样做.

  • @Acccumulation:不精确不是我的.当应用于单个操作数时,`-`运算符在SQL查询计划中称为"MINUS".它的二进制对应物称为"SUB".如果你愿意,可以将"一元减号"解释为"由减号表示的一元算子"的简写 - 一种句法而不是语义指定. (10认同)
  • "负10"是美国的标准用法(我相信),但它在英国并不标准. (3认同)

Jam*_*ard 10

在文档中注意(可能反直觉地)优先顺序为- (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
Run Code Online (Sandbox Code Playgroud)