Mysql
 sql >> Datenbank >  >> RDS >> Mysql

PHP/SQL-Einfügefehler bei der Verwendung von benannten Platzhaltern

Ihre $userData muss genau die gleichen Platzhalter haben, die durch Ihre Aussage gebunden sind, nicht mehr und nicht weniger. Siehe PDOStatement::execute Dokumentation , der Teil, der sagt "Sie können nicht mehr Werte als angegeben binden".

Sie müssen Ihr Argument für execute() vorbereiten um genau zu Ihren Bindungen zu passen. Das geht ganz einfach mit array_intersect_key() wenn Sie Ihre Arrays richtig anordnen. Normalerweise packe ich dies in eine Funktion, die sich auch um das Präfix kümmert, wie unten:

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

Der Vorteil einer solchen Abstraktion ist, dass Sie sich nicht um die Bindungsparameter selbst kümmern müssen.