2011-06-03 11 views
5

Después de publicar esta pregunta MySQL update or insert or die query He cambiado al uso de PDO pero tengo algunos problemas al utilizar la frase de actualización de clave duplicada.Inserción de PDO en la actualización de clave duplicada

He aquí un ejemplo de mis datos de la matriz

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"} 

En realidad hay 113 campos, pero yo no quería desperdiciar el espacio mostrando todas aquí. Actualmente estoy tratando de insertar/actualizar en mi base de datos mediante el siguiente código

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

Me estoy poniendo el número de parámetro no válido: parámetro no se definió mensaje de error. Estoy bastante seguro de que mis problemas se encuentran en ON DUPLICATE KEY UPDATE :fieldlist');, pero he hecho tantos intentos diferentes y ninguno de ellos ha funcionado. ¿Debo usar más el ON DUPLICATE KEY UPDATE?

Además, soy nuevo en el: e :: sintaxis, ¿significa :name es un tipo de variable denominada como $name y hace PDOStatement::bindValue algo así como PDOStatement->bindValue?

Editar

En respuesta a los dos primeros comentarios a continuación He actualizado el código thusly (pero aún sin resultado, la debugDumpParams dice que tengo no hay parametros). Además, ¿por qué crear el $array_of_parameters cuando se convierte exactamente en la misma matriz que $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; 
+0

La razón para crear '$ array_of_parameters' fue porque en su primera iteración, se utilizó obligado params tanto para la cláusula 'ON DUPLICATE KEY' como para 'INSERT VALUES()'. Todos tienen que ir en la misma matriz pasada a 'execute()' La primera vez que llamas a 'execute()' con '$ array_of_parameters' está en una instrucción UPDATE donde no has usado ningún parámetro. Además, ha envuelto el conjunto dentro de otro 'array()' que no es necesario. –

+0

La primera instrucción UPDATE hace la concatenación de cadenas SQL y luego se pasa a 'prepare()' por lo que todavía es vulnerable a la inyección. Ver la edición en mi respuesta para más información. –

+0

Es posible que necesite un espacio entre los campos separados por comas en la cláusula 'SET'. No recuerdo si es válido omitir el espacio. Únase a ellos con coma-espacio '$ field_list = join (',', $ fields);' –

Respuesta

2

Lo que han tratado de hacer es construir dinámicamente una cadena SQL que se parametrizarse Se espera que los parámetros :paramname sean valores únicos asignados a valores de columna, donde los parámetros de cláusula, etc. En su lugar, ha utilizado $fields[] = sprintf("%s = :%s", $key, $key); para crear una cadena de campos :paramname para conectarse a la consulta. Esto simplemente no funcionará en una declaración parametrizada.

En lugar de hacer ON DUPLICATE KEY UPDATE :fieldlist, debe construir toda la cadena sql antes de pasarla a prepare().

Luego, en lugar de usar el método bindParam() para vincular cada uno individualmente, puede usar una sintaxis alternativa a execute() para pasar una matriz de valores paramétricos esperados. Deben estar en el orden correcto o tener las teclas de matriz con los mismos nombres que los parámetros :param en su SQL.See the docs for more info and examples.

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

EDITAR Para utilizar correctamente los parámetros en su estado de cuenta UPDATE, hacerlo de esta manera:

// 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); 
+0

Michael, muchas gracias por su ayuda. El código está funcionando ahora. – Michael

2

El nombre con dos puntos no es más que named placeholder. Cuando va a enlazar sus parámetros, solo vincula su marcador de posición a algún valor arbitrario.

ON DUPLICATE KEY UPDATE no es muy compatible con varios DBMS, pero si está conectado a una base de datos compatible, debería funcionar (ya que no creo que PDO bloquee todo eso, pero podría estar equivocado). No lo usaría solo por portabilidad. Sin embargo, es posible que desee comprobar cómo está vinculando sus listas de campos, bindparam solo debería hacer un parámetro, y esas son columnas, que no deberían citarse como deberían hacerlo los valores (lo que bind param hará).

El diseño se realiza ejecutando un máximo de dos consultas: Actualizar y luego Insertar. Primero actualizaré y verificaré si el número de filas actualizadas es mayor que 0. Si las filas afectadas son 0, ejecute Insertar.

Sólo un comentario ocioso, 113 campos es mucho de campos, puede sufrir alguna actuación mesa si no tiene cuidado

+0

El formulario es un lunes a viernes de 8 a. M. A 6:30 p. M. En intervalos de 30 m para que los profesores ingresen sus horas de oficina. Estoy abierto a otras ideas sobre diseño de bases de datos, pero ese es un tema completamente diferente. – Michael

Cuestiones relacionadas