PDO将多个插入语句绑定到映射的数组值

时间:2018-08-27 20:20:07

标签: php mysql pdo

我正在尝试创建订单/发票系统。

我有一个用于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 :(得分:1)

我会这样做,这要简单得多:

<div class="product-descriptions">
  <div class="product-descriptions__item">
    <div class="product-descriptions__icon-container">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 70" aria-hidden="true" focusable="false">
    <title>icon_circleplus</title>
    <g>
        <path d="M50.66,4.76a30.71,30.71,0,1,0,30.7,30.7,30.71,30.71,0,0,0-30.7-30.7M66.55,38.87H54.06V51.35H47.25V38.87H34.76V32.06H47.25V19.57h6.81V32.06H66.55Z"></path>
    </g>
</svg>

    </div>
    <div class="product-descriptions__title">Advantage SafeBalance</div>
    <div class="product-descriptions__description">Say goodbye to paper checks—and to overdraft fees.</div>
    <a id="" class="product-descriptions__link" href="#" data-index="0">
                                See details
                            </a>
  </div>
  <div class="product-descriptions__item">
    <div class="product-descriptions__icon-container">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 70" aria-hidden="true" focusable="false">
    <title>icon_circleplus</title>
    <g>
        <path d="M50.66,4.76a30.71,30.71,0,1,0,30.7,30.7,30.71,30.71,0,0,0-30.7-30.7M66.55,38.87H54.06V51.35H47.25V38.87H34.76V32.06H47.25V19.57h6.81V32.06H66.55Z"></path>
    </g>
</svg>

    </div>
    <div class="product-descriptions__title">Advantage Plus</div>
    <div class="product-descriptions__description">More control, more options, more ways to waive the monthly fee.</div>
    <a id="" class="product-descriptions__link" href="#" data-index="1">
                                See details
                            </a>
  </div>
  <div class="product-descriptions__item">
    <div class="product-descriptions__icon-container">
      <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 70" aria-hidden="true" focusable="false">
    <title>icon_circleplus</title>
    <g>
        <path d="M50.66,4.76a30.71,30.71,0,1,0,30.7,30.7,30.71,30.71,0,0,0-30.7-30.7M66.55,38.87H54.06V51.35H47.25V38.87H34.76V32.06H47.25V19.57h6.81V32.06H66.55Z"></path>
    </g>
</svg>

    </div>
    <div class="product-descriptions__title">Advantage Relationship</div>
    <div class="product-descriptions__description">Everything you get with the Plus setting along with extra perks and services.</div>
    <a id="" class="product-descriptions__link" href="#" data-index="2">
                                See details
                            </a>
  </div>
</div>

您可以多次重新执行一条准备好的语句,并将不同的数组传递给每次执行。这与多查询代码一样好,并且更易于编码和阅读。

我从不使用多重查询(在一个SQL查询字符串中包含多个语句)。正确的做法很复杂,而且这样做没有任何好处。

绑定参数值时,一次必须在键上放置一个冒号前缀,以匹配参数占位符。但是他们修复了很久以前,以至于甚至修复了它们的PHP版本也已被弃用。您可以使用纯字符串作为绑定键。

您根本不需要使用$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); } ,只需将数组传递给bindValue()

此外,上面的代码假定您的列名不需要分隔。也就是说,它们不是SQL保留字,并且不包含空格,标点符号或国际字符等特殊字符。

答案 1 :(得分:-1)

在获取索引元素总和后在for循环中打印。

$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";