Максимальные значения полей типа int. Откуда они такие беруться ?

Максимальные значения полей типа int. Откуда они такие беруться ?

Есть такая табличка:
PHP:
CREATE TABLE `battle_stat` (
 `person_id` int(10) unsigned NOT NULL,
 `opponent_id` int(10) unsigned NOT NULL,
 `score_1` mediumint(8) unsigned NOT NULL default '0',
 `score_2` mediumint(8) unsigned NOT NULL default '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8
Новые строки в таблице появляются по выполнению следующих запросов:
PHP:
INSERT `battle_stat` SET `person_id` = 111, `opponent_id` = 222, `score_1` = 1
INSERT `battle_stat` SET `person_id` = 111, `opponent_id` = 222, `score_2` = 1
Обновляются при помощи таких:
PHP:
UPDATE `battle_stat` SET `score_1` = `score_1` + 1 WHERE `person_id` = 111 AND `opponent_id` = 222
UPDATE `battle_stat` SET `score_2` = `score_2` + 1 WHERE `person_id` = 111 AND `opponent_id` = 222
UPDATE `battle_stat` SET `score_1` = `score_1` + 1, `score_2` = `score_2` - 1 WHERE `person_id` = 111 AND `opponent_id` = 222
UPDATE `battle_stat` SET `score_2` = `score_2` + 1, `score_1` = `score_1` - 1 WHERE `person_id` = 111 AND `opponent_id` = 222
Как видно нет никакой возможности выставить какое либо конкретное значение, только +-1. Однако при это в таблице наблюдаются вот такие аномалии:
PHP:
mysql> SELECT * FROM `battle_stat` WHERE `score_1` > 10000 LIMIT 5;
+-----------+-------------+----------+---------+
| person_id | opponent_id | score_1  | score_2 |
+-----------+-------------+----------+---------+
|       466 |        1363 | 16777215 |       2 |
|      1355 |        2530 | 16777215 |       2 |
|      1108 |        3169 | 16777215 |       2 |
|      2341 |        3169 | 16777215 |       2 |
|       158 |        3897 | 16777215 |       2 |
+-----------+-------------+----------+---------+
16777215 - это максимальное значение для типа mediumint на текущей системе... но я уверен на все 100% в данных случаях, что не мог UPDATE-запрос выполниться 16777215 раз. Так откуда тогда такие числа там беруться ?
 

zerkms

TDD infected
Команда форума
запиши в поле 0 и вручную напиши запрос который от 0 отнимет 1
 

Adelf

Administrator
Команда форума
про unsigned тоже советую где-нибудь почитать :)
 
Действительно... а я ведь подозревал ))
PHP:
mysql> INSERT INTO battle_stat SET person_id = 111, opponent_id = 222, score_1 = 1;
Query OK, 1 row affected (0.23 sec)

mysql> SELECT * FROM battle_stat WHERE person_id = 111 AND opponent_id = 222;
+-----------+-------------+---------+---------+
| person_id | opponent_id | score_1 | score_2 |
+-----------+-------------+---------+---------+
|       111 |         222 |       1 |       0 |
+-----------+-------------+---------+---------+
1 row in set (0.19 sec)

mysql> UPDATE battle_stat SET score_2 = score_2 - 1 WHERE person_id = 111 AND opponent_id = 222;
Query OK, 1 row affected, 1 warning (0.18 sec)
Rows matched: 1  Changed: 1  Warnings: 1

mysql> SHOW WARNINGS;
+---------+------+--------------------------------------------------+
| Level   | Code | Message                                          |
+---------+------+--------------------------------------------------+
| Warning | 1264 | Out of range value for column 'score_2' at row 1 |
+---------+------+--------------------------------------------------+
1 row in set (0.00 sec)

mysql> SELECT * FROM battle_stat WHERE person_id = 111 AND opponent_id = 222;
+-----------+-------------+---------+----------+
| person_id | opponent_id | score_1 | score_2  |
+-----------+-------------+---------+----------+
|       111 |         222 |       1 | 16777215 |
+-----------+-------------+---------+----------+
Это получается, что прежде чем отнять единицу от какого либо значения, нужно проверить не лежит ли там нуль ? Жестяк...
 
