Странная проблема работы в SQL Server (-100 / -100 * 10 = 0)

  • Если вы выполните 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 не прав или я что-то упустил? Кажется, что - отбрасывает (ожидаемый) приоритет.

Ответ 1

Согласно таблице приоритетов, это ожидаемое поведение. Оператор с более высоким приоритетом (/ и *) оценивается перед оператором с более низким приоритетом (унарный -). Итак, это:

-100 / -100 * 10

оценивается как:

-(100 / -(100 * 10))

Обратите внимание, что это поведение отличается от большинства языков программирования, где унарное отрицание имеет более высокий приоритет, чем умножение и деление, например, VB, JavaScript.

Ответ 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, который делает.

Ответ 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

Ответ 4

Я считаю, что оператор - просто переводит выражение в -1 * argument, а аргумент - это числовое выражение до следующего оператора прецедента. Несколько примеров:

Вот что я считаю двигателем:

SELECT -100                                 -- Result: -100
SELECT - 1 * (100)                          -- Result: -100

Здесь я перевожу каждый - в отдельном шаге слева направо:

SELECT -100 / -100                          -- Result: 1
SELECT -1 * (100 / -100)                    -- Result: 1
SELECT -1 * (100 / -1 * (100))              -- Result: 1

Здесь я добавляю + 1 в конце, поэтому аргумент (добавленные скобки) закончится непосредственно перед добавлением:

SELECT -100 / -100 + 1                      -- Result: 2
SELECT -1 * (100 / -100) + 1                -- Result: 2
SELECT -1 * (100 / -1 * (100)) + 1          -- Result: 2

Это тот случай, упомянутый в вопросе. Он возвращает 0 потому что первая вычисленная операция равна 100 * 10, затем 100 делится на -1000, в результате чего получается 0.

SELECT -100 / -100 * 10                     -- Result: 0
SELECT -1 * (100 / -100 * 10)               -- Result: 0
SELECT -1 * (100 / -1 * (100 * 10))         -- Result: 0

Ответ 5

Оператор минус действительно оценивается как вычитание из 0, а не как буквальный отрицательный символ.

Чтобы получить правильный результат, добавьте скобки, чтобы сначала вычиталось вычитание.

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

Ответ 6

Расчет на самом деле правильный, и делает порядок операций, насколько ему известно. Вы видели на своем примере добавления в скобках -100/(-100 * 10) == 0. Порядок операций сохраняется, но кажется, что система читает справа налево, а не слева направо. Это говорит о том, что он использует постфикс для анализа уравнения.

TSQL неявно определяет типы данных. Причина, по которой ваш -100 / -100 * 10 == 0 состоит в том, что он выводит тип данных всех операндов как INT. Если бы вы бросили каждое из этих значений в число с плавающей точкой, оно бы правильно показало 0.1