简体   繁体   中英

How to ORDER BY String column in SQL?

I have a table with ID and Slot_label columns. I have different time slots in Slot Label column and I would like to order them from lowest time to highest time slot. Time slots are saved as a string values in DB. Here is how my columns look after I run this query:

Select *
From EVENT_SLOTS
Order By Slot_Label



ID            TIME SLOTS
1778        10:00  AM - 10:20  AM
1776        10:20  AM - 10:40  AM
1779        10:40  AM - 11:00  AM
1780        11:00  AM - 11:20  AM
1781        8:00  AM - 8:20  AM
1777        8:20  AM - 8:40  AM
1782        8:40  AM - 9:00  AM
1775        9:00  AM - 9:20  AM
1774        9:20  AM - 9:40  AM
1783        9:40  AM - 10:00  AM

I want my time slots to go from 8:00 am - 8:20 am all the way up to 11:00 am - 11:20 am in order. How I can get this to work since I do not have any other columns that i can order by? If any one can help please let me know.

If there is no overlap between your slots, then you can pull the first timestamp out and use that for ordering. If you need to consider both endpoints then it obviously gets more complex, but is still doable.

In my example I've left the extracted time value in the output so you can see it:

with dat as (
SELECT 1778 ID,        '10:00  AM - 10:20  AM' slot_label from dual union all
SELECT 1776,        '10:20  AM - 10:40  AM' from dual union all
SELECT 1779,        '10:40  AM - 11:00  AM' from dual union all
SELECT 1780,        '11:00  AM - 11:20  AM' from dual union all
SELECT 1781,        '8:00  AM - 8:20  AM' from dual union all
SELECT 1777,        '8:20  AM - 8:40  AM' from dual union all
SELECT 1782,        '8:40  AM - 9:00  AM' from dual union all
SELECT 1775,        '9:00  AM - 9:20  AM' from dual union all
SELECT 1774,        '9:20  AM - 9:40  AM' from dual union all
SELECT 1783,        '9:40  AM - 10:00  AM' from dual )
select id, slot_label, substr(slot_label, 1, instr(slot_label,'M')) first_time 
from dat 
order by to_Date(substr(slot_label, 1, instr(slot_label,'M')),'HH:MI AM');


ID,    SLOT_LABEL,             FIRST_TIME
1781,  8:00  AM - 8:20  AM,     8:00  AM
1777,  8:20  AM - 8:40  AM,     8:20  AM
1782,  8:40  AM - 9:00  AM,     8:40  AM
1775,  9:00  AM - 9:20  AM,     9:00  AM
1774,  9:20  AM - 9:40  AM,     9:20  AM
1783,  9:40  AM - 10:00  AM,    9:40  AM
1778,  10:00  AM - 10:20  AM,  10:00  AM
1776,  10:20  AM - 10:40  AM,  10:20  AM
1779,  10:40  AM - 11:00  AM,  10:40  AM
1780,  11:00  AM - 11:20  AM,  11:00  AM

To get the second timestamp in case you need it use:

    with dat as (
SELECT 1778 ID,        '10:00  AM - 10:20  AM' slot_label from dual union all
SELECT 1776,        '10:20  AM - 10:40  AM' from dual union all
SELECT 1779,        '10:40  AM - 11:00  AM' from dual union all
SELECT 1780,        '11:00  AM - 11:20  AM' from dual union all
SELECT 1781,        '8:00  AM - 8:20  AM' from dual union all
SELECT 1777,        '8:20  AM - 8:40  AM' from dual union all
SELECT 1782,        '8:40  AM - 9:00  AM' from dual union all
SELECT 1775,        '9:00  AM - 9:20  AM' from dual union all
SELECT 1774,        '9:20  AM - 9:40  AM' from dual union all
SELECT 1783,        '9:40  AM - 10:00  AM' from dual )
select id
     , slot_label
     , substr(slot_label, 1, instr(slot_label,'M')) first_time 
     , substr(slot_label, instr(slot_label,'-')+2) last_time 
from dat 
order by to_Date(substr(slot_label, 1, instr(slot_label,'M')),'HH:MI AM')
        ,to_Date(substr(slot_label, instr(slot_label,'-')+2),'HH:MI AM')

To respond to your comment, yes there are lots of options available. For example you can avoid any dataype changes by extracting out the first AM/PM flag and then lpadding the first timestamp:

select id
     , slot_label
     , substr(slot_label, instr(slot_label,'M')-1,2) First_ampm 
     , lpad(substr(slot_label, 1, instr(slot_label,' ')-1),10,'0') first_time 
from dat 
order by substr(slot_label, instr(slot_label,'M')-1,2)
       , lpad(substr(slot_label, 1, instr(slot_label,' ')-1),10,'0');

Ugly i agree but something like this works :

with myTestCase as
(
select '8:00  PM - 8:20  PM' data from dual union all
select '10:00  AM - 10:20  AM' data from dual union all
select '10:30  AM - 10:20  AM' data from dual union all
select '8:00  AM - 8:20  AM' from dual
)
select t.*
  from myTestCase t
 order by case when instr(substr(t.data,1,9),'PM') != 0 then 12 else 0 end +
          to_number(replace(substr(t.data, 1, instr(t.data,' ') - 1),':','.'));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM