Не добавление 1, но 2, 3 или 4 при ОБНОВЛЕНИИ mysql с переполнением стека

У меня эта таблица называется classes:

+------------+----------+------+-----+----------------+
| Field      | Type     | Null | Key | Extra          |
+------------+----------+------+-----+----------------+
| class_id   | int(3)   | NO   | PRI | auto_increment |
| class_level| int(1)   | YES  |     |                |
| class_name | char(1)  | YES  |     |                |
+------------+----------+------+-----+----------------+

С данными внутри вот так:

+----------+-------------+------------+
| class_id | class_level | class_name |
+----------+-------------+------------+
| 1        | 0           | N          |
| 2        | 1           | A          |
| 3        | 1           | B          |
| 4        | 2           | C          |
| 5        | 2           | D          |
| 6        | 3           | E          |
| 7        | 3           | F          |
+----------+-------------+------------+

С PHP я хочу увеличить все значения внутри class_level кроме 0
Итак, я сделал эту функцию PHP / MySQL:

mysql_query("UPDATE classes SET class_level = (class_level + 1) WHERE class_level != 0") or die(mysql_error());

Это (что странно) не добавляет 1 к каждому class_level кроме тех, что равны 0, но добавляет 2 или 3 или 4! Я не нашел правила, что этот скрипт добавил бы 2 или 3 или 4. Это СЛУЧАЙНО выбрано. И ошибки тоже не выводится.

Все, что он делает, это добавляет случайным образом 2, 3 или 4 к каждой строке.

Итак, для отладки я сделал этот код PHP, чтобы добавить к каждому по одному:

$query = mysql_query("SELECT * FROM `classes` WHERE `class_level` != 0");

while ($row = mysql_fetch_assoc($query)) {
$class_id = $row['class_id'];

$class_level = $row['class_level'];
$class_level = $class_level + 1;
var_dump($class_level);

mysql_query("UPDATE `classes` SET `class_level` = '$class_level' WHERE `class_id` = '$class_id'") or die(mysql_error());
}

Вывод из var_dump:

int(2) int(2) int(3) int(3) int(4) int(4)

Но в базе данных в таблице я получаю следующий результат:

+----------+-------------+------------+
| class_id | class_level | class_name |
+----------+-------------+------------+
| 1        | 0           | N          |
| 2        | 4           | A          |
| 3        | 4           | B          |
| 3        | 5           | C          |
| 4        | 5           | D          |
| 5        | 6           | E          |
| 6        | 6           | F          |
+----------+-------------+------------+

Это пустой файл только с подключением MySQL и приведенным выше кодом, поэтому над ним нет цикла.

Вот моя информация о версии: версия PHP: 5.2.12, версия MySQL Client API 5.1.44. Обратите внимание, что я не могу установить ни mysqli, ни PDO.

РЕДАКТИРОВАТЬ:

Сразу после выполнения запроса MySQL я вывел данные из таблицы, и результат был, как и должно быть. Но в самой таблице (или при обновлении кода только для вывода) было добавлено 3, а не 1!

РЕДАКТИРОВАТЬ 2:

Я попытался выполнить этот запрос MySQL из командной строки (он же инструмент Webmin для команд SQL), и результат был, как и должно быть: 1 был добавлен.

1

Решение

РЕДАКТИРОВАТЬ

добавленной Демонстрация SQL Fiddle: http://sqlfiddle.com/#!9/efa05b/1

create table classes
( class_id    int(3) not null auto_increment primary key comment 'pk'
, class_level int(1)
, class_name  char(1)
)
;
insert into classes (class_id,class_level,class_name) values
('1','0','N')
,('2','1','A')
,('3','1','B')
,('4','2','C')
,('5','2','D')
,('6','3','E')
,('7','3','F')
;
update classes set class_level = (class_level + 1) where class_level != 0
;

Запрос подтверждает, что ожидаемый результат возвращается. Каждая строка (кроме строки с class_level=0) был обновлен, с class_level увеличивается ровно на 1.

select * from classes order by class_id

