Вставка нескольких строк сразу с помощью подготовленных операторов

Я хотел бы знать, как можно вставить несколько значений в массив через подготовленные операторы. Я рассмотрел эти два вопроса ( этот вопрос и этот другой ), но они, похоже, не делают то, что я пытаюсь. Это то, что у меня есть:

$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(); } } } 

Solutions Collecting From Web of "Вставка нескольких строк сразу с помощью подготовленных операторов"

Принцип работы:

Для добавления нескольких записей, определяемых парами значений, используйте только один оператор SQL INSERT. Для этого вам нужно построить соответствующий sql-оператор в форме

 INSERT INTO [table-name] ([col1],[col2],[col3],...) VALUES (:[col1],:[col2],:[col3],...), (:[col1],:[col2],:[col3],...), ... 

путем итерации через массив значений.

Заметки:

  • Надеюсь, вы все поймете. Я прокомментировал столько, сколько мог. Я не тестировал его, но он должен работать. Возможно, ответ, который я написал недавно, даст вам дополнительные идеи относительно структурирования классов / функций доступа к данным.
  • Никогда не используйте ";" в конце операторов sql, когда вы определяете их в PHP.
  • Никогда не используйте один входной маркер для привязки нескольких значений. Для каждого значения привязки используйте уникальный именованный маркер ввода.

Удачи.

connection.php

 <?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(); } 

Import.php:

 <?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; } } 

Я думаю, что заявления должны быть подготовлены и связаны отдельно для каждой итерации:

 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(); } }