Видимо это:
In nonstrict mode, when an out-of-range value is assigned to an integer column, MySQL stores the value representing the corresponding endpoint of the column data type range. If you store 256 into a TINYINT or TINYINT UNSIGNED column, MySQL stores 127 or 255, respectively. When a floating-point or fixed-point column is assigned a value that exceeds the range implied by the specified (or default) precision and scale, MySQL stores the value representing the corresponding endpoint of that range.
А у меня на одном серваке:
PHP:
mysql> SELECT @@SESSION.sql_mode;
+--------------------+
| @@SESSION.sql_mode |
+--------------------+
|                    |
+--------------------+
И на нём всё работает плохо... т.е. подставляются некорректные значения. А на втором:
PHP:
mysql> SELECT @@SESSION.sql_mode;
+----------------------------------------------------------------+
| @@SESSION.sql_mode                                             |
+----------------------------------------------------------------+
| STRICT_TRANS_TABLES,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION |
+----------------------------------------------------------------+
И тут всё работает хорошо.
Короче нужно у мускуля включить STRICT_TRANS_TABLES-режим... как вариант.
 
Adelf
Не, спасибо конечно за направление куда мыслить, но я не телепат... всё таки интернеты тем и хороши, что всегда ссылку дать можно...
 

zerkms

TDD infected
Команда форума
можно даже слово не переводить. просто триггер повесить, BEFORE UPDATE, который будет проверять NEW значение.
 
zerkms
Спасибо за ещё один вариант
Fortop
Благодаря вам, помощь на форумах, превращается в тролинг
UNSIGNED
Перевёл... и что ?? Что я должен узнать про этот тип данных ? Вышеуказанная вырезка из документации разве не про UNSIGNED ? Если нет, то почему бы, повторюсь, не дать прямую ссылку ?
 

Fortop

Новичок
Вася Патриков
Благодаря вам
Нас благодарить не надо :D лучше думать научитесь.

В данном случае имеется типичный closure
Вы находитесь на форуме о программировании, значит контекст не общеупотребительный, а компьютерный.
Соответственно переводить надо как жаргонизм и проф.лексику

http://rus-eng-slovar.ru/index.php?action=find&text=unsigned
 

craz

Нестандартное звание
блин поле сделай не отрицательным и все
или наоборот
 

Fortop

Новичок
блин поле сделай не отрицательным и все
Если хочется отрицательных чисел, то ровно наоборот :) У него они как раз unsigned.

Если нужно без переполнения, то слушать надо zerkms
 

craz

Нестандартное звание
нуда надо их не ансигнед сделать и проверять если меньше ноля то ноль а это зеркмс советует как раз. че не понятного то?
 
Fortop
Отлично... прежде чем что то впаривать и настаивать на своей правоте и превосходстве, спросите, что требуется, если не поняли это изначально. Отрицательные числа мне там нахрен не нужны, поэтому unsigned там и стоит!
К тому же в процессе обсуждения найдены три способа, как избежать того, чтобы ячейка таблицы типа unsigned int при попытке внести туда значение выходящее за границы хранимого диапазона не стала содержать максимально возможное значение... это я к тому, что способ предложенный
zerkms не единственный.

-~{}~ 27.04.10 18:33:

craz
то же самое, что и к Fortop... мыслители...
 

Fortop

Новичок
Вася Патриков
К тому же в процессе обсуждения найдены три способа, как избежать ...
Когда человек выходит на форум с тривиальным вопросом, презумпция невиновности(наличия опыта) на него не распространяется.
Поэтому я бы настоятельно рекомендовал научится думать и выражать связно свои мысли и желания.
Дабы мыслителям не давать повода для измышлений :D

Поскольку вопрос был
Вася Патриков
Так откуда тогда такие числа там беруться ?
А не "как избежать".

craz
мы теперь в одной лодке
Три мудреца в одном тазу. Пустились по морю в грозу. Будь попрочнее старый таз, длиннее был бы мой рассказ.
 
Сверху