如何在SQL中ORDER BY String列?

时间:2016-02-18 15:58:51

标签: sql oracle sql-order-by

我有一个带ID和Slot_label列的表。我在Slot Label列中有不同的时隙,我想从最低时间到最高时隙订购它们。时隙在DB中保存为字符串值。以下是运行此查询后我的列的显示方式:

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

我希望我的时段从早上8点到早上8点20分一直到上午11点到凌晨11点20分。我怎么能让这个工作,因为我没有任何其他我可以订购的列?如果有人可以帮忙,请告诉我。

2 个答案:

答案 0 :(得分:1)

如果您的插槽之间没有重叠,那么您可以拉出第一个时间戳并将其用于订购。如果你需要考虑两个端点,那么它显然会变得更复杂,但仍然可行。

在我的示例中,我将提取的时间值保留在输出中,以便您可以看到它:

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

要获得第二个时间戳,以备需要时使用:

    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')

要回复您的评论,是的,有很多选项可供选择。例如,您可以通过提取第一个AM / PM标志然后lpadding第一个时间戳来避免任何dataype更改:

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');

答案 1 :(得分:1)

丑陋我同意但这样的事情有效:

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),':','.'));