Context
Using PostgreSQL, I’m storing articles
and their associated events
. Here is a simple structure of the 2 tables for the sake of the example:
Articles table
x
+----+-----------+-----------------------+
| ID | title | description |
+----+-----------+-----------------------+
| 1 | article 1 | article 1 description |
| 2 | article 2 | article 2 description |
| 3 | article 3 | article 3 description |
| 4 | article 4 | article 4 description |
| 5 | article 5 | article 5 description |
+----+-----------+-----------------------+
Events table
+-----+-----------+--------------+----------------+--------------+
| ID | name | eventable_id | eventable_type | created_at |
+-----+-----------+--------------+----------------+--------------+
| 1 | validated | 1 | Article | 2020-05-10 |
| 2 | reported | 1 | Article | 2020-05-11 |
| 3 | reported | 2 | Article | 2020-05-10 |
| 4 | reported | 2 | Article | 2020-05-11 |
| 5 | reported | 2 | Article | 2020-05-12 |
| 6 | reported | 3 | Article | 2020-05-20 |
| 7 | validated | 3 | Article | 2020-05-21 |
| 8 | reported | 4 | Article | 2020-05-12 |
| 9 | moved | 4 | Article | 2020-05-13 |
| 10 | reported | 4 | Article | 2020-05-14 |
| 11 | moved | 5 | Article | 2020-05-13 |
| 12 | moved | 5 | Article | 2020-05-14 |
+-----+-----------+--------------+----------------+--------------+
Problem
Here I need to be able to get all articles
which have their latest events
being reported
.
So for example, following the data above, we must only get:
article 1
: because it has beenvalidated
thenreported
article 2
: because it only has beenreported
article 4
: because it has beenmoved
thenreported
(same as article 1)
As you can see:
article 3
: should not be return because its latest event isvalidated
.article 5
: should not be return because its latest event ismoved
.
I can easily find all articles
having a reported
event. But how to get the ones having their latest event to be reported
?
Here is what I did try to do so far without success:
SELECT *
FROM articles a
INNER JOIN (
SELECT *
FROM events
WHERE name = 'reported'
ORDER BY created_at
LIMIT 1
) AS e ON e.moderable_id = a.id AND e.moderable_type = 'Article'
We currently have:
- 459 892
articles
- 62 074
events
Advertisement
Answer
You could use a correlated subquery for filtering:
select a.*
from articles a
where
(
select e.name
from events e
where e.eventable_id = a.id and e.eventable_type = 'Article'
order by created_at desc
limit 1
) = 'reported'
We could also express this with a lateral join:
select a.*
from articles a
inner join lateral (
select e.name
from events
where e.eventable_id = a.id and e.eventable_type = 'Article'
order by created_at desc
limit 1
) x on x.status = 'reported'