class_id class_level class_name
-------- ----------- ----------
1        0           N
2        2           A
3        2           B
4        3           C
5        3           D
6        4           E
7        4           F

оригинальный ответ

Предполагая, что в таблице нет триггера BEFORE / AFTER UPDATE, учитывая выполняемый оператор SQL:

UPDATE classes SET class_level = (class_level + 1) WHERE class_level != 0

Наиболее логичным объяснением такого поведения является то, что оператор SQL выполняется в функции несколько раз или функция вызывается несколько раз.

Чтобы убедиться в этом, вы можете временно включить общий журнал MySQL, запустить тест, отключить общий журнал и просмотреть … и вы найдете несколько выполнений оператора. Если у вас нет доступа к серверу MySQL, лучше всего будет вывести строку непосредственно перед выполнением оператора; Вы увидите, что эта линия повторяется несколько раз.

Маловероятно, что это ошибка в базе данных MySQL. (Убедитесь, что в таблице не определен TRIGGER.)

Кроме того, протестируйте этот оператор, используя другой клиент, например команду mysql, например client, или phpmyadmin. И убедитесь, что заявление работает правильно.


СЛЕДОВАТЬ ЗА

Учитывая, что ваш тест оператора SQL от другого клиента дает ожидаемые результаты, я думаю, это демонстрирует, что это не проблема с базой данных MySQL или оператором SQL.

По какой-то причине этот оператор SQL выполняется несколько раз. В качестве следующего шага в отладке я бы добавил еще немного кода. Я бы временно создал таблицу «log», используя движок MyISAM, содержащий идентификатор auto_increment, столбец datetime и информационную строку:

 CREATE TABLE debug_log
( id   INT UNSIGNED AUTO_INCREMENT PRIMARY KEY
, dt   DATETIME
, info VARCHAR(40)
) Engine=MyISAM

Затем добавьте еще один оператор SQL в вашу функцию, чтобы вставить строку в эту таблицу, непосредственно перед и / или после выполнения оператора UPDATE.

INSERT INTO debug_log (dt, info) VALUES (SYSDATE(), 'my function before update')

Затем запустите тест и посмотрите, сколько строк вставлено в таблицу debug_log.

Чтобы получить ошибку, если этот оператор выполняется более одного раза, укажите фиксированное значение для столбца id, например,

INSERT INTO debug_log (id, dt, info)
VALUES (123, SYSDATE(), 'my function before update')

При фиксированном значении для id, если этот оператор вызывается во второй раз, MySQL выдаст исключение дублирующегося ключа.

Как я упоминал ранее, основываясь на предоставленной информации, я подозреваю, что ваша функция вызывается несколько раз. (У меня нет достаточной информации, чтобы на самом деле принять такое решение; это всего лишь догадка.)

2

Другие решения

Вот простое решение ниже

<?php
print("<h1>BEFORE</h1>");
$q =mysql_query("select *from classes ");
while($row=mysql_fetch_array($q)){
print("$row['class_id'] - $row['class_level'] - row[$class_name] <br/>");
}

mysql_query("UPDATE classes SET class_level = class_level+1 WHERE class_level>0") or die(mysql_error());print("<h1>AFTER</h1>");

$q =mysql_query("select *from classes ");
while($row=mysql_fetch_array($q)){
print("$row['class_id'] - $row['class_level'] - row[$class_name] <br/>");
}?>

Вам не нужно писать какую-либо отдельную строку php, чтобы делать то, что вы действительно хотите сделать.

Хорошо, я обновил код, попробуйте этот способ. Сначала он получит данные & шоу . Во-вторых, он обновит данные. В конечном итоге отобразит данные. Попробуйте таким образом, надеюсь, вы можете найти свою проблему.

1

Я решил это, просто делая что-то вроде этого:

mysql_query("UPDATE classes SET class_level = 2 WHERE class_level = 1");
mysql_query("UPDATE classes SET class_level = 3 WHERE class_level = 2");
mysql_query("UPDATE classes SET class_level = 4 WHERE class_level = 3");

У меня есть только эти три класса, так что он выполняет свою работу.

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


Постскриптум Как я мог не думать об этом в первую очередь XD

0