fetch_array - Error de inserción de PHP/SQL al usar marcadores de posición con nombre
pdo php mysql (3)
Tengo la siguiente declaración PHP PDO:
$STH = $this->_db->prepare("INSERT INTO UserDetails (FirstName, LastName,
Address, City, County, PostCode, Phone, Mobile, Sex, DOB,
FundraisingAim, WeeksAim, LengthsAim, HearAboutID,
MotivationID, WelcomePackID, ContactPrefID, TitleID)
VALUES
(:firstName, :lastName, :address, :city, :county, :postCode,
:phone, :mobile, :sex, :DOB, :fundraisingAim, :weeksAim,
:lengthsAim, :hearAbout, :motivation,
:welcomePackPref, :contactPref, :title)");
$STH->execute($userData);
Donde $userData
es una matriz asociativa. Revisé los nombres por segunda vez y no entiendo por qué recibo el siguiente error:
SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
¿Qué tonto error he cometido?
Como implica el mensaje, $ userData tiene demasiadas o muy pocas entradas. Necesita coincidir exactamente. Considere publicar un volcado de $ userData.
No estoy seguro si esto es intencional por alguna razón, pero tiene esto:
EndDate = 1
En el medio de los nombres de columna.
Además, tiene 18 nombres de columna enumerados, pero solo 17 valores. Entonces el mensaje de error es correcto.
Su $userData
debe tener exactamente los mismos marcadores de posición vinculados por su extracto, ni más ni menos. Consulte la documentación de PDOStatement::execute
, la parte que dice "No puede enlazar más valores de los especificados".
Necesitas preparar tu argumento para execute()
para que coincida con tus enlaces exactamente. Esto es fácil con array_intersect_key()
si organiza sus matrices de forma correcta. Normalmente envuelvo esto en una función que también se encarga de prefijar, como a continuación:
// Adds a prefix to a name for a named bind placeholder
function prefix($name) {
return '':''.$name;
}
// like ''prefix()'', but for array keys
function prefix_keys($assoc) {
// prefix STRING keys
// Numeric keys not included
$newassoc = array();
foreach ($assoc as $k=>$v) {
if (is_string($k)) {
$newassoc[prefix($k)] = $v;
}
}
return $newassoc;
}
// given a map of datakeyname=>columnname, and a table name, returns an
// sql insert string with named bind placeholder parameters.
function makeInsertStmt($tablename, $namemap) {
$binds = array_map(''prefix'', array_keys($namemap));
return ''INSERT INTO ''.$tablename.'' (''.implode('','',$namemap).'') VALUES (''
.implode('','',$binds).'')'';
}
// returns an array formatted for an `execute()`
function makeBindData($data, $namemap) {
// $data assoc array, $namemap name->column mapping
return prefix_keys(array_intersect_key($data, $namemap));
}
// example to demonstrate how these pieces fit together
function RunTestInsert(PDO $pdo, $userData) {
$tablename = ''UserDetails'';
// map "key in $userData" => "column name"
// do not include '':'' prefix in $userData
$namemap = array(
''firstName'' => "FirstName",
''lastName'' => "LastName",
''address'' => "Address",
''city'' => "City",
''county'' => "County",
''postCode'' => "PostCode",
''phone'' => "Phone",
''mobile'' => "Mobile",
''sex'' => "Sex",
''DOB'' => "DOB",
''fundraisingAim'' => "FundraisingAim",
''weeksAim'' => "WeeksAim",
''lengthsAim'' => "LengthsAim",
''hearAbout'' => "HearAboutID",
''motivation'' => "MotivationID",
''welcomePackPref'' => "WelcomePackID",
''contactPref'' => "ContactPrefID",
''title'' => "TitleID",
);
$sql = makeInsertStmt($tablename, $namemap);
$binddata = makeBindData($userData, $namemap);
$pstmt = $pdo->prepare($sql);
$pstmt->execute($binddata);
}
El beneficio de una abstracción como esta es que no necesita preocuparse por los parámetros de enlace en sí mismos.