使用命名占位符时 PHP/SQL 插入错误

标签 php mysql arrays pdo associative-array

我有以下 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);

其中 $userData 是关联数组。我仔细检查了这些名称,但不明白为什么会收到以下错误:

SQLSTATE[HY093]:参数数量无效:绑定(bind)变量的数量与标记数量不匹配

我犯了什么愚蠢的错误?

最佳答案

您的 $userData 必须具有与您的语句绑定(bind)的完全相同的占位符,不多也不少。请参阅PDOStatement::execute documentation ,这部分内容是“您绑定(bind)的值不能多于指定的值”。

您需要准备 execute() 的参数以完全匹配您的绑定(bind)。如果您正确排列数组,那么使用 array_intersect_key() 就很容易做到这一点。我通常将其包装在一个函数中,该函数也将处理前缀,如下所示:

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

像这样的抽象的好处是您无需担心绑定(bind)参数本身。

关于使用命名占位符时 PHP/SQL 插入错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9396691/

相关文章:

php - Laravel 5.3 到 5.4 关系foreignKey问题

php - MySQL 事务 : SELECT + INSERT

mysql - 我如何将我的mysql数据库纳入主从配置以进行数据备份以及插入和选择的分离

MySQL插入重复值(非PK)

java - 数组适配器未在 onDataChange() 方法中更新

javascript - 如何通过拼接从数组中删除连续匹配的元素?

php - iFrame 不会在 Chrome 和 Safari 中保存与 Laravel 的 session

phpMyAdmin 外键下拉字段值

php - 将超链接元素传递到超链接页面并在超链接页面接收该元素

javascript - 尝试将提示中的输入用作函数中的对象值