【问题标题】:A strange operation problem in SQL Server: -100/-100*10 = 0SQL Server中一个奇怪的操作问题:-100/-100*10 = 0
【发布时间】:2019-06-28 00:50:03
【问题描述】:
  • 如果你执行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 错了,还是我遗漏了什么?似乎- 正在抛弃(预期的)优先级。

【问题讨论】:

  • 你有什么问题?
  • 为什么你认为你必须使用位,你正在使用整数。并且整数/整数=整数。所以 -100/-1000 是 0
  • 好的,我同意- 似乎确实导致流程“错误”。如果你尝试-100/(-100)*10,你会得到10的结果。似乎/ 被应用于方程中的值-,然后方程100*10 正在被确定。我不确定这是 BOL 的错误,但更多的是 SQL Server 没有按预期运行。可能值得在sql-docs 上提出一个问题,看看他们的反应是什么;也许可以在说明“功能”的文档中添加注释。
  • SELECT -100/(-100)*10 也返回 10。看起来 - 被视为 - 运算符,仅应在计算 100*10 后应用
  • A / -B * CA <div> <negate> B <multiply> C。根据文档,否定的优先级低于乘法,因此结果为A / -(B * C)。你可以通过使用浮动常量更清楚地看到这一点:12e / -13e * 14e vs. 12e / (-13e) * 14e vs 12e / 13e * 14e。这让我们失望的原因是因为我们通常期望一元减号成为文字的一部分,或者至少有非常高的优先级,但这不是 T-SQL 的工作方式。

标签: sql sql-server tsql operator-precedence


【解决方案1】:

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

-100 / -100 * 10

被评估为:

-(100 / -(100 * 10))

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

【讨论】:

  • 哇,T-SQL 中的另一个 gem 功能 :) 我想我现在必须审核我的所有代码以搜索错误。
  • 哦,伙计。这比各种PHP ternary operator bugsbugs.php.net/bug.php?id=61915还要糟糕。什么理智的人认为一元运算符的优先级必须低于二元运算符?
  • 真正的区别可能在于- 是否被视为-100 中的运算符。在某些语言中,它是整数语法的一部分。
  • 所以这是他们的一元-优先级中的一个错误。
  • 反直觉设计的赢家是......:微软 - 再次
【解决方案2】:

BOL 是正确的。 - 的优先级低于 *,所以

-A * B

被解析为

-(A * B)

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

C / -A * B

被解析为

C / -(A * B)

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

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

SELECT -1073741824 * 2

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

SELECT (-1073741824) * 2

产生预期的结果-2147483648,确实如此。

【讨论】:

  • "minus" 是二进制的。一元 - 是“负数”。说“负 10”之类的话的人的意思是“负 10”是不准确的。
  • @Accumulation:不精确不是我的。 - 运算符在应用于单个操作数时,在 SQL 查询计划中称为 MINUS。它的二进制对应物称为SUB。如果您愿意,可以将“一元减号”解释为“由减号表示的一元运算符”的简写——一种句法而不是语义指定。
  • "negative 10" 是美国的标准用法(我相信),但在英国不是标准的。
【解决方案3】:

请注意文档中(可能与直觉相反)- (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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-13
    • 2011-07-27
    相关资源
    最近更新 更多