【问题标题】:SQLSTATE[HY093]: Invalid parameter number: parameter was not defined (PDO)SQLSTATE[HY093]:无效参数号:未定义参数(PDO)
【发布时间】:2012-04-15 05:57:25
【问题描述】:

我知道:这已经被做死了。

但是,相信我,我一直在研究如何解决这个问题。我想要实现的是一个用于 PDO 的 PDO MySQL 数据库包装器,我可以将其合并到我的代码中。我的主要问题尤其源于两个功能,以及我试图达到的参数的实际绑定。我之所以说 两个 函数而不是一个函数,是因为尽管我努力了,但我还是无法确定哪个函数正在尝试解决问题。我var_dumped 的变量已经确认它不是变量,它是别的东西。尽管如此,我首先遇到此错误这一事实意味着 something 代码一定有问题。

展览 A: fetch( $table, $columns, $whereArgs )

这个函数的目的是简单地获取一行。这是通过接受要获取的行的表以及任何列和 where 子句来实现的,以便专门完成任务。一旦提交了参数,就会调用一两个循环来动态形成查询。

public function fetch( $table, $columns, $whereArgs )
    {
        if ( $whereArgs === NULL && $columns === NULL ) return false;

        $select = "SELECT ";
        $where  = " WHERE ";

        $iQuery = 0;

        $sqlParams = array();

        $columnCount = count( $columns ) - 1;

        foreach( $whereArgs as $key => $value )
        {
            $paramKey = sprintf( ':%s', $key );

            $where .= sprintf( "`%s`= %s", $key, $paramKey );

            $sqlParams[ "{$paramKey}" ] = sprintf( "%s", $value );

            if ( $iQuery <= $columnCount )
            {
                $select .= sprintf( '`%s`', $columns[ $iQuery ] );  
                $select .= ', ';
            }
            else 
            {
                $select .= ' '; 
            }

            ++$iQuery;
        }

        if ( $iQuery <= $columnCount )
        {
            for( ; $iQuery < $columnCount; ++$iQuery )
            {
                if ( $iQuery < $columnCount )
                {
                    $select .= sprintf( '`%s`', $columns[ $iQuery ] );  
                    $select .= ', ';
                }
                else 
                {
                    $select .= ' '; 
                }
            }
        }

        $select .= sprintf( "FROM `%s`", $table );

        $query = $select . $where;

        return $this->doQuery( $query, $sqlParams, TRUE, QueryType::Row );
    }

图表 B: doQuery( $query, $sqlParams, $return = FALSE, $queryType = QueryType::None )

这个函数相对简单:它所做的只是绑定值并执行语句,同时迅速检查要返回的类型(返回类型是'row'、'column'或'all')由类 QueryType 指定,该类超出了本问题的范围),然后返回任何要求的内容。

protected function doQuery( $query, $sqlParams, $return = FALSE, $queryType = QueryType::None )
    {
        $statement = $this->mConnection->prepare( $query );

        foreach( $sqlParams as $param => $value )
        {
            $statement->bindValue( $param, $value );
        }

        $statement->execute( );

        if ( $return )
        {
            switch( $queryType )
            {
                case QueryType::Row:
                    return $statement->fetch( );
                case QueryType::Column:
                    return $statement->fetchColumn( );
                case QueryType::All:
                    return $statement->fetchAll( );
                case QueryType::None:
                    return $statement;
                default:
                    return false;   
            }
        }

    }

图表 C: test.php

这只是我为测试数据库而编写的一个小测试脚本。

$database = new Database( 'evolve_admin' );

$res = $database->fetch(
    'evol_users', 
    array( 'user.id', 'user.email', 'user.firstname' ), 
    array( 'user.email' => 'test1234@test.com' )
);


var_dump( $res );

其他评论

我了解到我的代码有问题,我只是不知道它到底是什么。就我的调试技巧而言,我对这个问题进行了相当多的研究,而且似乎这个错误很常见。我的主要目标是让这个包装器正常工作,如果有人发现代码本身有任何错误(包括特别是本问题范围之外的错误),请告诉我。

对于任何提供帮助的人:非常感谢。

