MySQL запрос с сложными условиями
349 повідомлень
#10 років тому
Здравствуйте, уважаемые гуру.Сломала мозг себе за ночь. Я совсем почти не разбираюсь в mysql, но нужно составить запрос.
Есть таблица variable. В нем столбцы name и value

1. Нам нужны записи, начинающиеся в name на mymoney
2. Далее у этих записей в столбце value необходимо проверить условие >= 10 (чтобы не зайти в минус)
3. Если удовлетворяет условиям, то вычитаем 10
Попробовала составить запрос, но не получилось:
UPDATE `variable` (`name`, `value`) SET `value` = `value` -10 where `value` LIKE 'mymoney%' AND `value` > 9;
Этот запрос собираюсь выполнять раз в день по крону, чтобы списывать 10 единиц ежедневно у всех пользователей. (mymoney1 - средства пользователя1, mymoney2 - средства пользователя2 и т.д.)
Еще вопрос. Что за символы в данных, типа i: и s:? информации в интернете не смогла найти по этим символам, потому что даже не знаю как это сформулировать.
10 повідомлень
#10 років тому
Эти символы указывают на сериализованные данные (php function i:integer, s:string)MySQL не умеет десериализовывать поэтому value > 9 не срабатывает (вы сравниваете строку с целым)
используйте регулярку для отбора значений (то есть целой части поля value)
..where REGEXP '.*i:+.*'
После этого, выбранные значения можно положить во временную таблицу
Синтаксис может быть таким
CREATE TEMPORARY TABLE IF NOT EXISTS table2 AS (SELECT * FROM table1)
Затем, примените update (декремент) к выборке
На самом деле, средствами SQL получается слишком хитровы..анно
В общем, нужно сначала десериализовать данные
11416 повідомлень
#10 років тому
Примерно так:
$db->q("SELECT * FROM `variable` WHERE `value` LIKE 'mymoney%'");
$res = $db->result();
foreach ($res as $r) {в цикле десериализовать данные и сравнить с 10, провести апдейты.}
349 повідомлень
#10 років тому
Hungry_Hunter, Спасибо! Только целый час ломала голову, почему не работает. Оказалось у вас опечатка. Надо name вместо value 
3562 повідомлення
#10 років тому
Ну или прочитать про вложенные запросы, для конкретно этой задачи скорее всего разницы не почувствуете, но все же.
11416 повідомлень
349 повідомлень
#10 років тому
Вот что в результате написала. Спасибо всем, кто не был равнодушен. Если есть предложения по оптимизации или где то что то не так сделала, пишите 
$query = "SELECT * FROM `variable` WHERE `name` LIKE 'mymoney%'";
$res = mysql_query($query);
while($row = mysql_fetch_array($res)){
$value = unserialize($row);
if ($value >= 10) {
$vychet = $value - 10;
mysql_query("UPDATE `variable` SET `value`='".serialize($vychet)."' WHERE `name`='".$row."'");
}
}
11416 повідомлень
#10 років тому
Можно на всякий случай в строке 7 сделать intvalА в 13 строке заменить условие на WHERE id = $row, если у вас есть он, будет работать быстрее.
349 повідомлень
#10 років тому
Hungry_Hunter, в вопросах денег стоит ли пользоваться intval? Копейки нельзя списывать с счетов ))id нету, только столбцы name и value
Это Drupal...
575 повідомлень
#10 років тому
В вопросах денег хорошо бы использовать pdo, prepared statements и транзакции
11416 повідомлень
#10 років тому
Цитата (WebAir):в вопросах денег стоит ли пользоваться intval? Копейки нельзя списывать с счетов ))
А, ну если там дробные могут быть, то, конечно не нужно.
Вообще деньги лучше хранить в int а потом умножать/делить на 100. Т.е. сумму вида 120 руб 15 коп хранить в виде 12015, тогда операции будут делаться быстрее и не будет проблем с округлением типа float.
402 повідомлення
#10 років тому
Цитата (Hungry_Hunter):Вообще деньги лучше хранить в int а потом умножать/делить на 100. Т.е. сумму вида 120 руб 15 коп хранить в виде 12015, тогда операции будут делаться быстрее и не будет проблем с округлением типа float.Ух ты! Думал, я один такой) Когда только начинал, мы в небольшой веб-конторе именно так и делали. Потом посчитал что это "исторически сложилось" и из-за незнания типа decimal. Оказывается, до сих пор в тренде )) Эхх, олдскульный, тепло-ламповый подход

3562 повідомлення
#10 років тому
Цитата (Hungry_Hunter):Вообще деньги лучше хранить в int а потом умножать/делить на 100.А можно еще почитать и использовать decimal :-D
UPD. Ну вот, чукча не читатель - чукча писатель, но пусть будет.
11416 повідомлень
#10 років тому
Цитата (tarakan_):из-за незнания типа decimal.
Цитата (SmartDesign):
А можно еще почитать и использовать decimal :-D
Когда-то тоже выбирал что использовать, вот эти аргументы убедили меня в использовании типа int.
Минусы:
- При неаккуратной работе (не через bcmath) можно ошибиться при умножении или делении
- Работа через bcmath медленее
- У разной валюты разное кол-во знаков поле запятой — если у вас мультивалютная система, будет избыточность данных. Придется делать более 2 знаков после запятой, но они будут нужны не всем
3562 повідомлення
#10 років тому
Когда я слышу "медленее" и "избыточно" сразу задаю вопрос о числах.Я вообще сильно сомневаюсь что внутри хранение децимала держит избыточные знаки если они не заданы, но даже если так это даже мельче чем экономия на спичках. Про скорость - вообще молчу, на фоне выборки из базы и перебора значений в ПХП - это точно мизер.
Что до ошибки в умножении или делении - не совсем понимаю о чем речь, работа с деньгами и так и так штука особенная =)
11416 повідомлень
#10 років тому
SmartDesign, c decimal не сравнивал, но int по сравнению с float работает быстрее в 6 раз 
3562 повідомлення
#10 років тому
Децимал - это инт со смещением ;-)работает "в 6 раз быстрее" - это какой-то рекламный лозунг, о какой "работе" идет речь?
11416 повідомлень
#10 років тому
<?php
$a = 1.2;
$b = 3.4;
for ($i=0;$i<1000000;$i++) {$c = bcdiv($a,$b,2);}
<?php
$a = 11.2;
$b = 3.4;
$a *= 100;
$b *= 100;
for ($i=0;$i<1000000;$i++) {$c = $a/$b; $c *= 100; $c = (int)$c; $c /= 100;}
Время работы первого 3,49 секунды, второго 0.57 секунды
3562 повідомлення
#10 років тому
Не касаясь вопроса методологии измерения и аналогичности операций: выигрыш в 3 секунды на одним миллионе операций это правильное приложений усилий?что до методологии - почему домножение на 100 вынесено из цикла?