2

Ok, so I'm sure that was a freakishly confusing question. Let me try to explain more clearly...

Problem:

enter image description here

Schema is simple, essentially:

enter image description here

I'm working with a very large data set and need to compile everything into just 1 efficient query. There are several one to many relationships and I'm attempting to "filter" the data set.

I want all preceptor associations for events that have at least 1 preceptor matching the given ID.

For example, I have an "event" entity that can have zero or several "preceptors" associated with it. My user's filter needs to allow them to choose a "preceptor" and return all events with the given preceptor ID. Well that's easy enough. BUT I need to still list the other preceptors - I need the other relationships to still be queried, but require at least 1 of the associations to match the given criteria.

I hope that makes a bit more sense. I can always "filter" the data once it's queried, but I'd like to avoid getting irrelevant data since it's such a huge data set.

Here's a snippet of my code:

        $qb->select($selectPartials)
       ->from('EventLegacy', 'e')
       ->leftJoin('e.site', 's')
       ->leftJoin('s.program_site_associations', 'psa')
       ->leftJoin('e.base', 'b')
       ->leftJoin('b.program_base_associations', 'pba')
       ->leftJoin('e.preceptor_associations', 'pa')
       ->leftJoin('pa.preceptor', 'pre')
       ->andWhere('e.program = ?3')
       ->andWhere('e.start_datetime >= ?1')
       ->andWhere('e.start_datetime <= ?2')
       ->andWhere('psa.active = true')
       ->andWhere('psa.program = ?3')
       ->andWhere('pba.active = true')
       ->andWhere('pba.program = ?3')
       ->andWhere('pre.id = ?4')
       ->orderBy('e.start_datetime')
       ->setParameter(1, $startDate)
       ->setParameter(2, $endDate)
       ->setParameter(3, $program)
       ->setParameter(4, $preceptorId);

        return $qb->getQuery()->getArrayResult();

An equivalent SQL Query:

SELECT *
FROM EventData e0_
LEFT JOIN AmbulanceServices a1_ ON e0_.site_id = a1_.AmbServ_id
LEFT JOIN ProgramSiteData p2_ ON a1_.AmbServ_id = p2_.AmbServ_id
LEFT JOIN AmbServ_Bases a3_ ON e0_.StartBase_id = a3_.Base_id
LEFT JOIN ProgramBaseData p4_ ON a3_.Base_id = p4_.Base_id
LEFT JOIN EventPreceptorData e5_ ON e0_.Event_id = e5_.Event_id
LEFT JOIN PreceptorData p6_ ON e5_.Preceptor_id = p6_.Preceptor_id
WHERE (e0_.Program_id = 287)
  AND (e0_.start_datetime >= ?)
  AND (e0_.start_datetime <= ?)
  AND (p2_.Active = 1)
  AND (p2_.Program_id = 287)
  AND (p4_.Active = 1)
  AND (p4_.Program_id = 287)
  AND (p6_.Preceptor_id = 179293)
ORDER BY e0_.start_datetime ASC

Here's some fake data that may be helpful.

Let's say I have 3 events total. (id, name)
1, eventA
2, eventB
3, eventC

eventA has 2 preceptors associated with it, eventB doesn't have any, and eventC has 1. So, our EventPreceptorData table would have something like this:
(id, event_id, preceptor_id)
1,1,1
2,1,2
3,3,1

Our prceptors (PreceptorData) may look something like this (id, name)
1, Bob
2, Chris

So if I were searching for Bob, I would want to see events A and C, and I would want my output to be:

eventA
Preceptors: Bob, Chris

eventB
Preceptors: Bob

My issue is that "Chris" does not get listed (Which makes perfect sense considering my query).

ahammond
  • 125
  • 2
  • 7
  • It might help to write this as an SQL query and work backwards from there to convert it to a Doctrine query. Even after that lengthier explanation I can't quite work out the logic you want to use to determine the result set :-P – DaveRandom Apr 22 '13 at 16:11
  • http://sqlfiddle.com/ may help you to clarify your ideas. Also reminds me of panel #2 of http://xkcd.com/568/ – DaveRandom Apr 22 '13 at 16:17
  • Alright, added some more clarification. Hopefully that helps :) Thanks in advance! – ahammond Apr 22 '13 at 16:39
  • Which table does the additional (currently missing) data come from? – DaveRandom Apr 22 '13 at 16:42
  • The additional data, comes from the same table as the partially included data: PreceptorData – ahammond Apr 22 '13 at 16:49
  • OK I think I can see where the issue is now - remember you cannot have an arbitrary width row in a result set (meaning every row in the result set must have the same number of columns). Since it sounds like each event can have an arbitrary number of preceptors, you need to be thinking in terms of 1 per-row instead of *n* per row. In short, I suspect that what you have in your head at the moment isn't actually possible, and you need to rethink the result set you are expecting. – DaveRandom Apr 22 '13 at 16:55
  • Unless I still don't understand what you are trying to do, in which case some concrete input data/expected result set would probably be the best thing to get your point across. – DaveRandom Apr 22 '13 at 16:56
  • Haha sure, I think it's entirely possible that what I want to do is not possible. I was just hoping that wasn't the case! – ahammond Apr 22 '13 at 17:06
  • Yeh see you can't do that (with your most recent edit), at least, not directly. Because in order to get the extra column that shows the second preceptor, you would have to join the preceptors onto the data *twice* - which is of course perfectly possible, but the problem is that the number of joins you would need to do is arbitrary and, crucially, cannot be known ahead of time. – DaveRandom Apr 22 '13 at 17:12
  • 1
    You could work around this (probably) if you were using MySQL and sending raw queries using `GROUP BY` and `GROUP_CONCAT()` to join the preceptor data into strings (this may not be what you want of course, but it's a start) - there is [apparently](http://stackoverflow.com/questions/7864345/doctrine2-and-group-concat) a Doctrine extension that can give you this functionality, although I can't vouch for whether it actually works. – DaveRandom Apr 22 '13 at 17:14
  • Just remember that your data/result set can only ever be a grid with a uniform number of columns per row - you cannot sensibly get anything table-driven to represent n-dimensional data in a single query/result set. I'm heading home now, hope you get it sorted :-) – DaveRandom Apr 22 '13 at 17:17

0 Answers0