您可以使用to_date() 将字符串转换为名义日期的时间;如果您不提供日期部分,则默认为当月的第一天;使用 CTE(子查询分解)使用您的示例数据创建一个虚拟表 t:
with t (check_out, check_in) as (
select '1015', '1331' from dual
union all select '0642', '0911' from dual
union all select '1002', '1242' from dual
union all select '1434', '1658' from dual
union all select '1821', '2058' from dual
union all select '2221', '0051' from dual
)
select check_out, check_in,
to_char(to_date(check_out, 'HH24MI'), 'YYYY-MM-DD HH24:MI:SS') as d1,
to_char(to_date(check_in, 'HH24MI'), 'YYYY-MM-DD HH24:MI:SS') as d2
from t;
CHEC CHEC D1 D2
---- ---- ------------------- -------------------
1015 1331 2016-08-01 10:15:00 2016-08-01 13:31:00
0642 0911 2016-08-01 06:42:00 2016-08-01 09:11:00
1002 1242 2016-08-01 10:02:00 2016-08-01 12:42:00
1434 1658 2016-08-01 14:34:00 2016-08-01 16:58:00
1821 2058 2016-08-01 18:21:00 2016-08-01 20:58:00
2221 0051 2016-08-01 22:21:00 2016-08-01 00:51:00
然后,您可以从另一个日期中减去其中一个日期。但是,当您的时间超过午夜并因此跨越两天时,如果签入时间表示的时间早于签出时间,您需要将签入时间调整一天 - 这是您上一个示例中的情况。您可以使用 case 表达式来解决这个问题,甚至可以将它们作为字符串进行比较,如果它们总是四个字符(零填充)。所以你可以这样做:
select check_out, check_in,
to_char(to_date(check_out, 'HH24MI'), 'YYYY-MM-DD HH24:MI:SS') as d1,
to_char(to_date(check_in, 'HH24MI') + case when check_in < check_out then 1 else 0 end,
'YYYY-MM-DD HH24:MI:SS') as d2
from t;
CHEC CHEC D1 D2
---- ---- ------------------- -------------------
1015 1331 2016-08-01 10:15:00 2016-08-01 13:31:00
0642 0911 2016-08-01 06:42:00 2016-08-01 09:11:00
1002 1242 2016-08-01 10:02:00 2016-08-01 12:42:00
1434 1658 2016-08-01 14:34:00 2016-08-01 16:58:00
1821 2058 2016-08-01 18:21:00 2016-08-01 20:58:00
2221 0051 2016-08-01 22:21:00 2016-08-02 00:51:00
请注意,最后一行的签到时间现在是第二天。
然后减去,这会给你一天的一小部分作为差异:
select check_out, check_in,
to_date(check_in, 'HH24MI')
+ case when check_in < check_out then 1 else 0 end -- adjust if check_in is next day
- to_date(check_out, 'HH24MI') as diff
from t;
CHEC CHEC DIFF
---- ---- ----------
1015 1331 0.13611
0642 0911 0.10347
1002 1242 0.11111
1434 1658 0.10000
1821 2058 0.10903
2221 0051 0.10417
如果您将该分数添加到另一个名义日期,其时间为午夜,那么您会得到一个日期,其时间部分与退房和入住时间之间的差异相匹配。然后,您可以随意格式化:
with t (check_out, check_in) as (
select '1015', '1331' from dual
union all select '0642', '0911' from dual
union all select '1002', '1242' from dual
union all select '1434', '1658' from dual
union all select '1821', '2058' from dual
union all select '2221', '0051' from dual
)
select check_out, check_in, to_char(trunc(sysdate) + diff, 'HH24:MI') as diff
from (
select check_out, check_in,
to_date(check_in, 'HH24MI')
+ case when check_in < check_out then 1 else 0 end -- adjust if check_in is next day
- to_date(check_out, 'HH24MI') as diff
from t
);
CHEC CHEC DIFF
---- ---- -----
1015 1331 03:16
0642 0911 02:29
1002 1242 02:40
1434 1658 02:24
1821 2058 02:37
2221 0051 02:30
您的真实查询将没有 CTE,但会直接从您的真实表中选择:
select OUTUDT, INUDT, to_char(trunc(sysdate) + diff, 'HH24:MI') as diff
from (
select OUTUDT, INUDT,
to_date(OUTUDT, 'HH24MI') + case when INUDT < OUTUDT then 1 else 0 end
- to_date(INUDT, 'HH24MI') as diff
from your_real_table
)
当然,这是假设退房和入住之间的时间不超过 24 小时。由于您没有正确记录日期,因此您无法知道是否有任何跨度实际上比这更长。
如果您想使用“日期”列(也存储为文本),则可以将其与时间连接并转换为实际日期:
with t (check_out_date, check_out_time, check_in_date, check_in_time) as (
select '24/08/2016', '1015', '24/08/2016', '1331' from dual
union all select '23/08/2016', '0642', '23/08/2016', '0911' from dual
union all select '23/08/2016', '1002', '23/08/2016', '1242' from dual
union all select '23/08/2016', '1434', '23/08/2016', '1658' from dual
union all select '24/08/2016', '1821', '24/08/2016', '2058' from dual
union all select '24/08/2016', '2221', '25/08/2016', '0051' from dual
)
select check_out_date, check_out_time, check_in_date, check_in_time,
to_char(trunc(sysdate) + diff, 'HH24:MI') as diff
from (
select check_out_date, check_out_time, check_in_date, check_in_time,
to_date(check_in_date || check_in_time, 'DD/MM/YYYYHH24MI')
- to_date(check_out_date || check_out_time, 'DD/MM/YYYYHH24MI') as diff
from t
);
CHECK_OUT_ CHEC CHECK_IN_D CHEC DIFF
---------- ---- ---------- ---- -----
24/08/2016 1015 24/08/2016 1331 03:16
23/08/2016 0642 23/08/2016 0911 02:29
23/08/2016 1002 23/08/2016 1242 02:40
23/08/2016 1434 23/08/2016 1658 02:24
24/08/2016 1821 24/08/2016 2058 02:37
24/08/2016 2221 25/08/2016 0051 02:30
如果您正确存储日期,则不需要进行连接和转换 - 当有特定数据类型可用时,将内容存储为字符串不是一个好主意。
如果时间段可能超过一天,您需要更改显示差异的方式。