PDO, привязывающий множественные операторы вставки к сопоставленным значениям массива - PullRequest
0 голосов
/ 27 августа 2018

Я пытаюсь создать систему заказов / счетов.

У меня есть одна таблица для orders и одна таблица для позиций: orders_items.

Я пытаюсь вставить все позиции сразу, используя атрибут PDO::ATTR_EMULATE_PREPARES.

Я понимаю, о риске безопасности, пользовательский ввод в эту базу данных отсутствует. Это все за кадром.

Когда я анализирую массив $order_item, я создаю несколько операторов INSERT sql с заполнителями.

Однако, когда я иду связывать параметры, в БД появляется сообщение, что добавляется только последний элемент в массиве $order_item.

Вот как переменная $data выглядит для массива $order_item.

array(2) {
  [0]=>
  array(4) {
    ["name"]    =>  string(8) "A red item"
    ["quantity"]=>  int(1)
    ["price"]   =>  string(1) "1"
    ["order_id"]=>  string(2) "44"
  }
  [1]=>
  array(4) {
    ["name"]    =>  string(9) "A blue item"
    ["quantity"]=>  int(1)
    ["price"]   =>  string(1) "2"
    ["order_id"]=>  string(2) "44"
  }
}

Операторы Build Insert создадут это:

INSERT INTO orders_items ( name, quantity, price, order_id ) VALUES ( :name, :quantity, :price, :order_id );
INSERT INTO orders_items ( name, quantity, price, order_id ) VALUES ( :name, :quantity, :price, :order_id );

И на этапе привязки значения местозаполнителя я пытаюсь сделать следующее:

:name = "A red item", :quantity = 1, :price = 1, :order_id = 44
:name = "A blue item", :quantity = 1, :price = 2, :order_id = 44

Но только этот вставляется в БД:

:name = "A blue item", :quantity = 1, :price = 2, :order_id = 44

Вот моя функция создания

public static function create ($data = []) {

$order_info = $data['order_info'];
$orderID = //do first insert and get the record ID

$order_item = $data['order_item'];

//Attach the order number to the each item in the $order_item array
//This way during the SQL for each, the order_id, which is a required column, will be added
foreach ($order_item as $key=>$value){
       $order_item[$key]["order_id"] = $orderID;
}

//Build the INSERT statements
$sql = "";
foreach ($order_item as $item){
  $sql .= "INSERT INTO  orders_items ";
  $sql .= " ( " . implode(", ", array_keys($item)) . " )";
  $sql .= " VALUES ( :" . implode(", :", array_keys($item)) . " ); ";
}


$db = static::getDB();
$db->setAttribute( PDO::ATTR_EMULATE_PREPARES, 1 );
$stmt = $db->prepare( $sql );

//BIND ALL THE ORDER ITEM PLACEHOLDERS TO THEIR VALUES.
foreach ($order_item as $item) {
    foreach ($item as $linekey => $linevalue) {
        $stmt->bindValue(":" . $linekey, $linevalue, PDO::PARAM_STR);
    }
}

   return $stmt->execute();
}

Что я делаю не так? Это возможно? Есть ли лучший способ?

Ответы [ 2 ]

0 голосов
/ 27 августа 2018

печатать в цикле for после получения суммы элемента index.

$arr_count = count($array);
for($i = 0; $i <= $arr_count; $i++){
    $insert_ord_query = $dbh->prepare("INSERT INTO orders(name, quantity, price, order_id) VALUES(:name, :quantity, :price, :order_id)");
    $inser_ord_query->execute(array(
        ":name" => $array[$i]['name'],
        ":quantity" => $array[$i]['quantity'],
        ":price" => $array[$i]['price'],
        ":order_id" => $array[$i]['order_id']
    ));
}
echo "success";
0 голосов
/ 27 августа 2018

Я бы сделал это так, гораздо проще:

$cols = implode(',', array_keys($order_item[0]));

function colon_prefix($param) { return ":$param"; }

$params = implode(',', array_map("colon_prefix", array_keys($order_item[0])));

$sql = "INSERT INTO orders_items ($cols) VALUES ($params)";

$stmt = $db->prepare($sql);

foreach ($order_item as $item) {
    $stmt->execute($item);
}

Вы можете повторно выполнить подготовленный оператор несколько раз, передавая разные массивы для каждого выполнения. Это так же хорошо, как код с несколькими запросами, и его гораздо проще кодировать и легче читать.

Я никогда не использую несколько запросов (несколько операторов в одной строке запроса SQL). Сложно правильно понять, и нет никакой пользы от этого.

Когда вы связываете значения для параметров, когда-то вам приходилось ставить префикс двоеточия на ключ, чтобы соответствовать заполнителю параметра. Но они исправили это так давно, что даже версия PHP, в которой они это исправили, теперь устарела. Вы можете использовать простые строки в качестве ключей привязки.

Вам вообще не нужно использовать bindValue(), просто передайте массив в execute().

Кроме того, приведенный выше код предполагает, что имена столбцов не нужно разделять. То есть они не являются зарезервированными словами SQL и не содержат специальных символов, таких как пробел, пунктуация или международные символы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...