SQL:只将新行/记录插入表中?

时间:2009-10-31 11:25:05

标签: php mysql sql zend-framework zend-db

我正在定期解析json feed,只需要插入feed中的最新用户并忽略现有用户。

根据一些搜索,我认为我需要的是ON DUPLICATE KEY UPDATEINSERT IGNORE,但我不太确定我问的是什么原因 - 例如:

users
1     John
2     Bob

部分JSON:

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

从这个Feed中我只想插入Jeff。我可以通过所有用户做一个简单的循环,并做一个简单的SELECT查询,看看用户id是否已经在表中,如果不是我做INSERT,但我怀疑它不是一个有效和实用的方法。

顺便说一下,如果有人愿意提供具体的答案,我正在使用Zend_Db进行数据库交互:)我不介意一般的战略解决方案。

5 个答案:

答案 0 :(得分:5)

ON DUPLICATE KEY UPDATE替代方案允许您将更新与插入决策引用到数据库:

INSERT INTO table (userid, name) VALUES (2, 'Bobby');
  ON DUPLICATE KEY UPDATE name = 'Bobby';
如果已存在具有用户标识2的条目,则

会将名称字段更新为“Bobby”。

如果您向UPDATE提供无效操作,则可以将其用作INSERT IGNORE的替代方法:

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

如果用户标识2已存在,则无效,从而避免了警告和吞下使用INSERT IGNORE时出现的其他错误。


另一种选择是REPLACE

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

如果用户标识2尚不存在,这将执行正常插入。如果它确实存在,它将首先删除旧条目,然后插入一个新条目。


请注意,这两个版本都是SQL的MySQL特定扩展。

答案 1 :(得分:4)

对于Zend Framework,我所做的是insert语句的try / catch,并根据异常代码采取进一步的操作:

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 :(得分:2)

您需要将userid定义为PRIMARY或UNIQUE键,并使用类似:

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

如果用户ID 2已经存在,它将忽略并继续下一个插入。

您还可以在表架构上使用ON DUPLICATE KEY UPDATE。 另一种选择可能是使用REPLACE INTO语法。

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

这将尝试INSERT,如果记录已经存在,它将在再次插入之前删除它。

答案 3 :(得分:1)

我的解决方案:

/**
 * 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();
}

答案 4 :(得分:0)

在循环中,如果没有行受影响,您可以先进行更新,这意味着它是一个新条目。跟踪那些“失败的更新”,然后将它们作为新条目插入。

我不熟悉Zend_Db,但我认为它可以返回更新是否会影响行数。