Вставка PDO при обновлении дубликата ключа - PullRequest
5 голосов
/ 03 июня 2011

После публикации этого вопроса Обновление 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 полей, но я не хотел тратить место, показывая их здесь. В настоящее время я пытаюсь вставить / обновить в своей базе данных с помощью следующего кода

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 говорит, что у меня нет параметров). Кроме того, зачем создавать $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;

Ответы [ 2 ]

2 голосов
/ 03 июня 2011

То, что вы пытались сделать, это динамически построить строку SQL, которая станет параметризованной.Ожидается, что параметры :paramname будут единичными значениями, сопоставленными со значениями столбца, где параметры предложения и т. Д. Вместо этого вы использовали $fields[] = sprintf("%s = :%s", $key, $key); для создания строки из полей :paramname для подключения к запросу.Это просто не будет работать в параметризованном операторе.

Вместо того, чтобы делать ON DUPLICATE KEY UPDATE :fieldlist, вы должны построить всю строку sql перед передачей ее в prepare().

Затем, вместо использования метода bindParam() для привязки каждого из них по отдельности, вы можете использовать альтернативный синтаксис для execute() для передачи массива ожидаемых параметрических значений.Они должны быть в правильном порядке или иметь ключи массива с такими же именами, что и параметры :param в вашем SQL. См. Документы для получения дополнительной информации и примеров.

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

РЕДАКТИРОВАТЬ Чтобы правильно использовать параметры в вашем операторе 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);
2 голосов
/ 03 июня 2011

Имя с префиксом двоеточия является не чем иным, как именованным заполнителем.Когда вы идете, чтобы связать свои параметры, вы просто связываете свой заполнитель с какой-то произвольной величиной.

ON DUPLICATE KEY UPDATE не очень подходит для нескольких СУБД, но если вы подключены к базе данных, совместимой, она должна работать (поскольку я не верю, что PDO все это заблокирует, но я могу ошибаться).Я бы не стал использовать это только ради мобильности.Возможно, вы захотите проверить, как вы связываете свои списки полей, хотя bindparam должен использовать только один параметр, и это столбцы, которые не должны заключаться в кавычки, как значения (которые будет делать параметр связывания).

Я создаю upserts, выполняя максимум два запроса: Update, затем Insert.Сначала я обновлю и проверю, больше ли количество обновленных строк, чем 0. Если затронутых строк равно 0, запустите операцию вставки.

Просто пустой комментарий, 113 полей - это много полей, вы можете понизить производительность таблицы, если не будете осторожны

...