我想知道如何通过预处理语句在数组中插入多个值。我已经看过这两个问题(this question和this other one),但他们似乎没有做我正在尝试的问题。这就是我所拥有的:
$stmt = $this->dbh->prepare("INSERT INTO
t_virtuemart_categories_en_gb
(category_name, virtuemart_category_id)
VALUES
(:categoryName, :categoryId)
;");
foreach($this->values as $insertData){
$categoryName = $insertData['categoryName'];
$categoryId = $insertData['categoryId'];
$stmt->bindParam(':categoryName', $categoryName);
$stmt->bindParam(':categoryId', $categoryId);
$stmt->execute();
}
我尝试将prepare
行放在foreach循环内外,但它只添加了数组中的第一个键,我不明白为什么。
这是我的Connection.php
文件:
<?php
$hostname = 'localhost';
$username = 'root';
$password = '';
function connectDB ($hostname, $username, $password){
$dbh = new PDO("mysql:host=$hostname;dbname=test", $username, $password);
return $dbh;
}
try {
$dbh = connectDB ($hostname, $username, $password);
} catch(PDOException $e) {
echo $e->getMessage();
}
我的Import.php文件:
<?php
class Import{
public function __construct($dbh, $values) {
$this->dbh = $dbh;
$this->values = $values;
}
public function importData() {
$stmt = $this->dbh->prepare("INSERT INTO
t_virtuemart_categories_en_gb
(category_name, virtuemart_category_id)
VALUES
(:categoryName, :categoryId)
;");
foreach($this->values as $insertData){
$categoryName = $insertData['categoryName'];
$categoryId = $insertData['categoryId'];
$stmt->bindParam(':categoryName', $categoryName);
$stmt->bindParam(':categoryId', $categoryId);
$stmt->execute();
}
}
}
答案 0 :(得分:1)
我认为必须为每次迭代单独准备和绑定语句:
if($stmt = $this->dbh->prepare("INSERT INTO t_virtuemart_categories_en_gb (category_name, virtuemart_category_id) VALUES (:categoryName, :categoryId);")){
foreach($this->values as &$insertData){
$stmt->bindParam(':categoryName', $insertData['categoryName']);
$stmt->bindParam(':categoryId', $insertData['categoryId']);
$stmt->execute();
$stmt->close();
}
}
答案 1 :(得分:1)
工作原理:
仅使用一个INSERT sql语句添加由值对定义的多个记录。为了实现这一点,你必须以
的形式构建相应的sql语句INSERT INTO [table-name] ([col1],[col2],[col3],...) VALUES (:[col1],:[col2],:[col3],...), (:[col1],:[col2],:[col3],...), ...
迭代你的数组数组。
备注:强>
<?php
$hostname = 'localhost';
$username = 'root';
$password = '';
$port = 3306;
try {
// Create a PDO instance as db connection to a MySQL db.
$connection = new PDO(
'mysql:host='. $hostname .';port='.$port.';dbname=test'
, $username
, $password
);
// Assign the driver options to the db connection.
$connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE);
$connection->setAttribute(PDO::ATTR_PERSISTENT, TRUE);
} catch (PDOException $exc) {
echo $exc->getMessage();
exit();
} catch (Exception $exc) {
echo $exc->getMessage();
exit();
}
<?php
class Import {
/**
* PDO instance as db connection.
*
* @var PDO
*/
private $connection;
/**
*
* @param PDO $connection PDO instance as db connection.
* @param array $values [optional] Values list.
*/
public function __construct(PDO $connection, array $values = array()) {
$this->connection = $connection;
$this->values = $values;
}
/**
* Import data.
*
* @return int Last insert id.
* @throws PDOException
* @throws UnexpectedValueException
* @throws Exception
*/
public function importData() {
/*
* Values clauses list. Each item will be
* later added to the sql statement.
*
* array(
* 0 => '(:categoryName0, :categoryId0)',
* 1 => '(:categoryName1, :categoryId1)',
* 2 => '(:categoryName2, :categoryId2)',
* )
*/
$valuesClauses = array();
/*
* The list of the input parameters to be
* bound to the prepared statement.
*
* array(
* :categoryName0 => value-of-it,
* :categoryId0 => value-of-it,
* :categoryName1 => value-of-it,
* :categoryId1 => value-of-it,
* :categoryName2 => value-of-it,
* :categoryId2 => value-of-it,
* )
*/
$bindings = array();
/*
* 1) Build a values clause part for each array item,
* like '(:categoryName0, :categoryId0)', and
* append it to the values clauses list.
*
* 2) Append each value of each item to the input
* parameter list.
*/
foreach ($this->values as $key => $item) {
$categoryName = $item['categoryName'];
$categoryId = $item['categoryId'];
// Append to values clauses list.
$valuesClauses[] = sprintf(
'(:categoryName%s, :categoryId%s)'
, $key
, $key
);
// Append to input parameters list.
$bindings[':categoryName' . $key] = $categoryName;
$bindings[':categoryId' . $key] = $categoryId;
}
/*
* Build the sql statement in the form:
* INSERT INTO [table-name] ([col1],[col2],[col3]) VALUES
* (:[col1],:[col2],:[col3]), (:[col1],:[col2],:[col3]), ...
*/
$sql = sprintf('INSERT INTO t_virtuemart_categories_en_gb (
category_name,
virtuemart_category_id
) VALUES %s'
, implode(',', $valuesClauses)
);
try {
// Prepare the sql statement.
$statement = $this->connection->prepare($sql);
// Validate the preparing of the sql statement.
if (!$statement) {
throw new UnexpectedValueException('The sql statement could not be prepared!');
}
/*
* Bind the input parameters to the prepared statement
* and validate the binding of the input parameters.
*
* -----------------------------------------------------------------------------------
* Unlike PDOStatement::bindValue(), when using PDOStatement::bindParam() the variable
* is bound as a reference and will only be evaluated at the time that
* PDOStatement::execute() is called.
* -----------------------------------------------------------------------------------
*/
foreach ($bindings as $key => $value) {
// Read the name of the input parameter.
$inputParameterName = is_int($key) ? ($key + 1) : (':' . ltrim($key, ':'));
// Read the data type of the input parameter.
if (is_int($value)) {
$inputParameterDataType = PDO::PARAM_INT;
} elseif (is_bool($value)) {
$inputParameterDataType = PDO::PARAM_BOOL;
} else {
$inputParameterDataType = PDO::PARAM_STR;
}
// Bind the input parameter to the prepared statement.
$bound = $statement->bindValue($inputParameterName, $value, $inputParameterDataType);
// Validate the binding.
if (!$bound) {
throw new UnexpectedValueException('An input parameter could not be bound!');
}
}
// Execute the prepared statement.
$executed = $statement->execute();
// Validate the prepared statement execution.
if (!$executed) {
throw new UnexpectedValueException('The prepared statement could not be executed!');
}
/*
* Get the id of the last inserted row.
*/
$lastInsertId = $this->connection->lastInsertId();
} catch (PDOException $exc) {
echo $exc->getMessage();
// Only in development phase !!!
// echo '<pre>' . print_r($exc, TRUE) . '</pre>';
exit();
} catch (Exception $exc) {
echo $exc->getMessage();
// Only in development phase !!!
// echo '<pre>' . print_r($exc, TRUE) . '</pre>';
exit();
}
return $lastInsertId;
}
}
答案 2 :(得分:0)
我建议使用$ dbh = mysqli_connect():
<?php
class Import{
public function __construct($dbh, $values) {
$this->dbh = $dbh;
$this->values = $values;
}
public function importData() {
$stmt = $this->dbh->prepare("INSERT INTO t_virtuemart_categories_en_gb
(category_name, virtuemart_category_id)
VALUES
(?, ?)");
$catetoryName = ''; $categoryId = '';
$stmt->bind_param('ss', $categoryName, $categoryId);
foreach($this->values as $insertData){
$categoryName = $insertData['categoryName'];
$categoryId = $insertData['categoryId'];
$stmt->execute();
}
}
}
通过这种方式,您可以创建引用并将该变量绑定到已准备好的语句的执行上。
您在传递数组时应该小心,技巧在php.net页面(http://php.net/manual/it/mysqli.prepare.php)中注释
有效的代码是:
$typestring = 'sss'; //as many as required: calc those
$stmt = $dbconni->prepare($ansqlstring);
$refs = [$typestring];
// if $source is an array of array [ [f1,f2,...], [f1,f2,...], ...]
foreach($source as $data) {
if (count($refs)==1) {
foreach ($data as $k => $v) {
$refs[] = &$data[$k];
}
$ref = new \ReflectionClass('mysqli_stmt');
$method = $ref->getMethod("bind_param");
$method->invokeArgs($stmt, $refs);
$r = $stmt->execute();
} else {
// references are maintained: no needs to bind_param again
foreach ($data as $k => $v) {
$refs[$k+1] = $v;
}
$r = $stmt->execute();
}
}
这是多余的资源,性能更高,但是您必须确定基准以确保我的话语。
这是准备好的语句有意义的一种情况,请参见
https://joshduff.com/2011-05-10-why-you-should-not-be-using-mysqli-prepare.md
通常PDO模拟准备好的语句,请参见PDO :: ATTR_EMULATE_PREPARES
编辑:指定它正在使用mysqli,并更正代码。