Как отрицать целочисленное значение в MySQL 5.7?

#mysql #sql

#mysql #sql

Вопрос:

Я выполняю выбор в 5.7.32, где я хочу отрицать значения:

 SELECT (val * -1) AS new_value
 

Это приводит к ошибке:

 Data truncation: BIGINT UNSIGNED value is out of range i
 

Как это можно преодолеть?

Комментарии:

1. Ну, зачем тип данных BIGINT UNSIGNED , если вам нужно, чтобы значение было отрицательным?

Ответ №1:

Вы можете cast signed сначала:

 select cast(val as signed) * -1 as new_value from mytable
 

Обратите внимание, что вы также можете сформулировать это как:

 select - cast(val as signed) as new_value from mytable
 

Как ни странно, оба следующих выражения работают нормально, без явного приведения:

 select - val as new_value from mytable;
select val / -1 as new_value from mytable;
 

Обратите внимание, что неподписанные наборы данных имеют максимально допустимое значение, чем эквивалентные беззнаковые (в основном это то же количество возможных значений, но также включая отрицательные значения). Таким образом, в основном, как прокомментировал Билл Карвин, значения, превышающие максимальное 32-разрядное целое число со знаком, не будут правильно обработаны.

Комментарии:

1. @ysth: мы можем получить эту ошибку с любым unsigned значением (кроме 0 ). Смотрите: db-fiddle.com/f/v42SJCyPZ6Vux5HWjKnZBY/0

2. ах, вы правы. Я испортил свое тестирование.

3. кажется -val , сбой происходит только при слишком больших значениях, но val * -1 всегда сбой? Я этого не понимаю.

4. Обратите внимание, что это приведет к усечению значений BIGINT, превышающих максимальное 32-разрядное целое число со знаком.

5. @BillKarwin нет, он не усекает, по крайней мере, в 5.7, он просто обрабатывает >= 2 ** 63 как отрицательное, а не положительное.

Ответ №2:

Вы можете пропустить строки, где оно находится вне диапазона:

 select -val as new_value from foo where val <= 9223372036854775807
 

или вы можете просто обработать его как строку:

 select concat('-',val) as new_value from foo;
 

приведение к signed не будет работать, поскольку оно изменит значения, превышающие 9223372036854775807, на отрицательные числа, которые при отрицании будут положительными.

Вы можете преобразовать его обратно в число с помощью:

 select 0 concat('-',val) as new_value from foo;
 

но это приведет к потере точности для больших чисел.

скрипка