У меня эта таблица называется 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!
Я попытался выполнить этот запрос MySQL из командной строки (он же инструмент Webmin для команд SQL), и результат был, как и должно быть: 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 выдаст исключение дублирующегося ключа.
Как я упоминал ранее, основываясь на предоставленной информации, я подозреваю, что ваша функция вызывается несколько раз. (У меня нет достаточной информации, чтобы на самом деле принять такое решение; это всего лишь догадка.)
Вот простое решение ниже
<?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, чтобы делать то, что вы действительно хотите сделать.
Хорошо, я обновил код, попробуйте этот способ. Сначала он получит данные & шоу . Во-вторых, он обновит данные. В конечном итоге отобразит данные. Попробуйте таким образом, надеюсь, вы можете найти свою проблему.
Я решил это, просто делая что-то вроде этого:
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