【问题讨论】:

  • 检查生成的SQL与绑定的参数个数,然后找出数量不匹配的原因。
  • 问题是只绑定了一个参数。我已经测试了通过并绑定参数的 for 循环。我也可以输出变量,它们看起来和它们应该看起来的完全一样。
  • 不,问题是没有绑定任何参数(或者更具体地说,您有 N 个参数并且正在绑定一些 x 使得 x

标签: php mysql pdo wrapper parameterized


【解决方案1】:

我认为你忘记了那里的一些空格:

$where .= sprintf( "`%s`= %s", $key, $paramKey );

您下次使用 $wher 变量时是将其附加到 $select 变量。

如果不止一个 where arg 是哪里:

WHERE `%s`= %s`%s`= %s`%s`= %s`%s`= %s`%s`= %s

您的 SELECT 生成思想并没有犯错误。 顺便说一句,您有两个相同的循环和测试您选择的一代if ( $iQuery &lt;= $columnCount )。一个在 where 循环中,另一个在外面。有什么用?

编辑:当然我忘了指出为什么你有这个可怕的错误: 它在

$sqlParams[ "{$paramKey}" ] = sprintf( "%s", $value );

您创建了一个如下所示的表:array ( "{:akey}" =&gt; "avalue")(我认为该值是字符串。 你为什么使用大括号({}),它完全改变了键名(应该是:keynamenot {:keyname}

编辑 2: 心情很好,所以这里是您的 fetch 方法的简化版本。(未经测试,但应该可以正常工作)

/*
* $whereArgs default value is an array, so you can call a select 
* without an empty array supplied if you does not have some where clause arguments
* The separator is how the element will be binded alltogether in the where clause
*/
public function fetch( $table, $columns, $whereArgs = array(), $separator= 'AND' )
{
    /* We return false, if the columns variable is not set, or is not an array, 
    *  or (if it is an array) does not contain anything 
    *  or the $whereArgs is not and array (it would mean something bad have been given)
    */
    if ( false == isset($columns) || false == is_array($columns) 
            || 0 == count($columns) || false == is_array($whereArgs) )
    {
        return false;
    }

    $select = "SELECT";
    $from = " FROM `$table`";
    $where  = " WHERE ";

    /* SELECT generation */
    for ( $columIt = 0; $columIt < count($columns);  $columIt++)
    {
        $select .= " " . $columns[$columIt];
        // We check if we need to add a ','
        if ( $columIt+1 < count($columns) )
        {
            $select .= ",";
        }
    }

    /* WHERE clause generation */
    $sqlParams = array();
    $whereIt = 0;
    foreach( $whereArgs as $key => $value )
    {
        $stripedKey = preg_replace('/\\./', '_', $key);
        $where .= " $key= :$stripedKey";
        $sqlParams[ ":$stripedKey" ] = "$value";
        // We check if we need to add a where separator
        if ( $whereIt +1 < count($whereArgs ) )
        {
            $select .= " $separator";
        }
        $whereIt++;

    }

    /*  the generated where clause is only printed if $whereArgs 
    *   is not an empty array 
    */
    $query = $select . $from . ((0<count($whereArgs))?$where:"");

    return $this->doQuery( $query, $sqlParams, TRUE, QueryType::Row );
}

编辑 3: 顺便说一句,没有看到您的测试样本,但参数名称不能包含“。”字符

编辑 4: 没看到你解决了,我添加了一个 pre_replace 来替换 '.'在你的子集中。 回显键时也要去掉'`'字符,否则查询将失败

`user.email`=:arg

不喜欢=)

user.email=:arg or user.`email`=:arg

首选(`)用于在列名中包含特殊字符,因此像以前一样使用,列名与任何现有的都不匹配。

编辑 5: 而不是剥离您的密钥来创建您的参数和参数数组。您可以通过利用 $whereIt 计数器来使用一种安全的方式来防止误导性字符的幻影:

$where .= " $key= :arg_$whereIt";
$sqlParams[ ":arg_$whereIt" ] = "$value";

问候

【讨论】:

  • 已编辑帖子以添加出现此错误的原因(忘记告诉 xD)
  • 是的,感谢您的帮助,但不幸的是,我的 var_dump() 仍然有完全相同的查询,输出:SELECT user.id, user.email, user.firstname, FROM evol_users WHERE user.email= :user.email.
  • 什么返回 var_dump 或 $sqlParams?
  • var_dump(); $sq;Params 是用于绑定到查询的参数。不过,感谢您的编辑,它有所帮助:)。
  • Oups 忘记在 where 子句中添加分隔符
【解决方案2】:

问题是由于我在测试数据库中的每一列都有一个“。”。在“用户”和列名之间。我通过用下划线替换每个句点来解决问题,这样就消除了错误。虽然由于某种原因查询仍然无法正常工作,但我相信一切都会好起来的。

所以,例如:

user.email = user_email.

【讨论】:

    猜你喜欢
    • 2016-12-15
    • 2022-01-10
    • 2017-06-10
    • 1970-01-01
    • 2012-06-13
    相关资源
    最近更新 更多