За последние 24 часа нас посетили 17815 программистов и 1627 роботов. Сейчас ищет 1381 программист ...

Можно объединить несколько запросов в один?

Тема в разделе "MySQL", создана пользователем Sergey_Tsarev, 15 дек 2016.

  1. Sergey_Tsarev

    Sergey_Tsarev Активный пользователь

    С нами с:
    17 мар 2016
    Сообщения:
    502
    Симпатии:
    105
    Здравствуйте! есть база данных, примерно такая:

    TABLE.jpg

    Есть четыре запроса:
    Код (Text):
    1. UPDATE `item` SET `item_1` = `item_1` - 1  WHERE (`item_1` > 0) AND (`time`- $time >= 86400)
    2.  
    3. UPDATE `item` SET `item_2` = `item_2` - 1  WHERE (`item_2` > 0) AND (`time`- $time >= 86400)
    4.  
    5. UPDATE `item` SET `item_3` = `item_3` - 1  WHERE (`item_3` > 0) AND (`time`- $time >= 86400)
    6.  
    7. UPDATE `item` SET `item_4` = `item_4` - 1  WHERE (`item_4` > 0) AND (`time`- $time >= 86400)
    Возможно ли их объединить в один запрос? Спасибо.
     
  2. Deonis

    Deonis Старожил

    С нами с:
    15 фев 2013
    Сообщения:
    1.521
    Симпатии:
    504
    Объединить можно, но я не уверен, что такой запрос будет эффективней, чем четыре простых запроса.
    PHP:
    1. <?php
    2. $query = "UPDATE `tbl_name` SET
    3.  `item_1` = `item_1` - (CASE WHEN `item_1` > 0 AND `time`- $time >= 0 THEN 1 ELSE 0 END),
    4.  `item_2` = `item_2` - (CASE WHEN `item_2` > 0 AND `time`- $time >= 0  THEN 1 ELSE 0 END),
    5.  `item_3` = `item_3` - (CASE WHEN `item_3` > 0 AND `time`- $time >= 0  THEN 1 ELSE 0 END),
    6.  `item_4` = `item_4` - (CASE WHEN `item_4` > 0 AND `time`- $time >= 0  THEN 1 ELSE 0 END)";
     
    denis01 нравится это.
  3. Sergey_Tsarev

    Sergey_Tsarev Активный пользователь

    С нами с:
    17 мар 2016
    Сообщения:
    502
    Симпатии:
    105
    Спасибо за ответ. Вы думаете, что лучше оставить четыре простых запроса?
     
  4. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    лучше не делать четыре колонки.
     
    denis01 нравится это.
  5. Sergey_Tsarev

    Sergey_Tsarev Активный пользователь

    С нами с:
    17 мар 2016
    Сообщения:
    502
    Симпатии:
    105
    А как по-другому? В этих колонках разные данные и объединить их в одну не получится. Задача примерно такая: есть контейнер в котором 4 отделения. Если в одном отделении что-то лежит, то другие должны быть пусты. То-есть если Item_1 больше 0, то остальные item'ы будут равны 0. Но раз в сутки скрипт должен отнять единицу от Item'а, который больше 0.
     
  6. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    на вид там число. т.е. данные одинаковые. значит получится. =)
    --- Добавлено ---
    с правильной формулировки задачи начинается правильное решение. Хз какое оно, надо подумать. Но с формулировки "помогите смазать костыли" правильное решение не начинается.

    Навскидку могу предложить два поля - номер ящика и сколько в нём лежит.
     
    denis01 нравится это.
  7. Sergey_Tsarev

    Sergey_Tsarev Активный пользователь

    С нами с:
    17 мар 2016
    Сообщения:
    502
    Симпатии:
    105
    Согласен =) Просто когда знаешь что тебе нужно, кажется что и другим это тоже понятно. Попытаюсь объяснить все еще раз:

    PHP:
    1. <?php
    2. //есть массив данных
    3.  
    4. $item_arr = array('item_1' => 5, 'item_2' => 0, 'item_3' => 0, 'item_4' => 0, 'time' = 100000);
    5.  
    6. //только один из 4-х итемов больше 0, остальные равны 0.
    7. //на всякий случай проверяем
    8.  
    9. if ($item_arr['item_1'] > 0) {
    10.  
    11.     $item_1 = $item_arr['item_1'];
    12.     $item_2 = 0;
    13.     $item_3 = 0;
    14.     $item_4 = 0;
    15.    
    16. }
    17. else if ($item_arr['item_2'] > 0) {
    18.  
    19.     $item_1 = 0;
    20.     $item_2 = $item_arr['item_2'];
    21.     $item_3 = 0;
    22.     $item_4 = 0;
    23.    
    24. }
    25. else if ($item_arr['item_3'] > 0) {
    26.  
    27.     $item_1 = 0;
    28.     $item_2 = 0;
    29.     $item_3 = $item_arr['item_3'];
    30.     $item_4 = 0;
    31.    
    32. }
    33. else if ($item_arr['item_4'] > 0) {
    34.  
    35.     $item_1 = 0;
    36.     $item_2 = 0;
    37.     $item_3 = 0;
    38.     $item_4 = $item_arr['item_4'];;
    39.    
    40. }
    41.  
    42. //далее записываем в базу данных
    43.  
    44. mysqli_query($link, "INSERT INTO `items` (`item_1`, `item_2`, `item_3`, `item_4`, `time`) VALUES ('$item_1','$item_2','$item_3','$item_4','$item_arr['time'])");
    45.  
    46. ?>
    Вот, а раз в сутки мне нужно уменьшить те ячейки, которые больше 0 на единицу. Вопрос в том, можно ли это сделать одним запросом, или нужно делать четыре запроса. То есть по одному запросу для каждого поля item?
     
  8. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    можно, при той структуре, что я сказал. =)

     
  9. nasonov1990

    nasonov1990 Новичок

    С нами с:
    19 дек 2016
    Сообщения:
    2
    Симпатии:
    0
    а почему тогда лучше не делать четыре колонки?
     
  10. Sandulf

    Sandulf Новичок

    С нами с:
    11 дек 2016
    Сообщения:
    8
    Симпатии:
    1
    ИМХО так лучше:
    PHP:
    1. <?php
    2. //есть массив данных
    3. $item_arr = array(5, 0, 0, 0);
    4. $time = 100000;
    5. $new_arr = null;
    6. //только один из 4-х итемов больше 0, остальные равны 0.
    7. //на всякий случай проверяем
    8. foreach($item_arr as $k=>$v){
    9.     if($item_arr[$k] > 0){
    10.         $new_arr = [0,0,0,0];
    11.         $new_arr[$k] = $v;
    12.         break;
    13.     }
    14. }
    15.  
    16. if(is_null($new_arr)){
    17.  
    18.     // этой проверки в вашем коде небыло! т.е. если во всех ячейках числа <= 0.
    19.  
    20. }
    21. //далее записываем в базу данных
    22. $sql = [];
    23. foreach($new_arr as $k=>$v)
    24.     $sql[] = "(1, {$k+1}, $v, $time)";// $k+1 ради того чтобы был отсчет от 1, как у вас.
    25.     // Хотя, обычно у программистов отсчет от 0 всегда.
    26.  
    27. mysqli_query($link, "INSERT INTO `items` (`row`, `cell`, `value`, `time`) VALUES ".implode(', ',$sql));
    28.  
    29.  
    30. // РАЗ В СУТКИ
    31. $today = mktime(0,0,0); // это таймштамп начала текущих суток
    32. mysqli_query($link, "UPDATE `tbl_name` SET `value` = `value`-1 AND `time` = UNIX_TIMESTAMP()"
    33.     ." WHERE `time` < ".$today." AND `value` > 0");
    34. // такой подход к датам позволит ликвидировать опастность двойной обработки данных в пределах одних суток.
     
    Sergey_Tsarev нравится это.
  11. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    потому что если будут два поля - номер ящика и счётчик, то можно будет снижать счётчик у всей таблицы одним запросом не зависимо от того, в каком ящике что лежит.
     
  12. Sergey_Tsarev

    Sergey_Tsarev Активный пользователь

    С нами с:
    17 мар 2016
    Сообщения:
    502
    Симпатии:
    105
    Но получается, что строк в таблице будет больше?
     
  13. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    разве?
     
  14. Sandulf

    Sandulf Новичок

    С нами с:
    11 дек 2016
    Сообщения:
    8
    Симпатии:
    1
    Да. Но будет удобнее. А какая разница? БД создана ради того, чтобы работать с большим количеством строк. И она будет работать быстро, если ею правильно пользоваться. Такой вариант (когда строк больше) оптимальный, потому что будут быстро выполнятся запросы на выборку и обновление одинаково эффективно. В вашем же варианте 4 запроса на обновление вместо одного. Даже со всякими хитростями типа CASE все равно это получается костыль, а не нормальная и быстрая работа БД. Конечно, не забудьте добавить индексы.
     
  15. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    я не вижу почему строк будет больше, если может быть занят только один ящик из четырёх. Так же одна строка на четыре ящика с полями номер ящика и сколько лежит.
     
  16. Sergey_Tsarev

    Sergey_Tsarev Активный пользователь

    С нами с:
    17 мар 2016
    Сообщения:
    502
    Симпатии:
    105
    Я понял. Вы говорите о том, что в базу будет записывать только тот ящик, в котором что-то лежит, а пустые ящики записываться не будут?
     
  17. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    да. номер ящика и сколько лежит.
    --- Добавлено ---
    это позволяет одним запросом прогонять декремент по времени по всем записям в базе. и никаких дополнительных условий.
     
    Sergey_Tsarev нравится это.
  18. Sergey_Tsarev

    Sergey_Tsarev Активный пользователь

    С нами с:
    17 мар 2016
    Сообщения:
    502
    Симпатии:
    105
    Да, вы правы. Так будет действительно лучше. Спасибо!
     
  19. igordata

    igordata Суперстар
    Команда форума Модератор

    С нами с:
    18 мар 2010
    Сообщения:
    32.408
    Симпатии:
    1.768
    не за что