SQLSTATE [HY093]: недопустимый номер параметра: параметр не был определен (PDO) - PullRequest
3 голосов
/ 01 апреля 2012

Я знаю: это было сделано до смерти.

Но, поверьте мне, я довольно долго изучал, как это исправить.То, чего я пытаюсь добиться - это оболочка базы данных MySQL PDO для использования с PDO, которую я могу просто включить в свой код.Моя главная проблема связана, в частности, с двумя функциями, а также с фактической привязкой параметров, которые я пытаюсь достичь.Причина, по которой я заявляю две функции в отличие от одной, заключается в том, что, несмотря на все мои усилия, я не смог определить, какая из них пытается решить проблему.Переменная, которую я var_dump ed, подтвердила, что это не переменная, это что-то еще.Тем не менее, тот факт, что я получаю эту ошибку в первую очередь, означает, что что-то должно быть неправильно с кодом.

Приложение 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 );

Другие комментарии

Я узнал, что что-то не так с моимкод, я просто потерял, что именно это может быть.Что касается моих навыков отладки, я исследовал эту проблему довольно немного, и кажется, что эта ошибка очень распространена.Моя главная цель - заставить эту оболочку работать, и если кто-то увидит какие-либо ошибки в самом коде (включая те, которые выходят за рамки этой проблемы, в частности), пожалуйста, дайте мне знать.

Всем, кто предлагаетрука в этом: большое спасибо.

Ответы [ 2 ]

4 голосов
/ 01 апреля 2012

Я думаю, что вы там подделываете пробелы:

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

В следующий раз вы использовали переменную $wher, когда вы добавили ее к $select.

Если более того, где arg, то где:

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

Вы не сделали ошибку с мыслью о выборе SELECT. Кстати, у вас есть два одинаковых цикла и тест для выбранного поколения if ( $iQuery <= $columnCount ). Один в цикле где, а другой снаружи. Какая польза?

Редактировать: И, конечно, я забыл указать, почему у вас есть эта ужасная ошибка: Это в

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

Вы создаете таблицу, которая будет выглядеть так: array ( "{:akey}" => "avalue") (я рассматривал значение как строку. Почему вы использовали фигурные скобки ({}), это полностью меняет имя ключа (должно быть :keyname, а не {:keyname}

Редактировать 2: Был в хорошем настроении, так что вот упрощенная версия вашего метода извлечения (не проверено, но должно работать нормально)

/*
* $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

Prefered (`) используется для включения специального символа в имя столбца, поэтому, как и раньше, имя столбца не соответствует ни одному из существующих.

Изменить 5: Вместо того, чтобы разделять ваш ключ, чтобы создать ваши аргументы и массив аргументов. Вы можете использовать безопасный способ предотвращения появления вводящих в заблуждение символов, воспользовавшись счетчиком $ whereIt:

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

Привет

0 голосов
/ 01 апреля 2012

Проблема была в том, что у каждого столбца, который я имел в моей тестовой базе данных, был символ '.' между «пользователем» и именем столбца. Я решил проблему, просто заменив каждый период подчеркиванием, и это избавило от ошибки. Хотя по какой-то причине запрос все еще не работает, я уверен, что все будет хорошо.

Так, например:

user.email = user_email.

...