Question

I have the following code:

$params = array();
$query_questions_visibles = questionTable::getInstance()->createQuery("q")
    ->select("q.*, ua.*, a.*, u.*, c.*")
    ->leftJoin("q.Answers a")
    ->leftJoin("a.UserAnswers ua")
    ->Where("q.blocked = false")
    ->andWhere("ua.user_id = :user_id")
->orderBy("q.id DESC")
->groupBy("q.id");

    //Subquery --> Calculates when a question is active or not      
    $format = sfConfig::get("app_datetime_format");
    $active_time = date($format, strtotime(sfConfig::get("app_question_active_time")));
    $sub_query_is_active = $query_questions_visibles->createSubQuery()
            ->select("MAX(ua0.created_at)")
            ->from("question q0")
            ->leftJoin("q0.Answers a0")
            ->leftJoin("a0.UserAnswers ua0")
            ->where("q0.id = q.id");                
    $query_questions_visibles->addSelect("COALESCE((".$sub_query_is_active.") > :active_time, false) as Active");

//Set param values
$params["user_id"] = $guardUser->id;
$params["active_time"] = $active_time;

$result = $query_questions_visibles->execute($params);

The previous code works as expected.

Generated SQL is complete and works:

SELECT q.id AS q__id, q.user_id AS q__user_id, q.category_id AS q__category_id, q.gender_restriction AS q__gender_restriction, q.question AS q_question, q.photo AS q_photo, q.latitude AS q_latitude, q.longitude AS q_longitude, q.multiple AS q_multiple, q.blocked AS q_blocked, q.created_at AS q__created_at, q.updated_at AS q__updated_at, a.id AS a__id, a.question_id AS a__question_id, a.text AS a_text, u.id AS u_id, u.user_id AS u__user_id, u.answer_id AS u__answer_id, u.created_at AS u__created_at, u.updated_at AS u__updated_at, COALESCE((SELECT MAX(u2.created_at) AS u2__0 FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE (q2.id = q.id)) > :active_time, 0) AS u2__0 FROM question q LEFT JOIN answer a ON q.id = a.question_id LEFT JOIN user_answer u ON a.id = u.answer_id WHERE (q.blocked = 0 AND u.user_id = :user_id) GROUP BY q.id ORDER BY q.id DESC

But, if I want to limit results, I modify the end lines as:

$query_questions_visibles->limit(10);
$result = $query_questions_visibles->execute($params);

Doctrine throws an error:

SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens

at Doctrine_Connection->execute('SELECT DISTINCT q2.id FROM question q2 LEFT JOIN answer a2 ON q2.id = a2.question_id LEFT JOIN user_answer u2 ON a2.id = u2.answer_id WHERE q2.blocked = 0 AND u2.user_id = :user_id GROUP BY q2.id ORDER BY q2.id DESC LIMIT 10', array('user_id' => '1', 'active_time' => '2013-03-17 17:12:12')) in SF_ROOT_DIR\lib\vendor\symfony\lib\plugins\sfDoctrinePlugin\lib\vendor\doctrine\Doctrine\Query.php line 1290 ...

My purpose is only limit the query to 10 results, ¿where is my Subquery with COALESCE and MAX functions? ¿Why there's a SELECT DISTINCT who I never specified? ¿Why is selecting only q.id?

I spend all day trying to figure it out, i have no answer... Any Ideas why setting a limit causes this?

Was it helpful?

Solution

When you add limit() to the Doctrine query then the Doctrine internals create in fact two queries. The first one select a limited set of distinct ids based on the conditions of your query. The second query selects the actual objects limiting the select to the ids found with the first query.

The problem with your query is that you use params inside of the select part, which is not used in the first query.

The only solutuion that comes to my mind is to add the value of the active_time parameter directly to the select part, without using the named param. It might not be the nicest solution but I can't think of a different one right now. The addSelect() does not accept additional parameters like where() does which could fix the issue (with where() you can use: ->where('field > ?', $value)).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top