重复密钥更新时插入PDO


PDO Insert on Duplicate Key Update

在发布这个问题MySQL更新或插入或死亡查询后,我改为使用PDO,但我在使用重复密钥更新短语时遇到了一些问题。

这是我的阵列数据的一个例子

array(114) {
["fname"]=>
string(6) "Bryana"
["lname"]=>
string(6) "Greene"
["m080"]=>
string(1) "c"
["t080"]=>
string(1) "-"
["w080"]=>
string(1) "-"
["r080"]=>
["notes"]=>
string(4) "yoyo"}

事实上有113个字段,但我不想浪费空间在这里展示它们。我目前正试图通过以下代码将INSERT/UPDATE插入到我的数据库中

try {
    $dbh = new PDO('login info here');
    $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
    $stmt = $dbh->prepare(
        'INSERT INTO fhours ('.implode(",", array_keys($faculty)).')'.
        ' VALUES (:'.implode(",:", array_keys($faculty)).')'.
        ' ON DUPLICATE KEY UPDATE :fieldlist');
    $stmt->bindParam(':field_list', $field_list);
    foreach($faculty as $key=>$val){
        $stmt->bindParam(':'.$key, $val);
        $fields[] = sprintf("%s = :%s", $key, $key);
    }
    $field_list = join(',', $fields);
    //echo $stmt->debugDumpParams();
    $stmt->execute();
}
catch(PDOException $e){
    echo $e->getMessage();
    exit(); 
}

我正在获取无效的参数编号:参数未定义错误消息。我很确定我的问题在于ON DUPLICATE KEY UPDATE :fieldlist');,但我做了很多不同的尝试,但都没有成功。我应该再使用ON DUPLICATE KEY UPDATE吗?

此外,我对:and::语法还不熟悉,:name是否意味着它是一个类似于$name的命名变量,PDOStatement::bindValue是否有点类似于PDOStatement->bindValue

编辑

作为对下面前两条评论的回应,我更新了代码(但仍然无效,debugDumpParams说我没有params)。此外,当$array_of_parameters一开始就与$faculty完全相同时,为什么要创建它呢?

  //grab form data
$faculty = $_POST;
$fname = $_POST['fname'];
$lname = $_POST['lname'];
//delete the submit button from array
unset($faculty['submit']);
$array_of_parameters = array();
foreach($faculty as $key=>$val){
        $array_of_parameters[$key] = $val;
        $fields[] = sprintf("%s=?", $key);
}
$field_list = join(',', $fields);
try {
    $dbh = new PDO('mysql:host=localhost;dbname=kiosk', 'kiosk', 'K10$k');
    $dbh->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION );
    $update =   'UPDATE fhours SET '.$field_list. 'WHERE fname="'.$fname.'" AND '.
                        'lname="'.$lname.'"';
    $stmt = $dbh->prepare($update);
    //echo $stmt->debugDumpParams();
    $stmt->execute(array($array_of_parameters));
    if($stmt->rowCount() == 0){
        $insert = 'INSERT INTO fhours ('.implode(",", array_keys($faculty)).')'.
                    ' VALUES (:'.implode(",:", array_keys($faculty)).')';
        $stmt = $dbh->prepare($insert);
        $stmt->execute(array($array_of_parameters));
    }
}
catch(PDOException $e){
    echo $e->getMessage();
    exit(); 
}
$dbh=null;

您尝试的是动态构建一个将被参数化的SQL字符串。:paramname参数应该是映射到列值、where子句参数等的单个值。相反,您使用$fields[] = sprintf("%s = :%s", $key, $key);创建了一个:paramname字段字符串,以便插入查询。这在参数化语句中是不起作用的。

与其执行ON DUPLICATE KEY UPDATE :fieldlist,不如在将整个sql字符串传递到prepare()之前构建它。

然后,您可以使用execute()的替代语法来传递预期参数值的数组,而不是使用bindParam()方法来单独绑定每一个。它们的顺序必须正确,或者数组键的名称与SQL中的:param参数的名称相同。有关更多信息和示例,请参阅文档。

$array_of_parameters = array();
foreach($faculty as $key=>$val){
    $array_of_parameters[$key] = $val);
}
$stmt->execute($array_of_parameters);

EDIT要正确使用UPDATE语句中的参数,请执行以下操作:

// Create your $field_list before attempting to create the SQL statement
$field_list = join(',', $fields);
$update = 'UPDATE fhours SET '.$field_list. 'WHERE fname=:fname AND lname=:lname';
// Here, echo out $update to make sure it looks correct
// Then add the fname and lname parameters onto your array of params
$array_of_parameters[] = $_POST['fname'];
$array_of_parameters[] = $_POST['lname'];
// Now that your parameters array includes all the faculty in the correct order and the fname & lname,
// you can execute it.
$stmt->prepare($update);
$stmt->execute($array_of_parameters);

以冒号为前缀的名称只不过是命名占位符。当您绑定params时,您只需将占位符绑定到某个任意值。

ON DUPLICATE KEY UPDATE对多DBMS不是很友好,但如果您连接到兼容的数据库,它应该可以工作(因为我不相信PDO会阻止所有这些,但我可能错了)。我不会仅仅为了便携性而使用它。不过,您可能需要检查如何绑定字段列表,bindparam应该只做一个参数,而这些都是列,不应该像值那样引用(bind-param会做)。

我通过运行最多两个查询来设计混乱:更新然后插入。我将首先更新并检查更新的行数是否大于0。如果受影响的行为0,请运行Insert。

只是一个闲置的注释,113个字段是很多的字段,如果你不小心

,你可能会受到一些表性能的影响