Reputation: 6896
So let's say I have a database that looks like this
Posts
id | author_id | created_at
1 1 1.day.ago
2 1 2.day.ago
3 2 3.day.ago
4 1 4.day.ago
Authors
id | type
1 Male
2 Female
I want to do a query on these posts so that they return in desc order of created, but also going through all the types.
So if I just did:
Post.order('created_at desc')
I would get:
Posts
id | author_id | created_at
1 1 1.day.ago
2 1 2.day.ago
3 2 3.day.ago
4 1 4.day.ago
But let's say instead I want the results to be in this order:
Posts
id | author_id | created_at
1 1 1.day.ago
3 2 3.day.ago
2 1 2.day.ago
4 1 4.day.ago
So that I get first the most recent post from author 1, then the most recent post from author 2, even if it's older than the next post from author 1, then, since there are no more posts from author 2, it returns the rest in normal created_at order.
Let's assume there will never be more than 20 authors or so, but I always want to cycle through the most recent posts from each other, then the next most recent one from each, etc.
Is this possible to do in sql?
Upvotes: 1
Views: 57
Reputation: 15140
You can order by a custom order using something like:
ORDER BY ROW_NUMBER()OVER(PARTITION BY author_id ORDER BY created_at DESC)
, author_id
If you add it to the select, you can see the result more easy, and apply tweaks where necessary.
At least, this is allowed in sql server, I assume likewise for postgreSQL.
Upvotes: 1
Reputation: 520968
We can assign a row number across a partition on authors, with the most recent posts being assigned the lowest row numbers. Then order by this row number, followed by the author id to break the tie.
select
t.id,
t.author_id,
t.created_at
from
(
select id, author_id, created_at,
row_number() over (partition by author_id order by created_at desc) rn
from Posts
) t
order by
t.rn,
t.author_id
Upvotes: 1
Reputation: 42753
If I correctly understand, one way is:
with Posts(id , author_id , created_at) as(
select 1 , 1 ,'2017-09-17'::date union all
select 2 , 1 ,'2017-09-16'::date union all
select 3 , 2 ,'2017-09-15'::date union all
select 5 , 2 ,'2017-09-10'::date union all
select 4 , 1 ,'2017-09-14'::date
)
select * from (
select * ,row_number() over(partition by author_id order by created_at desc) as rn
from Posts
) t
order by rn, created_at desc
Upvotes: 1