SQLSTATE[HY093]: недопустимый номер параметра: параметр не был определен (PDO)

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

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

Пример 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 );
    }

Пример Б: doQuery( $query, $sqlParams, $return = FALSE, $queryType = QueryType::None )

Эта функция относительно проста: все, что она делает, — это привязывает значения и выполняет инструкцию, быстро проверяя, какой тип возвращать (типы возвращаемых значений, которые являются «строка», «столбец» или «все», определяются класс 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' => '[email protected]' )
);


var_dump( $res );

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

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

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


person zeboidlund    schedule 01.04.2012    source источник
comment
Сравните сгенерированный SQL с количеством связанных параметров, а затем выясните, почему это число не совпадает.   -  person Corbin    schedule 01.04.2012
comment
Проблема в том, что привязан только один параметр. Я протестировал цикл for, который проходит и связывает параметры. Я также могу вывести переменные, которые выглядят точно так, как должны выглядеть.   -  person zeboidlund    schedule 01.04.2012
comment
Нет, проблема в том, что никакие параметры не привязаны (точнее, у вас есть N параметров и вы привязываете некоторый x, такой что x ‹ N). Параметр не был определен означает, что параметр не был привязан. Я слишком ленив, чтобы просмотреть ваш код и увидеть, где несоответствие.   -  person Corbin    schedule 01.04.2012


Ответы (2)


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

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

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

Если больше того, где аргумент, где находится:

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

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

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

$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: BTW не видел ваш тестовый образец, но имя параметра не может содержать '.' уголь

Редактировать 4: Не видел, чтобы вы решили это, я добавил pre_replace, чтобы заменить '.' в вашем подмножестве. Также избавьтесь от символа '`' при отображении ключа, иначе запрос завершится ошибкой.

`user.email`=:arg

Не нравится =)

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

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

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

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

С уважением

person grifos    schedule 01.04.2012
comment
Отредактированный пост, чтобы добавить, почему у вас есть эта ошибка (забыл сказать xD) - person grifos; 01.04.2012
comment
Да, я ценю помощь, но, к сожалению, у меня все тот же запрос с моим var_dump(), который выводит: SELECT user.id, user.email, user.firstname, FROM evol_users WHERE user.email= :user.email. - person zeboidlund; 01.04.2012
comment
Что возвращает var_dump или $sqlParams? - person grifos; 01.04.2012
comment
var_dump(); $sq;Params — это параметры, используемые для привязки к запросу. Спасибо за редактирование, хотя, это помогло :). - person zeboidlund; 01.04.2012
comment
Oups забыл добавить разделитель в предложение where - person grifos; 01.04.2012

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

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

user.email = user_email.

person zeboidlund    schedule 01.04.2012