PDO Prepared在单个查询中插入多行
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PDO Prepared在单个查询中插入多行相关的知识,希望对你有一定的参考价值。
我目前在mysql上使用这种类型的SQL在一个查询中插入多行值:
INSERT INTO `tbl` (`key1`,`key2`) VALUES ('r1v1','r1v2'),('r2v1','r2v2'),...
在PDO上的读数中,使用预处理语句应该比静态查询具有更好的安全性。
因此,我想知道是否可以使用预准备语句生成“通过使用一个查询插入多行值”。
如果是,我可以知道如何实施它?
使用PDO准备语句插入多个值
在一个execute语句中插入多个值。为什么因为根据this page它比常规插入更快。
$datafields = array('fielda', 'fieldb', ... );
$data[] = array('fielda' => 'value', 'fieldb' => 'value' ....);
$data[] = array('fielda' => 'value', 'fieldb' => 'value' ....);
更多数据值,或者您可能有一个填充数据的循环。
使用准备好的插入,您需要知道要插入的字段以及要创建的字段数?占位符绑定您的参数。
insert into table (fielda, fieldb, ... ) values (?,?...), (?,?...)....
这基本上就是我们想要insert语句的样子。
现在,代码:
function placeholders($text, $count=0, $separator=","){
$result = array();
if($count > 0){
for($x=0; $x<$count; $x++){
$result[] = $text;
}
}
return implode($separator, $result);
}
$pdo->beginTransaction(); // also helps speed up your inserts.
$insert_values = array();
foreach($data as $d){
$question_marks[] = '(' . placeholders('?', sizeof($d)) . ')';
$insert_values = array_merge($insert_values, array_values($d));
}
$sql = "INSERT INTO table (" . implode(",", $datafields ) . ") VALUES " .
implode(',', $question_marks);
$stmt = $pdo->prepare ($sql);
try {
$stmt->execute($insert_values);
} catch (PDOException $e){
echo $e->getMessage();
}
$pdo->commit();
虽然在我的测试中,当使用多个插入物和常规准备的单值插入物时,只有1秒的差异。
这就是我做的方式:
首先定义您将使用的列名,或将其留空,并且pdo将假定您要使用表中的所有列 - 在这种情况下,您需要按照它们在表上显示的确切顺序通知行值。
<?php
/**
* $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;
function __construct(\PDO $pdo, $tableName, $fieldsAsArray, $bigInsertCount = 100) {
$this->_numberOfFields = count($fieldsAsArray);
$insertIntoPortion = "INSERT 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;
}
}
现在,假设您已经准备好了二维数组。迭代它,并使用行值构造一个字符串,如下所示:
$cols = 'name', 'middleName', 'eMail';
$table = 'people';
现在,你刚才做的是检查是否已经定义了$ rows,如果没有,则创建它并存储行值和必要的SQL语法,这样它就是一个有效的语句。请注意,字符串应该在双引号和单引号内,因此它们将被及时识别。
剩下要做的就是准备语句并执行,如下:
foreach ( $people as $person ) {
if(! $rowVals ) {
$rows = '(' . "'$name'" . ',' . "'$middleName'" . ',' . "'$eMail'" . ')';
} else { $rowVals = '(' . "'$name'" . ',' . "'$middleName'" . ',' . "'$eMail'" . ')';
}
到目前为止测试了多达2000行,执行时间很短。将运行更多的测试,并将返回到这里,以防我有进一步的贡献。
问候。
由于尚未提出建议,我非常确定LOAD DATA INFILE仍然是加载数据的最快方式,因为它禁用索引,插入所有数据,然后重新启用索引 - 所有这些都在一个请求中完成。
将数据保存为csv应该是相当简单的,记住fputcsv。 MyISAM是最快的,但你仍然可以在InnoDB中获得很高的性能。还有其他的缺点,但是如果要插入大量数据,我会选择这条路线,而不是在100行以下。
虽然一个老问题所有的贡献帮助了我很多,所以这里是我的解决方案,它在我自己的$stmt = $db->prepare ( "INSERT INTO $table $cols VALUES $rowVals" );
$stmt->execute ();
课程中工作。 DbContext
参数只是一个表示行或模型的关联数组数组:$rows
。
如果使用使用模型的模式,那么当将模型数据作为数组传递时,这很适合,例如从模型类中的field name => insert value
方法传递。
注意:不言而喻,但绝不允许传递给此方法的参数向用户公开或依赖于任何用户输入,而不是插入值,这些用户输入已经过验证和清理。
ToRowArray
参数和列名应由调用逻辑定义;例如,$tableName
模型可以映射到用户表,其用户列表的列列表映射到模型的成员字段。
User
您可以使用此函数在单个查询中插入多行:
public function InsertRange($tableName, $rows)
{
// Get column list
$columnList = array_keys($rows[0]);
$numColumns = count($columnList);
$columnListString = implode(",", $columnList);
// Generate pdo param placeholders
$placeHolders = array();
foreach($rows as $row)
{
$temp = array();
for($i = 0; $i < count($row); $i++)
$temp[] = "?";
$placeHolders[] = "(" . implode(",", $temp) . ")";
}
$placeHolders = implode(",", $placeHolders);
// Construct the query
$sql = "insert into $tableName ($columnListString) values $placeHolders";
$stmt = $this->pdo->prepare($sql);
$j = 1;
foreach($rows as $row)
{
for($i = 0; $i < $numColumns; $i++)
{
$stmt->bindParam($j, $row[$columnList[$i]]);
$j++;
}
}
$stmt->execute();
}
$ row是一组值数组。在您的情况下,您将调用该函数
function insertMultiple($query,$rows) {
if (count($rows)>0) {
$args = array_fill(0, count($rows[0]), '?');
$params = array();
foreach($rows as $row)
{
$values[] = "(".implode(',', $args).")";
foreach($row as $value)
{
$params[] = $value;
}
}
$query = $query." VALUES ".implode(',', $values);
$stmt = $PDO->prepare($query);
$stmt->execute($params);
}
}
这样做的好处是,您可以使用预准备语句,同时使用单个查询插入多行。安全!
这对我有用
insertMultiple("INSERT INTO tbl (`key1`,`key2`)",array(array('r1v1','r1v2'),array('r2v1','r2v2')));
这是我
以上是关于PDO Prepared在单个查询中插入多行的主要内容,如果未能解决你的问题,请参考以下文章
使用 PDO Prepared Statement 在 MySQL 中插入 BIT 值
Laravel - PDO Prepared Statement - 在其他无缓冲查询处于活动状态时无法执行查询