简体   繁体   中英

Laravel 5.2 Builder insert replace multiple rows

I have this code, can insert an array at first time, but when trying replace and update, it returns error

Integrity constraint violation: 1062 Duplicate entry for composite key ['periodo_id','asociado_id']

Model:

<?php
 namespace App;
 use Illuminate\Database\Eloquent\Model;
 class Lectura extends Model
 {
  protected $primaryKey = array('periodo_id', 'asociado_id');
  public $timestamps = false;
  public $incrementing = false;     
 }

And controller:

$rows = DB::table('lecturas_temp')->get(); 
$arr = array();
foreach ($rows as $row) {
   $a = [
        'asociado_id' => $row->asociado_id,
        'periodo_id'  => $request->periodo_id,
        'nombre'      => $row->nombre,
    ];
   array_push($arr, $a);
}
DB::table('lecturas')->insert($arr);

Any alternatives to line DB::table('lecturas')->insert($arr) ?

I tried Eloquent Lectura::insert($arr) and updateOrCreate but same results;

The error message is crystal clear. You are using a composite key ['periodo_id', 'asociado_id'] , which means you cannot insert the same data twice because you defined it as your primary key.

If you are expecting to have duplicate composite key, then please, remove it from your model as the primary key. However, if you want the data to be unique, you should use updateOrCreate() .

$rows = DB::table('lecturas_temp')->get(); 
$arr = array();
foreach ($rows as $row) {
    Lectura::updateOrCreate(
        [
            'asociado_id' => $row->asociado_id,
            'periodo_id'  => $request->periodo_id
        ],
        [
            'nombre'      => $row->nombre
        ]
    );
}

As you can see, updateOrCreate() takes 2 arrays as arguments. The first array is the elements used to verify if it already exists. Also, unfortunately you will have to do it one by one instead all in one go as you were doing.

If you want to stick to the query builder, you can use DB::updateOrInsert() , with the same call signature (passing 2 arrays).

Using this code I did solved: https://github.com/yadakhov/insert-on-duplicate-key

class Lectura extends Model
{

