【问题标题】:PHP/SQL Insert Error when using Named Placeholders使用命名占位符时的 PHP/SQL 插入错误
【发布时间】:2012-03-12 21:25:32
【问题描述】:

我有以下 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]: Invalid parameter number: number of bound variables does not match number of tokens

我犯了什么愚蠢的错误?

【问题讨论】:

    标签: php mysql arrays pdo associative-array


    【解决方案1】:

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

    你需要准备好你的参数 execute() 以完全匹配你的绑定。如果您正确排列阵列,使用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);
    }
    

    这样的抽象的好处是您不必担心绑定参数本身。

    【讨论】:

    • 超越。谢谢你,先生!
    【解决方案2】:

    正如消息所暗示的,$userData 的条目太多或太少。需要完全匹配。考虑发布 $userData 的转储。

    【讨论】:

    • 数组大小需要完全匹配?我在数组中有一些额外的字段没有被使用,但我认为因为我在 PDO 语句中使用了命名占位符,所以可以吗? :(
    • @FrancisAvila 这看起来很疯狂!我可以找到一些关于此的文档吗?有什么选择?
    • 添加了解决这两个问题的答案。
    • 欢迎来到疯狂的 php 世界。我想这是一种错误检查之类的东西。不确定它是否记录在某处,但我已经得到了足够多的相同错误,以知道该数组需要准确。您可以查看诸如 Doctrine 2 之类的 ORM 解决方案来隐藏这些类型的语句。
    【解决方案3】:

    不确定这是否出于某种原因是故意的,但你有这个:

    EndDate = 1
    

    在列名的中间。

    此外,您列出了 18 个列名,但只有 17 个值。所以错误信息是正确的。

    【讨论】:

    • 我已更新声明以消除这两个问题。同样的错误信息。
    猜你喜欢
    • 2012-04-20
    • 2011-11-23
    • 2016-05-26
    • 2013-02-10
    • 2019-03-25
    • 1970-01-01
    • 2021-04-15
    • 2013-10-14
    • 1970-01-01
    相关资源
    最近更新 更多