dongpu1879 2012-02-22 14:27
浏览 132
已采纳

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

I have the following PHP PDO statement:

$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);

Where $userData is an associative array. I've double checked the names and I don't understand why I'm getting the following error:

SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

What silly mistake have I made?

  • 写回答

3条回答 默认 最新

  • doukaizha5417 2012-02-22 16:15
    关注

    Your $userData must have exactly the same placeholders bound by your statement, no more and no fewer. See PDOStatement::execute documentation, the part that says "You cannot bind more values than specified".

    You need to prepare your argument to execute() to match your binds exactly. This is easy with array_intersect_key() if you arrange your arrays correctly. I usually wrap this in a function which will also take care of prefixing, like below:

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

    The benefit of an abstraction like this is you don't need to worry about the bind parameters themselves.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 vc6.0中想运行代码的时候总是提示无法打开文件是怎么回事
  • ¥25 关于##爬虫##的问题,如何解决?:
  • ¥15 ZABBIX6.0L连接数据库报错,如何解决?(操作系统-centos)
  • ¥15 找一位技术过硬的游戏pj程序员
  • ¥15 matlab生成电测深三层曲线模型代码
  • ¥50 随机森林与房贷信用风险模型
  • ¥50 buildozer打包kivy app失败
  • ¥30 在vs2022里运行python代码
  • ¥15 不同尺寸货物如何寻找合适的包装箱型谱
  • ¥15 求解 yolo算法问题