"persons" table:
id | name
-----------
1 | alice
2 | ben
3 | claire
"items" table:
id | name | person_id | is_active
-----------------------------------------
1 | apple | 1 | NO
2 | banana | 2 | YES
3 | carrot | 2 | NO
4 | dragonfruit | 3 | NO
5 | eggplant | 3 | YES
So by running the below query:
SELECT * FROM persons p
LEFT JOIN items i ON p.id = i.person_id
I get:
id | name | id | name | person_id | is_active
-----------------------------------------------------
1 | alice | 1 | apple | 1 | NO
2 | ben | 2 | banana | 2 | YES
2 | ben | 3 | carrot | 2 | NO
3 | claire | 4 | dragonfruit | 3 | NO
3 | claire | 5 | eggplant | 3 | YES
Rules in application-level as follows:
- Each person must have at least 1 item.
- Each person can have 0 or 1 active items only.
I want to filter the above result to get:
- Get 1 record only for each person.
- Get the row with is_active = "YES" if person has an active item. If person doesn't have any active item, get 1 record (any record) of that person.
- Order result by person id DESC.
So I'm trying to get something like this:
id | name | id | name | person_id | is_active
-----------------------------------------------------
3 | claire | 5 | eggplant | 3 | YES
2 | ben | 2 | banana | 2 | YES
1 | alice | 1 | apple | 1 | NO
EDIT:
I need to get the persons records (even ones without an active item). From the items table I need only the active item's name. If the person doesn't have an active item, it's fine if I can get it as empty string or null. So something like this will also be ok:
id | name | item_name
-----------------------------------------------------
3 | claire | eggplant
2 | ben | banana
1 | alice |
Best Answer
Thanks for the clear specifications of the requirements, and the sample input and output.
"Each person must have at least 1 item." -- probably no extra code.
"Each person can have 0 or 1 active items only." --
GROUP BY person_id
, then do the test inHAVING SUM(is_active = 'YES') <= 1
."Get 1 record only for each person" -- The
GROUP BY
does that."Get the row with is_active = "YES" if person has an active item. If person doesn't have any active item, get 1 record (any record) of that person." -- This gets tricky. If there were only one person, something like this should work:
ORDER BY is_active = 'YES' DESC LIMIT 1
. But that does not work with grouping. More in a minute."Order result by person id DESC" -- This happens at the end.
Now it gets tricky because you need a "groupwise max". Let's try to get the
item.id
values rather than just the one id desired. Then work on getting the details for the 'first'id
. And let's wait until the end to get theperson.name
; we can easily ignore it until then.See if that gives you the correct set of rows (1 per person, ordered correctly) and the first
id
ofids
is the desireditem
. Assuming all that works, let's finish by getting the other desired columns. (I will eliminate the redundant column in your sample output, and toss the ids.)(There is, of course, a chance that I goofed. But that could come close.)