SQL: вставлять только новые строки / записи в таблицу? - PullRequest
5 голосов
/ 31 октября 2009

Я регулярно анализирую фид json, и мне нужно вставить только новых пользователей из фида и игнорировать существующих.

Я думаю, что мне нужно ON DUPLICATE KEY UPDATE или INSERT IGNORE на основе некоторых поисков, но я не совсем уверен, поэтому я спрашиваю - так, например:

users
1     John
2     Bob

Частично JSON:

{ userid:1, name:'John' },
{ userid:2, name:'Bob' },
{ userid:3, name:'Jeff' }

Из этого канала я хочу вставить только Джефф. Я мог бы сделать простой цикл для всех пользователей и сделать простой запрос SELECT и посмотреть, есть ли идентификатор пользователя в таблице, если нет, я делаю INSERT, однако я подозреваю, что это не будет эффективным и практичным методом.

Кстати, я использую Zend_Db для взаимодействия с базой данных, если кто-то захочет обслужить конкретный ответ :) Хотя я не против универсального стратегического решения.

Ответы [ 5 ]

5 голосов
/ 31 октября 2009

Альтернатива ON DUPLICATE KEY UPDATE позволяет передать решение об обновлении и вставке в базу данных:

INSERT INTO table (userid, name) VALUES (2, 'Bobby');
  ON DUPLICATE KEY UPDATE name = 'Bobby';

изменит поле имени на «Бобби», если запись с идентификатором пользователя 2 уже существует.

Вы можете использовать его как альтернативу INSERT IGNORE, если вы предоставляете ОБНОВЛЕНИЕ неэффективной операции:

INSERT INTO table (userid, name) VALUES (2, 'Bobby');
  ON DUPLICATE KEY UPDATE name = name;

Это ничего не даст, если ID пользователя 2 уже существует, что позволяет избежать предупреждения и проглатывания других ошибок, которые вы получите при использовании INSERT IGNORE.


Другой альтернативой будет REPLACE:

REPLACE INTO table (userid, name) VALUES (2, 'Bobby');

Это сделает обычную вставку, если идентификатор пользователя 2 еще не существует. Если он существует, он сначала удалит старую запись, а затем вставит новую.


Помните, что обе версии являются специфическими расширениями MySQL для SQL.

4 голосов
/ 24 октября 2011

Для Zend Framework я делаю попытку / перехват оператора вставки и предпринимаю дальнейшие действия на основе кода исключения:

class Application_Model_DbTable_MyModel extends Zend_Db_Table_Abstract

    public function insert($aData, $bIgnore = false) 
    {

        try 
        {
            $id =  parent::insert($aData);
        } 
        catch(Zend_Db_Statement_Mysqli_Exception $e) 
        {
            // code 1062: Mysqli statement execute error : Duplicate entry
            if($bIgnore && $e->getCode() == 1062) 
            {
                // continue;
            } 
            else 
            {
                throw $e;
            }
        }
        return !empty($id) ? $id : false;
    }
}
2 голосов
/ 31 октября 2009

Вам необходимо определить идентификатор пользователя как ПЕРВИЧНЫЙ или УНИКАЛЬНЫЙ ключ и использовать что-то вроде:

INSERT IGNORE INTO table (userid, name) VALUES (2, 'Bob');

Если идентификатор пользователя 2 уже существует, он будет игнорироваться и перейдет к следующей вставке.

Вы также можете использовать ON DUPLICATE KEY UPDATE в вашей схеме таблицы. Другой альтернативой может быть использование синтаксиса REPLACE INTO.

REPLACE INTO table (userid, name) VALUES (2, 'Bob');

Это попытается ВСТАВИТЬ, если запись уже существует, УДАЛИТЕ ее до ВСТАВКИ в нее снова.

1 голос
/ 15 января 2013

Мое решение:

/**
 * Perform an insert with the IGNORE word
 *
 * @param $data array
 * @return number the number of rows affected
 */
public function insertIgnore(array $data)
{
    // Start of query
    $sql = sprintf("INSERT IGNORE INTO %s (", $this->getAdapter()->quoteIdentifier($this->info('name')));
    // Retrieve column identifiers
    $identifiers = array_keys($data);
    foreach ($identifiers as $key => $value) {
        // Quote identifier
        $identifiers[$key] = $this->getAdapter()->quoteIdentifier($value);
    }
    // Concat column identifiers
    $sql .= implode(', ', $identifiers);
    $sql .= ") VALUES (";
    foreach ($data as $key => $value) {
        // Quote values
        $data[$key] = $this->getAdapter()->quote($value);
    }
    // Concat values identifiers
    $sql .= implode(', ', $data);
    $sql .= ")";
    // Process the query
    return $this->getAdapter()->query($sql)->rowCount();
}
0 голосов
/ 31 октября 2009

В цикле вы можете сначала выполнить обновление, если строка не затронута, значит, это новая запись. Следите за этими «неудачными обновлениями», а затем вставляйте их как новые записи.

Я не знаком с Zend_Db, но предполагаю, что он может вернуть, повлияло ли обновление на количество строк.

...