  protected $primaryKey = array('periodo_id', 'asociado_id');
  public $timestamps = false;
  public $incrementing = false;


public static function insertOnDuplicateKey(array $data, array $updateColumns = null)
{
    if (empty($data)) {
        return false;
    }
    // Case where $data is not an array of arrays.
    if (!isset($data[0])) {
        $data = [$data];
    }
    $sql = static::buildInsertOnDuplicateSql($data, $updateColumns);
    $data = static::inLineArray($data);
    return self::getModelConnectionName()->affectingStatement($sql, $data);
}
/**
 * Insert using mysql INSERT IGNORE INTO.
 *
 * @param array $data
 *
 * @return int 0 if row is ignored, 1 if row is inserted
 */
public static function insertIgnore(array $data)
{
    if (empty($data)) {
        return false;
    }
    // Case where $data is not an array of arrays.
    if (!isset($data[0])) {
        $data = [$data];
    }
    $sql = static::buildInsertIgnoreSql($data);
    $data = static::inLineArray($data);
    return self::getModelConnectionName()->affectingStatement($sql, $data);
}
/**
 * Insert using mysql REPLACE INTO.
 *
 * @param array $data
 *
 * @return int 1 if row is inserted without replacements, greater than 1 if rows were replaced
 */
public static function replace(array $data)
{
    if (empty($data)) {
        return false;
    }
    // Case where $data is not an array of arrays.
    if (!isset($data[0])) {
        $data = [$data];
    }
    $sql = static::buildReplaceSql($data);
    $data = static::inLineArray($data);
    return self::getModelConnectionName()->affectingStatement($sql, $data);
}
/**
 * Static function for getting table name.
 *
 * @return string
 */
public static function getTableName()
{
    $class = get_called_class();
    return (new $class())->getTable();
}
/**
* Static function for getting connection name
*
* @return string
*/
public static function getModelConnectionName()
{
    $class = get_called_class();
    return (new $class())->getConnection();
}
/**
 * Get the table prefix.
 *
 * @return string
 */
public static function getTablePrefix()
{
    return self::getModelConnectionName()->getTablePrefix();
}
/**
 * Static function for getting the primary key.
 *
 * @return string
 */
public static function getPrimaryKey()
{
    $class = get_called_class();
    return (new $class())->getKeyName();
}
/**
 * Build the question mark placeholder.  Helper function for insertOnDuplicateKeyUpdate().
 * Helper function for insertOnDuplicateKeyUpdate().
 *
 * @param $data
 *
 * @return string
 */
protected static function buildQuestionMarks($data)
{
    $lines = [];
    foreach ($data as $row) {
        $count = count($row);
        $questions = [];
        for ($i = 0; $i < $count; ++$i) {
            $questions[] = '?';
        }
        $lines[] = '(' . implode(',', $questions) . ')';
    }
    return implode(', ', $lines);
}
/**
 * Get the first row of the $data array.
 *
 * @param array $data
 *
 * @return mixed
 */
protected static function getFirstRow(array $data)
{
    if (empty($data)) {
        throw new \InvalidArgumentException('Empty data.');
    }
    list($first) = $data;
    if (!is_array($first)) {
        throw new \InvalidArgumentException('$data is not an array of array.');
    }
    return $first;
}
/**
 * Build a value list.
 *
 * @param array $first
 *
 * @return string
 */
protected static function getColumnList(array $first)
{
    if (empty($first)) {
        throw new \InvalidArgumentException('Empty array.');
    }
    return '`' . implode('`,`', array_keys($first)) . '`';
}
/**
 * Build a value list.
 *
 * @param array $first
 *
 * @return string
 */
protected static function buildValuesList(array $first)
{
    $out = [];
    foreach (array_keys($first) as $key) {
        $out[] = sprintf('`%s` = VALUES(`%s`)', $key, $key);
    }
    return implode(', ', $out);
}
/**
 * Inline a multiple dimensions array.
 *
 * @param $data
 *
 * @return array
 */
protected static function inLineArray(array $data)
{
    return call_user_func_array('array_merge', array_map('array_values', $data));
}
/**
 * Build the INSERT ON DUPLICATE KEY sql statement.
 *
 * @param array $data
 * @param array $updateColumns
 *
 * @return string
 */
protected static function buildInsertOnDuplicateSql(array $data, array $updateColumns = null)
{
    $first = static::getFirstRow($data);
    $sql  = 'INSERT INTO `' . static::getTablePrefix() . static::getTableName() . '`(' . static::getColumnList($first) . ') VALUES' . PHP_EOL;
    $sql .=  static::buildQuestionMarks($data) . PHP_EOL;
    $sql .= 'ON DUPLICATE KEY UPDATE ';
    if (empty($updateColumns)) {
        $sql .= static::buildValuesList($first);
    } else {
        $sql .= static::buildValuesList(array_combine($updateColumns, $updateColumns));
    }
    return $sql;
}
/**
 * Build the INSERT IGNORE sql statement.
 *
 * @param array $data
 *
 * @return string
 */
protected static function buildInsertIgnoreSql(array $data)
{
    $first = static::getFirstRow($data);
    $sql  = 'INSERT IGNORE INTO `' . static::getTablePrefix() . static::getTableName() . '`(' . static::getColumnList($first) . ') VALUES' . PHP_EOL;
    $sql .=  static::buildQuestionMarks($data);
    return $sql;
}
/**
 * Build REPLACE sql statement.
 *
 * @param array $data
 *
 * @return string
 */
protected static function buildReplaceSql(array $data)
{
    $first = static::getFirstRow($data);
    $sql  = 'REPLACE INTO `' . static::getTablePrefix() . static::getTableName() . '`(' . static::getColumnList($first) . ') VALUES' . PHP_EOL;
    $sql .=  static::buildQuestionMarks($data);
    return $sql;
}

In Controller

Lectura::replace($arr);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM