通过一个php数组插入多行到MySQL
我通过PHP使用插入命令传递一个大的数据集到一个MySQL表,我想知道是否有可能通过一个查询,而不是追加一个英里长的string结束每个值,然后一次约1000行,然后执行它。 我正在使用codeigniter框架,所以它的function也可以给我。
使用多行组合一个INSERT
语句比在每行中使用一个INSERT
语句要快得多。
这就是说,这听起来像你可能会遇到PHP中的string处理问题,这实际上是一个algorithm问题,而不是语言问题。 基本上,当处理大string时,您希望尽量减less不必要的复制。 主要是,这意味着你想避免串联。 build立一个大string的最快和最有效的方法是利用implode()
函数和数组赋值。
$sql = array(); foreach( $data as $row ) { $sql[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')'; } mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $sql));
这种方法的好处在于,不要复制和重新复制到目前为止每个并置的SQL语句; 相反,PHP在implode()
语句中做了一次 。 这是一个很大的胜利。
如果有许多列放在一起,而且一个或多个列很长,则还可以构build一个内部循环来执行相同的操作,并使用implode()
将values子句分配给外部数组。
codeigniter现在支持多个插入/批量插入。 我有同样的问题。 虽然回答问题已经很晚了,但是会帮助别人。 这就是为什么回答这个问题。
$data = array( array( 'title' => 'My title' , 'name' => 'My Name' , 'date' => 'My date' ), array( 'title' => 'Another title' , 'name' => 'Another Name' , 'date' => 'Another date' ) ); $this->db->insert_batch('mytable', $data); // Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')
您可以使用mysqli_stmt类准备查询插入一行,然后遍历数据数组。 就像是:
$stmt = $db->stmt_init(); $stmt->prepare("INSERT INTO mytbl (fld1, fld2, fld3, fld4) VALUES(?, ?, ?, ?)"); foreach($myarray as $row) { $stmt->bind_param('idsb', $row['fld1'], $row['fld2'], $row['fld3'], $row['fld4']); $stmt->execute(); } $stmt->close();
“idsb”是你绑定的数据的types(int,double,string,blob)。
我知道这是一个古老的查询,但我只是阅读,并认为我会补充我在其他地方发现的:
在PHP 5中的mysqli是一个ojbect与一些很好的function,可以让你加快上述答案的插入时间:
$mysqli->autocommit(FALSE); $mysqli->multi_query($sqlCombined); $mysqli->autocommit(TRUE);
插入多行时closures自动提交大大加快了插入的速度,因此closures它,然后执行上面提到的操作,或者只是创build一个string(sqlCombined),它是用分号分隔的很多插入语句,而多重查询就可以很好地处理它们。
希望这有助于节省时间(search和插入!)
[R
那么,你不想执行1000个查询调用,但这样做是好的:
$stmt= array( 'array of statements' ); $query= 'INSERT INTO yourtable (col1,col2,col3) VALUES '; foreach( $stmt AS $k => $v ) { $query.= '(' .$v. ')'; // NOTE: you'll have to change to suit if ( $k !== sizeof($stmt)-1 ) $query.= ', '; } $r= mysql_query($query);
根据您的数据源,填充数组可能就像打开文件并通过file()
将内容转储到数组一样简单。
你总是可以使用mysql的LOAD DATA
:
LOAD DATA LOCAL INFILE '/full/path/to/file/foo.csv' INTO TABLE `footable` FIELDS TERMINATED BY ',' LINES TERMINATED BY '\r\n'
做批量插入而不是使用一堆INSERT
语句。
$query= array(); foreach( $your_data as $row ) { $query[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')'; } mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $query));
我创build了一个执行多行的类,用法如下:
$pdo->beginTransaction(); $pmi = new PDOMultiLineInserter($pdo, "foo", array("a","b","c","e"), 10); $pmi->insertRow($data); // .... $pmi->insertRow($data); $pmi->purgeRemainingInserts(); $pdo->commit();
该类定义如下:
class PDOMultiLineInserter { private $_purgeAtCount; private $_bigInsertQuery, $_singleInsertQuery; private $_currentlyInsertingRows = array(); private $_currentlyInsertingCount = 0; private $_numberOfFields; private $_error; private $_insertCount = 0; /** * Create a PDOMultiLine Insert object. * * @param PDO $pdo The PDO connection * @param type $tableName The table name * @param type $fieldsAsArray An array of the fields being inserted * @param type $bigInsertCount How many rows to collect before performing an insert. */ function __construct(PDO $pdo, $tableName, $fieldsAsArray, $bigInsertCount = 100) { $this->_numberOfFields = count($fieldsAsArray); $insertIntoPortion = "REPLACE INTO `$tableName` (`".implode("`,`", $fieldsAsArray)."`) VALUES"; $questionMarks = " (?".str_repeat(",?", $this->_numberOfFields - 1).")"; $this->_purgeAtCount = $bigInsertCount; $this->_bigInsertQuery = $pdo->prepare($insertIntoPortion.$questionMarks.str_repeat(", ".$questionMarks, $bigInsertCount - 1)); $this->_singleInsertQuery = $pdo->prepare($insertIntoPortion.$questionMarks); } function insertRow($rowData) { // @todo Compare speed // $this->_currentlyInsertingRows = array_merge($this->_currentlyInsertingRows, $rowData); foreach($rowData as $v) array_push($this->_currentlyInsertingRows, $v); // if (++$this->_currentlyInsertingCount == $this->_purgeAtCount) { if ($this->_bigInsertQuery->execute($this->_currentlyInsertingRows) === FALSE) { $this->_error = "Failed to perform a multi-insert (after {$this->_insertCount} inserts), the following errors occurred:".implode('<br/>', $this->_bigInsertQuery->errorInfo()); return false; } $this->_insertCount++; $this->_currentlyInsertingCount = 0; $this->_currentlyInsertingRows = array(); } return true; } function purgeRemainingInserts() { while ($this->_currentlyInsertingCount > 0) { $singleInsertData = array(); // @todo Compare speed - http://www.evardsson.com/blog/2010/02/05/comparing-php-array_shift-to-array_pop/ // for ($i = 0; $i < $this->_numberOfFields; $i++) $singleInsertData[] = array_pop($this->_currentlyInsertingRows); array_reverse($singleInsertData); for ($i = 0; $i < $this->_numberOfFields; $i++) array_unshift($singleInsertData, array_pop($this->_currentlyInsertingRows)); if ($this->_singleInsertQuery->execute($singleInsertData) === FALSE) { $this->_error = "Failed to perform a small-insert (whilst purging the remaining rows; the following errors occurred:".implode('<br/>', $this->_singleInsertQuery->errorInfo()); return false; } $this->_currentlyInsertingCount--; } } public function getError() { return $this->_error; } }
在codeigniter中使用插入批次来插入多行数据。
$this->db->insert_batch('tabname',$data_array); // $data_array holds the value to be inserted
你可以用codeigniter中的几种方法做到这一点
先循环
foreach($myarray as $row) { $data = array("first"=>$row->first,"second"=>$row->sec); $this->db->insert('table_name',$data); }
第二个 – 通过插入批处理
$data = array( array( 'first' => $myarray[0]['first'] , 'second' => $myarray[0]['sec'], ), array( 'first' => $myarray[1]['first'] , 'second' => $myarray[1]['sec'], ), ); $this->db->insert_batch('table_name', $data);
第三种方式 – 通过多重价值传递
$sql = array(); foreach( $myarray as $row ) { $sql[] = '("'.mysql_real_escape_string($row['first']).'", '.$row['sec'].')'; } mysql_query('INSERT INTO table (first, second) VALUES '.implode(',', $sql));
我已经创build了这个简单的function,你可以轻松使用。 您将需要传递表名($tbl)
,表字段($insertFieldsArr)
对插入数据,数据数组($arr)
。
insert_batch('table',array('field1','field2'),$dataArray); function insert_batch($tbl,$insertFieldsArr,$arr){ $sql = array(); foreach( $arr as $row ) { $strVals=''; $cnt=0; foreach($insertFieldsArr as $key=>$val){ if(is_array($row)){ $strVals.="'".mysql_real_escape_string($row[$cnt]).'\','; } else{ $strVals.="'".mysql_real_escape_string($row).'\','; } $cnt++; } $strVals=rtrim($strVals,','); $sql[] = '('.$strVals.')'; } $fields=implode(',',$insertFieldsArr); mysql_query('INSERT INTO `'.$tbl.'` ('.$fields.') VALUES '.implode(',', $sql)); }
虽然回答这个问题为时已晚。 这是我的同样的答案。
如果您使用的是CodeIgniter,则可以使用query_builder类中定义的内置方法。
$这个- > DB-> insert_batch()
根据您提供的数据生成插入string,并运行查询。 您可以将数组或对象传递给函数。 这是一个使用数组的例子:
$data = array( array( 'title' => 'My title', 'name' => 'My Name', 'date' => 'My date' ), array( 'title' => 'Another title', 'name' => 'Another Name', 'date' => 'Another date' )
);
$this->db->insert_batch('mytable', $data); // Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')
第一个参数将包含表名,第二个参数是一个值的关联数组。
你可以在这里find关于query_builder的更多细节
use this in codeigniter for multiple data insertion $data = array( array( 'title' => 'My title' , 'name' => 'My Name' , 'date' => 'My date' ), array( 'title' => 'Another title' , 'name' => 'Another Name' , 'date' => 'Another date' ) ); $this->db->insert_batch('mytable', $data); // Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date')