Question

I'm working on putting together an Oracle SQL statement that can do some advanced sorting that I need. So far here is my statement:

SELECT TIME, PLACE
FROM TABLENAME
ORDER BY MIN(year) OVER (PARTITION BY PLACE), PLACE, TIME;

I put this together after getting help with my other question (Oracle SQL Grouping/Ordering). Now I need to throw seasons into the mix, however, they are not numbered numerically in the existing database.

So let's say I have the following data

TIME   | PLACE
198410 | somewhere
198320 | work
198431 | somewhere
198232 | home
198322 | work
198211 | home
198422 | somewhere

The first four digits of the TIME column are the year and the next digit is the season (where 2 = Summer, 3 = Fall, 1 = Winter), and the last digit should be ignored (for comparison reasons).

The above query will produce the following result (groups the places together and orders them based on the time (numerically)):

TIME   | PLACE
198410 | somewhere
198422 | somewhere
198431 | somewhere
198320 | work
198322 | work
198211 | home
198232 | home

However, I need a query that will take the weirdly coded seasons (Summer = 2, Fall = 3, Winter = 1) into account and produce the following chronologically sorted result:

TIME   | PLACE
198422 | somewhere
198431 | somewhere
198410 | somewhere
198320 | work
198322 | work
198232 | home
198211 | home

I didn't make up this standard but unfortunately I have to work with it. Any help on figuring this out is greatly appreciated.

Was it helpful?

Solution

You can use a decode or a case statement to 'fix' the season ordering on the fly. (You don't have 'spring'?)

select time, place
from tablename
order by max(substr(time, 1, 4) || case substr(time, 5, 1)
      when '2' then 1 when '3' then 2 when '1' then 3 end)
    over (partition by place) desc,
  place,
  substr(time, 1, 4) desc,
  case substr(time, 5, 1) when '2' then 1 when '3' then 2 when '1' then 3 end;

You seem to be ordering the year in descending order which your code sample didn't do, but this matches the output you wanted:

TIME   PLACE   
------ ---------
198422 somewhere 
198431 somewhere 
198410 somewhere 
198320 work      
198322 work      
198232 home      
198211 home      

SQL Fiddle.

As you're repeating the year extraction and adjusted season calculation, you might prefer to handle those once in a subquery:

select time, place
from (
  select time, place, substr(time, 1, 4) as year,
    case substr(time, 5, 1) when '2' then 1 when '3' then 2 when '1' then 3 end
      as season
  from tablename
)
order by max(year || season) over (partition by place) desc,
  place, year desc, season;

Another SQL Fiddle.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top