Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

SQL Fiddle

Your sample data does not fit the text. The table entrytags should be

(1, 1),
(1, 2),
(2, 2),
(2, 1),
(3, 3);

select id, label
from (
    select distinct on (t.id) e.date, t.label, t.id
    from
        entries e
        inner join
        entrytags et on et.entry_id = e.id
        inner join
        tags t on t.id = et.tag_id
    order by t.id, e.date desc, t.label
) s
order by "date" desc, label
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top