I have built the following query with the Doctrine Query Builder in my Symfony application.
$qb->select('c')
->from('AppBundle:Course', 'c')
->join('AppBundle:Log', 'a', Expr\Join::WITH, $qb->expr()->eq('c.id', 'a.course'))
->where($qb->expr()->in('a.type', ':type'))
->andWhere($qb->expr()->between('a.time', ':start', ':end'))
->andWhere($qb->expr()->eq('c.status', ':status'))
->setParameter(':type', ['opened'])
->setParameter(':standardScratchScore', [74])
->setParameter(':status', Course::OPENED)
->setParameter(':start', $dateFrom->format('Y-m-d H:i:s'))
->setParameter(':end', $dateTo->format('Y-m-d H:i:s'))
;
In my code I iterate over the Course
s and then again query the Log
table to check that an entry with a specific type doesn't exist for the Course
. Is there a way I can incorporate the exclusion of log.type = 'log.sent-email'
for this Course into this initial query, without using something like a sub-select?
Querying the same table again within the loop feels sub-optimal to me and NewRelic suggests it is hurting the performance of my application.
Well you can always join the table one more time for this specific need:
$qb->select('c')
->from('AppBundle:Course', 'c')
->join('AppBundle:Log', 'a', Expr\Join::WITH, $qb->expr()->eq('c.id', 'a.course'))
->leftjoin(
'AppBundle:Log',
'b',
Expr\Join::WITH,
$qb->expr()->andx(
$qb->expr()->eq('c.id', 'b.course'),
$qb->expr()->eq('b.type', 'log.sent-email')
))
) // join log a second time, with the type condition
->where($qb->expr()->in('a.type', ':type'))
->andWhere($qb->expr()->between('a.time', ':start', ':end'))
->andWhere($qb->expr()->eq('c.status', ':status'))
->andWhere($qb->expr()->isNull('b.type')) // Only select records where no log record is found
->setParameter(':type', ['opened'])
->setParameter(':standardScratchScore', [74])
->setParameter(':status', Course::OPENED)
->setParameter(':start', $dateFrom->format('Y-m-d H:i:s'))
->setParameter(':end', $dateTo->format('Y-m-d H:i:s'))
;