php - stackoverflow - set sql_mode=( select replace(@@ sql_mode only_full_group_by
INSERTAR IGNORAR usando Codeigniter (12)
Acabo de encontrar esto, puede ayudar http://www.amplio.ch/blog/web-development/codeigniter-active-record-class-and-insert-ignore/ , aunque es un truco de ci
Estoy tratando de insertar algunas filas en la tabla MySQL usando Codeigniter y Active Records.
Código PHP
$data = array(''......''); // some rows of data to insert
$this->db->insert_batch(''my_table'', $data);
Sin embargo, esto puede provocar que se inserten filas duplicadas en la tabla. Para manejar la inserción de datos duplicados, planeo usar el INSERT IGNORE
para no insertar la fila si la fila es un duplicado.
Problema: no puedo encontrar el equivalente INSERT IGNORE
en Active Records y no quiero editar la clase Active Record. ¿Hay otras alternativas?
Lo siguiente parece interesante, pero si hago lo siguiente, ¿no se ejecutará la consulta dos veces?
$insert_query = $this->db->insert_batch(''my_table'', $data); // QUERY RUNS ONCE
$insert_query = str_replace(''INSERT INTO'',''INSERT IGNORE INTO'',$insert_query);
$this->db->query($insert_query); // QUERY RUNS A SECOND TIME
Como también encontré un problema similar, finalmente elegí una solución un poco más "elegante" como la de abajo. Una consulta completa de inserción_batch que es algo que usa las transacciones AND de respuesta de Rocket:
$this->db->trans_start();
foreach ($items as $item) {
$insert_query = $this->db->insert_string(''table_name'', $item);
$insert_query = str_replace(''INSERT INTO'', ''INSERT IGNORE INTO'', $insert_query);
$this->db->query($insert_query);
}
$this->db->trans_complete();
Eso también incluirá todo en una transacción que resulte en una consulta más rápida, como hacer un insert_batch (). Bueno, no tan rápido como insert_batch () pero más rápido que una sola consulta para cada entrada, por supuesto. Espero que ayude a alguien.
Esto es básicamente una modificación de la sugerencia de Rocket Hazmat, que es genial, pero no tiene en cuenta el hecho de que str_replace opera en toda la cadena y puede afectar inadvertidamente los datos.
$insert_query = $this->db->insert_string(''my_table'', $data);
$insert_query = preg_replace(''/INSERT INTO/'',''INSERT IGNORE INTO'',$insert_query,1);
$this->db->query($insert_query);
Evite las filas duplicadas estableciendo una clave única en la tabla de la base de datos para al menos uno de los campos.
No es muy recomendable, pero aquí hay un truco para preservar la inserción del lote (que es más eficiente que Mysql)
// try to insert as usual first
$this->db->insert_batch(''my_table'', $data);
// if it fails resort to IGNORE
if($this->db->_error_message())
{
$sql = $this->db->last_query();
$sql = str_replace(''INSERT INTO'', ''INSERT IGNORE INTO'', $sql);
$this->db->query($sql);
}
No use insert_batch
, ya que realmente ejecuta la consulta. Quieres insert_string
$insert_query = $this->db->insert_string(''my_table'', $data);
$insert_query = str_replace(''INSERT INTO'',''INSERT IGNORE INTO'',$insert_query);
$this->db->query($insert_query);
ACTUALIZACIÓN : Esto no funciona para consultas por lotes, solo una fila a la vez.
Para este propósito hice esta función de ayudante:
function insert_batch_string($table='''',$data=[],$ignore=false){
$CI = &get_instance();
$sql = '''';
if ($table && !empty($data)){
$rows = [];
foreach ($data as $row) {
$insert_string = $CI->db->insert_string($table,$row);
if(empty($rows) && $sql ==''''){
$sql = substr($insert_string,0,stripos($insert_string,''VALUES''));
}
$rows[] = trim(substr($insert_string,stripos($insert_string,''VALUES'')+6));
}
$sql.='' VALUES ''.implode('','',$rows);
if ($ignore) $sql = str_ireplace(''INSERT INTO'', ''INSERT IGNORE INTO'', $sql);
}
return $sql;
}
Puede hacer la inserción de lote y la inserción de lote con ignorar. Para evitar filas duplicadas, debe establecer una clave única en la tabla de la base de datos para un campo primario.
Para las cargas por lotes, es posible que necesite algo más como:
foreach ($data as $data_item) {
$insert_query = $this->db->insert_string(''my_table'', $data_item);
$insert_query = str_replace(''INSERT INTO'', ''INSERT IGNORE INTO'', $insert_query);
$this->db->query($insert_query);
}
ACTUALIZACIÓN: utilice la versión de dcostalis (en los comentarios debajo de este), escalará mucho mejor :-)
Usando la técnica de su segunda idea, podría generar una consulta al recorrer la matriz y usar:
$this->db->query($query_string);
Yo también tuve el mismo problema, lo que me ayudó es:
Abierto: Codeigniter / system / database / DB_query_builder.php :
encontrar
protected function _insert_batch($table, $keys, $values)
{
return ''INSERT INTO ''.$table.'' (''.implode('', '', $keys).'') VALUES ''.implode('', '', $values);
}
y reemplazar con:
protected function _insert_batch($table, $keys, $values)
{
return ''INSERT IGNORE INTO ''.$table.'' (''.implode('', '', $keys).'') VALUES ''.implode('', '', $values);
}
agregar al archivo DB_query_builder.php
estas 2 funciones
public function insert_ignore_batch($table = '''', $set = NULL, $escape = NULL) {
if ($set !== NULL)
{
$this->set_insert_batch($set, '''', $escape);
}
if (count($this->qb_set) === 0)
{
// No valid data array. Folds in cases where keys and values did not match up
return ($this->db_debug) ? $this->display_error(''db_must_use_set'') : FALSE;
}
if ($table === '''')
{
if ( ! isset($this->qb_from[0]))
{
return ($this->db_debug) ? $this->display_error(''db_must_set_table'') : FALSE;
}
$table = $this->qb_from[0];
}
// Batch this baby
$affected_rows = 0;
for ($i = 0, $total = count($this->qb_set); $i < $total; $i += 100)
{
$this->query($this->_insert_ignore_batch($this->protect_identifiers($table, TRUE, $escape, FALSE), $this->qb_keys, array_slice($this->qb_set, $i, 100)));
$affected_rows += $this->affected_rows();
}
$this->_reset_write();
return $affected_rows;
}
protected function _insert_ignore_batch($table, $keys, $values) {
return ''INSERT IGNORE INTO ''.$table.'' (''.implode('', '', $keys).'') VALUES ''.implode('', '', $values);
}
utilizando:
$this->db->insert_ignore_batch(''TableName'', $data);
solución:
$sql = $this->db->set($data)->get_compiled_insert($table);
$sql = str_replace(''INSERT INTO'', ''INSERT IGNORE INTO'', $sql);
$this->db->query($sql);
funciona en codeigniter 3.0.6 :)