如何按 SQL 中的字符串列进行排序?

How to ORDER BY String column in SQL?

我有一个带有 ID 和 Slot_label 列的 table。我在 Slot Label 列中有不同的时间段,我想从最低时间到最高时间段对它们进行排序。时隙在数据库中保存为字符串值。以下是我的专栏如何处理 运行 这个查询:

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:00 上午 - 8:20 一直到 11:00 上午 - 11:20 上午。由于我没有任何其他可以订购的列,我如何才能让它发挥作用?如果有人可以帮助,请告诉我。

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

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

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 标志然后填充第一个时间戳来避免任何数据类型更改:

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

丑陋的我同意,但像这样的东西有效:

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