I actually am a little new to how SQL works -- i've always let my ORM's handle everything for me. But this in this case Persistent doesn't expose this kind of functionality so I'm at lost at what to do.
I have a many-to-many relationship:
+------------+
| Entries |
+----+-------+
| id | date |
+----+-------+
| 1 | Jan 1 |
+----+-------+
| 2 | Jan 2 |
+----+-------+
| 3 | Jan 3 |
+----+-------+
+------------+
| Tags |
+------------+
| id | label |
+----+-------+
| 1 | Apple |
+----+-------+
| 2 | Boat |
+----+-------+
| 3 | Car |
+----+-------+
+-------------------+
| EntryTags |
+----------+--------+
| entry_id | tag_id |
+----------+--------+
| 1 | 1 |
+----------+--------+
| 1 | 2 |
+----------+--------+
| 2 | 2 |
+----------+--------+
| 3 | 3 |
+----------+--------+
And I want to sort tags primarily by the date of their most recent entry (descending), secondarily by their label (ascending).
Tag Car
's most recent entry is on Jan 3rd, so it goes first.
Tag Apple
's most recent entry is January 2nd, but so is tag Boat
. However, the label Apple
comes before the label Boat
alphabetically, so Apple
is 2nd and Boat
is 3rd:
returns:
1. Tag w/ id 3
2. Tag w/ id 1
3. Tag w/ id 2
Through my research I've figured out that I need some kind of combination of joins to do this. However so far I've only found soutions for one-to-many relations (sorting topics in a thread by their most recent post), and I think I understand them, but none involving these three-way joins for many-to-many relations.
I'm including raw sql as a possible answer because I think I'm really just asking for the sql way to do it, and even though I'm using Esqueleto for my SQL bindings, I think that once I understand the SQL, the translation to Esqueleto will be straightforward. I'm using postgresql as my backend, but I'd rather not use postgres-specific things because my bindings are for general backends.
Anyone have any idea where I can start? What kind of joins should I be looking at and how do I sort through most recent entry?
Another solution:
select t.id as tag_id, t.label as tag, max(date) as date from Tags t
join EntryTags et on t.id=et.tag_id
join Entries e on e.id=et.entry_id
group by t.label,t.id
order by date desc,tag
which returns:
tag_id tag date
------ ----- -----
1 Apple jan 3
3 Car jan 3
2 Boat jan 2
(In your data, Apple's most recent entry is January 3, not January 2.)
Joins in Postgres are implicity "inner joins". If you may have tags without entries, you will want to change the joins to left joins.