Viewed   98 times

UPDATE

I was making a petty mistake when listing the VALUES. I should have put ":username" and not ":alias". I suppose the answer credit to this question is free reign for anyone who wants it? Or do I delete the question?

ORIGINAL

I've been using Yii's active record pattern for a while. Now, my project needs to access a different database for one small transaction. I thought the Yii's DAO would be good for this. However, I'm getting a cryptic error.

CDbCommand failed to execute the SQL statement: SQLSTATE[HY093]: Invalid parameter number: parameter was not defined

Here is my code:

public function actionConfirmation
{
    $model_person = new TempPerson();

    $model = $model_person->find('alias=:alias',array(':alias'=>$_GET['alias']));
    $connection=Yii::app()->db2;
            $sql = "INSERT INTO users (username, password, ssn, surname
                    , firstname, email, city, country) 
                    VALUES(:alias, :password, :ssn, :surname
                    , :firstname, :email, :city, :country)";
            $command=$connection->createCommand($sql);
            $command->bindValue(":username", $model->alias);
            $command->bindValue(":password", substr($model->ssn, -4,4));
            $command->bindValue(":ssn", $model->ssn);
            $command->bindValue(":surname", $model->lastName);
            $command->bindValue(":firstname", $model->firstName);
            $command->bindValue(":email", $model->email);
            $command->bindValue(":city", $model->placeOfBirth);
            $command->bindValue(":country", $model->placeOfBirth);
            $command->execute();
            $this->render('confirmation',array('model'=>$model));
}

This constructs the following query (as seen on the application log):

INSERT INTO users (username, password, ssn, surname, firstname, email
                   , city, country) 
VALUES(:alias, :password, :ssn, :surname, :firstname, :email, :city, :country);

FYI $model->placeOfBirth is supposed to be in both city and county values. That's not a typo (just a silly thing I have to do).

 Answers

3

Just to provide an answer - because this error is pretty common - here are a few causes:

1) The :parameter name does not match the bind by mistake (typo?). This is what happened here. He has :alias in the SQL statement, but bound :username. So when the param binding was attempted, Yii/PDO could not find :username in the sql statement, meaning it was "one parameter short" and threw an error.

2) Completely forgetting to add the bindValue() for a parameter. This is easier to do in Yii other constructs like $critera, where you have an array or params ($criteria->params = array(':bind1'=>'test', ':bind2'=>'test)).

3) Weird conflicts with CDataProvider Pagination and/or Sorting when using together and joins. There is no specific, easy way to characterize this, but when using complex queries in CDataProviders I have had weird issues with parameters getting dropped and this error occurring.

One very helpful way to troubleshoot these issues in Yii is to enable parameter logging in your config file. Add this to your db array in your config file:

'enableParamLogging'=>true,

And make sure the CWebLogRoute route is set up in your log section. This will print out the query that gave and error, and all of the parameters it was attempting to bind. Super helpful!

Sunday, October 16, 2022
3

If you use positional parameters, the array of parameters you pass to execute() must be an ordinal array. Likewise, if you use named parameters, the array must be an associative array.

Here's a test to confirm the behavior:

$stmt = $db->prepare("SELECT ?, ? ,?");

$params = array( 'a', 'b', 'c' );
// OK
if ($stmt->execute($params)) {
  print_r($stmt->fetchAll());
}

$params = array( 'A'=>'abc', 'B'=>'def', 'C'=>'ghi' );
// ERROR!
if ($stmt->execute($params)) {
  print_r($stmt->fetchAll());
}

$stmt = $db->prepare("SELECT :A, :B, :C");

$params = array( 'a', 'b', 'c' );
// ERROR!
if ($stmt->execute($params)) {
  print_r($stmt->fetchAll());
}

$params = array( 'A'=>'abc', 'B'=>'def', 'C'=>'ghi' );
// OK
if ($stmt->execute($params)) {
  print_r($stmt->fetchAll());
}

Note that in current versions of PHP, the associative array keys don't have to be prefixed with : as @prodigitalson comments. The : prefix used to be required in array keys in older versions of PHP.

It's also worth mentioning that I've encountered bugs and unpredictable behavior when I tried to mix positional parameters and named parameters in a single query. You can use either style in different queries in your app, but chose one style or another for a given query.

Sunday, October 30, 2022
1

The problem - and you will kick yourself - is with :color.

The array key for the value you are passing for that marker when calling execute() is named :color:. Remove the trailing : (I'm guessing this was just a typo anyway).

$stmt3->execute(array(
    ':room' => $Clean['room'],
    ':name' => $Clean['name'],
    ':message' => $Clean['message'],
    ':time' => $time,
    ':color' => $Clean['color'],
    ));
Friday, September 23, 2022
 
5

You can try this:

$connection=Yii::app()->db;   // assuming you have configured a "db" connection
$sql = 'SELECT id, parent, naam FROM categories ORDER BY naam';
$command=$connection->createCommand($sql);
$dataReader=$command->queryAll();


function createList($elements, $parentId = 0) {
        $branch = array();

        foreach ($elements as $element) {
            if ($element['parent'] == $parentId) {
                $children = createList($elements, $element['id']);
                if ($children) {
                    $element['children'] = $children;
                }
                $branch[] = $element;
            }
        }

        return $branch;
    }

    $list = createList($dataReader);
    CVarDumper::dump($list, 5678, true);
Wednesday, August 3, 2022
 
kbtz
 
5

PHP will not replace placeholders inside strings, i.e within quotes. As in:

$criteria->addCondition('col = :app'); // param can be replaced
$criteria->addCondition('col = ":app"'); // param can't be replaced

Therefore we need to use mysql's CONCAT() function to actually generate the string for regexp, instead of providing the string ourselves, like so:

$criteria->addCondition('col regexp CONCAT("[[:<:]]", :app, "[[:>:]]")');

OR, bind the entire regex itself:

$criteria->addCondition('col regexp :regexp');
$criteria->params = array(':regexp'=>'[[:<:]]'.$app.'[[:>:]]');
Friday, September 30, 2022
 
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :