Doctrine 2 - How to add limit in multiple addSelect

Viewed 798

Problem : got Error when i run my query

{
    "status": false,
    "error": {
        "classname": "Doctrine\\ORM\\Query\\QueryException",
        "message": "[Syntax Error] line 0, col 783: Error: Expected Doctrine\\ORM\\Query\\Lexer::T_CLOSE_PARENTHESIS, got 'LIMIT'"
    }
}

How can i add limit in addSelect in below query.

 $qb = $this->em->createQueryBuilder();
    $qb->select("identity(igsm.group) as group_id,
    qp.id AS q_paper_id,
    qp.name AS q_name,
    qp.description AS q_description,        
    qp.marks,
    identity(qp.questionPaperStatus) AS qpStatus,
    qp.timeInMinutes as time_in_minutes,
    sa.marks as marks_obtained,
    sa.id AS assessment_id");
    $qb->addSelect("(SELECT IfElse(count(qps.id) > 0 , TRUE, FALSE) FROM Entity\QuestionPaper qps "
            . "WHERE qps.createdBy = :userId AND qps.id = qp.id) as flag");
    $qb->addSelect("(SELECT count(qpe.id) from Entity\QuestionPaperEvaluation qpe "
            . "where qpe.questionPaper = qp.id AND qpe.user = :userId) as student_evaluation_cnt");
    $qb->addSelect("(SELECT LOWER(ats.assignee) from Entity\AssessmentTimelineStatus ats, Entity\AssessmentStudentTimeline ast "
            . "WHERE ast.assessmentTimelineStatus = ats.id AND ast.user = igsm.user AND ast.assessment = qp.id "
            . "ORDER BY ats.id DESC LIMIT 1) AS assignee");
    $qb->addSelect("(SELECT identity(ast.assessmentTimelineStatus) from Entity\AssessmentTimelineStatus ats, Entity\AssessmentStudentTimeline ast "
            . "WHERE ast.assessmentTimelineStatus = ats.id AND ast.user = igsm.user AND ast.assessment = qp.id "
            . "ORDER BY ats.id DESC LIMIT 1) AS assessment_timeline_id");
    $qb->addSelect("(SELECT UPPER(ConcatWs(' ', ats.action,ats.item)) as assesment_submissions from Entity\AssessmentTimelineStatus ats, "
            . "Entity\AssessmentStudentTimeline ast WHERE ast.assessmentTimelineStatus = ats.id AND ast.user = igsm.user AND ast.assessment = qp.id "
            . "ORDER BY ats.id DESC LIMIT 1) AS action");
    $qb->from('Entity\QuestionPaperGroupStudentMap', 'qpgsm');
    $qb->innerJoin('Entity\InstituteGroupStudentMap', 'igsm', 'WITH', 'igsm.id=qpgsm.instituteGroupStudentMap');
    $qb->innerJoin('Entity\QuestionPaper', 'qp', 'WITH', 'qp.id=qpgsm.questionPaper AND qp.questionPaperStatus > 4');
    $qb->leftJoin('Entity\AssesmentSubmissions', 'sa', 'WITH', 'sa.assesmentId = qp.id AND sa.userId = igsm.user');
    $qb->leftJoin('Entity\PackageQuestionPaperHistory', 'pqph', 'WITH', 'pqph.questionPaperId = qp.id');
    $qb->where('igsm.user = :userId')->setParameter(':userId', $userId);
    $qb->andWhere("igsm.group IN (:GroupIds)")->setParameter(':GroupIds', explode(",", $groupId));
    $qb->orderBy('qpgsm.id', 'DESC');
    $qb->setMaxResults(1);
    $result = $qb->getQuery()->getResult();
    return $result;

Can i put subquery individualy though Subquery is dependent on main query. How can i add limit in my sub query.

Thanks.

1 Answers

There is an issue about this in github.

The same question has been asked:

A possible quick hack solution could be to:

  • Prepend the desired select column with the "order by" column in the select statement
  • use MIN or MAX to aggregate the results to just get the 1st one(to have the same result as LIMIT 1)

This subselect:

$qb->addSelect("(SELECT LOWER(ats.assignee) from Entity\AssessmentTimelineStatus ats, Entity\AssessmentStudentTimeline ast "
        . "WHERE ast.assessmentTimelineStatus = ats.id AND ast.user = igsm.user AND ast.assessment = qp.id "
        . "ORDER BY ats.id DESC LIMIT 1) AS assignee");

would be written as:

$qb->addSelect("(SELECT MAX(concat(ats.id, ' ', LOWER(ats.assignee))) from Entity\AssessmentTimelineStatus ats, Entity\AssessmentStudentTimeline ast "
        . "WHERE ast.assessmentTimelineStatus = ats.id AND ast.user = igsm.user AND ast.assessment = qp.id "
        . "ORDER BY ats.id DESC) AS assignee");

When you get the "assignee" value, you can split to the 1st single whitespace value and get the value of "LOWER(ats.assignee)".

$result = explode(' ',$assignee, 2);

Use MAX when the ORDER BY is DESC and MIN when ASC.

This works because MAX or MIN aggregate function select only the highest or lowest value, which can be either a number or a string.

References

MAX/MIN mysql documentation

explode to 1st whitespace character

Related