Предел доктрины нарушает мой запрос?

У меня такой код:

$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);

Предыдущий код работает должным образом.

Сгенерированный SQL завершен и работает:

ВЫБРАТЬ 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 вопрос q LEFT JOIN ответ 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) ГРУППА ПО q.id ЗАКАЗАТЬ ПО q.id DESC

Но если я хочу ограничить результаты, я изменяю конечные строки следующим образом:

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

Доктрина выдает ошибку:

SQLSTATE [HY093]: недопустимый номер параметра: количество связанных переменных не соответствует количеству токенов.

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 ГРУППА ПО q2.id ORDER BY q2.id DESC LIMIT 10 ', array (' user_id '=>' 1 ',' active_time '=>' 2013-03-17 17:12:12 ')) в SF_ROOT_DIR \ lib \ vendor \ symfony \ lib \ plugins \ sfDoctrinePlugin \ lib \ vendor \ doctrine \ Doctrine \ Query.php строка 1290 ...

Моя цель - ограничить запрос только 10 результатами, где мой подзапрос с функциями COALESCE и MAX? ¿Почему есть SELECT DISTINCT, которого я не указал? ¿Почему выбирается только q.id?

Я весь день пытаюсь понять это, у меня нет ответа ... Есть идеи, почему установка лимита вызывает это?


person Pipe    schedule 16.04.2013    source источник


Ответы (1)


Когда вы добавляете limit() в запрос Doctrine, внутренние компоненты Doctrine фактически создают два запроса. Первый выбирает ограниченный набор различных идентификаторов в зависимости от условий вашего запроса. Второй запрос выбирает фактические объекты, ограничивая выбор идентификаторами, найденными с помощью первого запроса.

Проблема с вашим запросом заключается в том, что вы используете params внутри части select, которая не используется в первом запросе.

Единственное решение, которое приходит мне в голову, - это добавить значение параметра active_time непосредственно в выбранную часть, без использования именованного параметра. Возможно, это не самое лучшее решение, но сейчас я не могу придумать другого. addSelect() не принимает дополнительные параметры, такие как where(), которые могут решить проблему (с where() вы можете использовать: ->where('field > ?', $value)).

person Michal Trojanowski    schedule 17.04.2013
comment
Привет @Michal, это странно, у меня много похожих Doctrine_Querys, использующих именованные параметры и подзапросы, и ir работает. Только у этого проблемы. Мой настоящий запрос примерно в 3 или 4 раза больше этого, мне нужно использовать именованные параметры, потому что я использую много подзапросов. Есть другие идеи? - person Pipe; 18.04.2013
comment
Используете ли вы указанные параметры в select части и в заявлении limit в других случаях? Сложность (почти) не имеет ничего общего с тем фактом, что вы будете использовать параметры или нет (поместите значения непосредственно в запрос). Использование named params больше похоже на Doctrine, но если нет другого способа, вам, возможно, придется отказаться от них. - person Michal Trojanowski; 18.04.2013
comment
Да, я использую тот же подзапрос, чтобы вычислить, активен вопрос или нет в других запросах, и другой большой запрос тоже использует ограничение и работает нормально ... это очень странно. В моем текущем запросе есть только один addSelect() с именованными параметрами (как в примере). У меня есть такие, как addSelect("(".otherSubquery->getDql().") as Value"); в otherSubquery также есть именованные параметры. Действительно, неплохо заменить: COALESCE((".$sub_query_is_active.") > :active_time на COALESCE((".$sub_query_is_active.") > $active_time? это может быть проблема безопасности? - person Pipe; 18.04.2013
comment
Я не понимаю, почему я могу использовать почти один и тот же запрос в одном месте, используя именованные параметры, и хорошо работает ... в любом случае, я следую предложению @Michal, я изменил некоторые именованные параметры (: param) и заменил их на $ param непосредственно в строка, и это сработало. Спасибо! :) - person Pipe; 18.04.2013
comment
Это должно быть различие в использовании запроса или сгенерированного Dql (с использованием $sub_query_is_active против $otherSubquery->getDql()), хотя вам придется копаться во внутренностях, чтобы увидеть, что там происходит. - person Michal Trojanowski; 18.04.2013
comment
Что касается безопасности - если $active_time можно прочитать из пользовательского ввода, вероятно, неплохо было бы избежать его вручную. Если значение устанавливается только в сценарии, это не должно быть проблемой для безопасности. - person Michal Trojanowski; 18.04.2013