Ok, I have experience in various databases, but not Oracle specifically, so still trying to wrap my head around how it handles things (i.e. the lack of 'Top' drives me mad!) Anyway, here's what we're trying to do...
Note: We're using Oracle 11. I understand a new feature was added to Oracle 12 (i.e. FETCH NEXT n ROWS ONLY
) but we can't use that unfortunately.
To start, we have an articles table (technically it's a view, but I'm simplifying it here). Here are the relevant fields...
- ID (Integer, Primary Key)
- Title (String)
- Body (String)
- IsFavorite ('Y' or 'N')
- IsFeatured ('Y' or 'N')
- DatePublished (Date)
Multiple articles can be marked as favorites and/or featured.
What we want to return is a result set that has the following, in order...
- The most-recently published article with
IsFeatured = 'Y'
, if any. - The most-recently published article with
IsFavorite = 'Y'
that's not the row from #1 (this avoids duplicates if the most recent featured is also the most recent favorited and instead selects the next favorited row) if any - The three most-recently published articles that are not #1 or #2, if any
Here's what I've come up with so far (cut/pasted/edited here so there may be some typos), but this just feels so 'clunky' to me... like I'm wasting a lot of unnecessary processing and iterations.
WITH mostRecentlyFeatured as (
Select * from (
Select 2 as MAJOR_SORT, A.*
From Articles A
where IsFeatured = 'Y'
order by DatePublished DESC
)
where ROWNUM = 1
),
mostRecentlyFavorited as (
Select * from (
Select 1 as MAJOR_SORT, A.*
From Articles A
minus Select * From mostRecentlyFeatured
where IsFavorite = 'Y'
order by DatePublished DESC
)
where ROWNUM = 1
),
topThreeOthers as (
Select * from (
select 0 as MAJOR_SORT, A.*
from Articles
minus
SELECT * from mostRecentlyFeatured
minus
SELECT * from mostRecentlyFavorited
order by DatePublished desc
)
where ROWNUM <= 3
),
finalRows as (
Select * from mostRecentlyFeatured
union all
Select * from mostRecentlyFavorited
union all
select * from topThreeOthers
)
Select * from finalRows
Order By MAJOR_SORT DESC,
DatePublished DESC;
This isn't the most uncommon of queries so I can't imagine there isn't a better way to do this, but I'm just not yet seeing it. So is there?