За последние 24 часа нас посетили 21764 программиста и 1690 роботов. Сейчас ищет 1851 программист ...

автоматический выбор Insert или Update

Тема в разделе "MySQL", создана пользователем DekaR, 21 янв 2008.

  1. DekaR

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

    С нами с:
    18 ноя 2006
    Сообщения:
    52
    Симпатии:
    0
    Уважаемы знатоки.Нужно проверить имеется ли запись в одной таблицы,и если есть -то обновить её из другой.Если нет -скопировать из другой .Я делаю это так :
    PHP:
    1.  
    2.  
    3. $c=mysql_query("Select * FROM `tmp_prod`");
    4. while ($array=mysql_fetch_row($c)){
    5. $q="Select * FROM `production` WHERE `name` ='$array[2]'";
    6. $c=mysql_query($q);
    7. if (mysql_num_rows($c)>0) {
    8. $q="UPDATE `production` SET `uploadflag`=100,`opt` ='$array[7]',`roznica`='$array[5]',`lopt`='$array[6]',`cout`='$array[8]' WHERE `name` ='$array[2]'";
    9. }else {
    10. $q="INSERT INTO `production` ( `rublica` , `group` , `name` , `about` , `korpus` , `roznica` , `lopt` , `opt` , `cout` , `id` , `file` , `folder` ,`uploadflag`,`mopt`,`mbopt` )
    11. VALUES ('$array[0]', '$array[1]', '$array[2]', '$array[3]', '$array[4]', '$array[5]', '$array[6]', '$array[7]','$array[8]','', '', '',100,10,100)";
    12. };
    13. };
    14.  
    как видно из кода приходится в цикле каждый раз запрашивать из одной базы.Решение не проходит по времени
    Можно ли оптимизировать что бы сделать одним запросом ?кто что предложит ?
    З.Ы, poduct и tmp_prod - полностью идентичные таблицы.
     
  2. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    insert ... on duplicate key update при уникальном индексе на поле.

    (mysql 4.1+)

    или insert ignore values (),(),(),...
    а потом update a,b set a.x=b.x
     
  3. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    дык нет у него этих values :)
    тут нужно что-нибудь типа insert .. select .. on dublicate key, но что-то мне подсказывает, что в мускуле это не сработает.
     
  4. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    пустые записи забить одним запросом, чтобы потом update отработал по всем нужным.
     
  5. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    и что даст это магическое действо?
     
  6. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    тупишь.
    перечти задачу ))

    сколько всего будет запросов?




    кстати это совсем тормознуто, даже с проверкой мог бы в массив один раз пхнуть идшники.
     
  7. dark-demon

    dark-demon Активный пользователь

    С нами с:
    16 фев 2007
    Сообщения:
    1.920
    Симпатии:
    1
    Адрес:
    леноград
    меня больше смущает "пустые записи забить одним запросом"
     
  8. DekaR

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

    С нами с:
    18 ноя 2006
    Сообщения:
    52
    Симпатии:
    0
    Значит подводя черту я понял следующие..Заводим поле которое будет служить индикатором запись новая или должна быть обновлена типа,например,enum .В результате получаем следующее :
    [sql]
    UPDATE `production` SET `uploadflag`='true';
    INSERT INTO `production` ( `rublica` , `group` , `name` , `about` , `korpus` , `roznica` , `lopt` , `opt` , `cout` , `id` , `file` , `folder` ,`uploadflag`,`mopt`,`mbopt` ) ignore
    VALUES ('$array[0]', '$array[1]', '$array[2]', '$array[3]', '$array[4]', '$array[5]', '$array[6]', '$array[7]','$array[8]','', '', '','false',10,100),.. и т.д.... ;
    update `production`,`tmp_prod` SET `production.rublica`=`tmp-prod.ruclica` ... WHERE `uploadflag`='true';
    [/sql]
    Таким образом.Все новые записи получают флаг false . А все старые мы обновляем.Правильно ?Не уверен в синтаксисе.
    [sql]
    Insert into `table` () IGNORE values (),(),() .... ;
    [/sql]
    Верно ?
     
  9. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    Сначала определись, как ТЫ САМ определяешь, запись надо обновить или добавить новую.
    В нормальной структуре это определяется по id записи, которая выставлена уникальным ключом.

    Тогда:
    [sql]Insert ignore into production select id,null,null,null,null, ... from tmp-prod where 1 #или что там у тебя[/sql]
    теперь в базе есть все записи, соответствующие исходной.
    [sql]update production, tmp_prod SET `production.rublica`=`tmp-prod.ruclica` where production.id=tmp-prod.id[/sql]
    проверять так оказывается ничего не надо.

    обрати внимание на where в условии update
    то, что написал ты
    будет последовательно обновлять каждую запись в production последовательно всеми значениями из tmp-prod
     
  10. DekaR

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

    С нами с:
    18 ноя 2006
    Сообщения:
    52
    Симпатии:
    0
    У всех записей и в обоих таблицах есть автоинкементные id.Но у записей с динаковыми именами (поля name) не обязательно будут одинаковые id.
    То есть как это соответствующие исходной ?В таблице tmp_prod все записи отлицаются как минимум двумя полями.
    where 1 - это что за монстр ?
    Это,если не ошибаюсь обновит ВСЕ записи.
     
  11. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    твоя задача - скопировать из таблицы tmp_prod записи в таблицу production
    , все из tmp_prod, или по какому то условию where
    Если это неверная формулировка и у тебя другая задача, излагай и формулируй так, чтобы было понятно.

    что мы делаем:
    1) выясняем (думаем мозгом головы), как выяснить, такая запись уже есть в production и ее надо обновить, или ее надо добавить новую. Как сравнить данные из tmp_prod и production
    По уму в tmp_prod хранится id из production
    как у тебя - я не в курсе. Тут ты даже не намекнул что понимаешь о чем я.

    2) если нам нужно целиком обновить эти записи в production, то делаем
    delete from production where $where
    insert into production select from tmp-prod where...

    3) если в записях, которые надо изменить, есть нужные поля, которые надо оставить, то делаем так:
    a) добавляем в production записи, которые надо добавить из tmp-prod, и которых в production еще нет. Пока добавляем пустые, только с id.
    b) теперь в production есть все записи, которые надо обновить.
    делаем update production, tmp_prod... - см. выше.
    это обновит все записи в production, которые есть в tmp-prod
    Если у тебя есть какое-то дополнительное условие, то добавляешь его в where


    И еще, если тебе даром стараются помочь - то попытайся разобраться, а не веди себя как наглый барин.
     
  12. DekaR

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

    С нами с:
    18 ноя 2006
    Сообщения:
    52
    Симпатии:
    0
    Прощу прощения если кого-то обидел.Просто,наверно не так выразился.Теперь начинаю понимать.
    Понял.У меня есть поля с именами деталей (name).Это и есть id.Короче мы добавляем все записи только заполняем только одно поле.А потом обновляем всё.Правильно ?
     
  13. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    да. Только сравнивать по ид с индексом будет несопоставимо быстрее.
    и так можно добавлять, если по полю уникальный индекс и дубль не добавится.
     
  14. DekaR

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

    С нами с:
    18 ноя 2006
    Сообщения:
    52
    Симпатии:
    0
    База сама по себе представляет каталог продукции.Сначала все наименования перегшружаются из cvs во временную базу (tmp_prod).А затем сначала я удаляю из конечной (production).Все наименования которые пропали из файла :
    [sql]DELETE FROM `production` WHERE NOT `name` = ANY(SELECT `name` FROM `tmp_prod`)[/sql]
    Поле `name` представляет собой наименование(т.е. то самое уникальное поле ).
    PHP:
    1.  
    2.  
    3. $c=mysql_query("Select * FROM `tmp_prod`");
    4. $q="INSERT INTO `production` (`name`) VALUES";
    5.  while ($array=mysql_fetch_row($c)){
    6.  $q="Select * FROM `production` WHERE `name` ='$array[2]'";
    7.  $c=mysql_query($q);
    8.  if (mysql_num_rows($c)=0) {
    9.  $q.="('$array[2]'),";
    10.  };};
    11. //Удаляем последнюю запятую
    12. $q=substr($q,0,strlen($q)-1);
    13. myql_query("update `production`, `tmp_prod` SET `production.rublica`=`tmp-prod.rublica`,`production.group`=`tmp-prod.group`,`production.about`=`tmp-prod.about`, .... where `production.name`=`tmp-prod.name`");
    14.  
    15.  
    Вот так.Сначала проходимся по всем записям и если их нет в production - добавляем ,заполняя только одно поле- name.Затем обновляем все записи.Правильно ?
     
  15. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    жесть. Сколько сравнений будет выполняться?
    Посмотри эту ветку.

    Нет, жесть - это очень мягко.
    Та продукция, что ты уже продал и новой нет, пропадает безвозвратно и ты никогда не найдешь что там было? Заказы по ним, клики или еще что-то?
    Еще раз, если в оставшихся записях нет нужных данных, то делается просто
    truncate table
    и insert select

    Но система очень странная, я даже не знаю с какого конца начинать. Неправильно ВСЕ.
     
  16. DekaR

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

    С нами с:
    18 ноя 2006
    Сообщения:
    52
    Симпатии:
    0
    Так мне и нужно "безаозвратно".Это одно из требований.
     
  17. DekaR

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

    С нами с:
    18 ноя 2006
    Сообщения:
    52
    Симпатии:
    0
    Работать моё творение не хочет .Пишет-сервер "ушел" ( MySQL server has gone away).Что это значит ?

    p.s. Прощу прощения ха навязчивость.Но сам что-то пока разобраться не могу.