Дивна проблема роботи в 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.

БОЛ заявляє:

Коли два оператори в виразі мають однаковий рівень пріоритетності оператора, вони оцінюються зліва направо на основі їх положення в виразі.

І

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
Чому, на вашу думку, ви маєте справу з бітами, ви працюєте з цілими числами. І integer / integer = ціле число. Так -100 / -1000 - це 0
sepupic

5
Гаразд, я згоден, це -, здається, викликає потік "неправильно". Якщо ви спробуєте, -100/(-100)*10ви отримаєте результат 10. видається, що значення /застосовується проти значення -в рівнянні, а потім визначається рівняння 100*10. Я не впевнений, що це помилка з BOL, але більше того, що SQL Server не веде себе так, як очікувалося. Можливо, варто підняти проблему на sql-docs і подивитися, на що їх відповідь; можливо, до документації, що свідчить про "особливість", може бути додана примітка.
Ларну

3
SELECT -100/(-100)*10також повертається 10. Схоже -, трактується як -оператор, який слід застосувати лише після того, як 100*10буде обчислено
Panagiotis Kanavos

7
A / -B * Cє A <div> <negate> B <multiply> C. Негати мають нижчий пріоритет, ніж множення, на документи, тому результат такий A / -(B * C). Ви можете зрозуміти це більш чітко, використовуючи плаваючі константи: 12e / -13e * 14eпорівняно 12e / (-13e) * 14eпроти 12e / 13e * 14e. працює.
Jeroen

Відповіді:


96

У відповідності до таблиці пріоритету, це є очікуваним поведінкою. Оператор з більш високим пріоритетом ( /і *) оцінюється перед оператором з нижчим пріоритетом (одинарним -). Отже це:

-100 / -100 * 10

оцінюється як:

-(100 / -(100 * 10))

Зауважте, що така поведінка відрізняється від більшості мов програмування, де одинарне заперечення має вищий пріоритет, ніж множення та ділення, наприклад VB , JavaScript .


38
Нічого собі, ще одна особливість дорогоцінного каміння в T-SQL :) Я думаю, що мені доведеться перевірити весь код зараз, щоб шукати помилки.
usr

14
о людино. Це ще гірше, ніж різні помилки, що потрійні оператори PHP bugs.php.net/bug.php?id=61915 . Що думають люди, що одинарні оператори повинні мати нижчий пріоритет, ніж бінарні?
phuclv

12
Реальна різниця може полягати в тому, чи -вважається оператором в Росії -100. У деяких мовах це частина синтаксису цілого числа.
Бармар

7
Так що це помилка в їх перевазі одинарних -.
Кевін

4
А переможець контр-інтуїтивного дизайну стає ...: Microsoft - ще раз
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

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.