我有一张桌子,有退房和入住时间,但这些时间是文本格式。我希望这两次有所不同。
示例:
Check out Check in
1015 1331
0642 0911
1002 1242
1434 1658
1821 2058
2221 0051
运行此查询时出错:
ORA-02000:缺少)关键字
02000. 00000 - “缺少%s关键字”
答案 0 :(得分:0)
您可以使用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
如果您正确存储日期,则不需要进行连接和转换 - 当有特定数据类型可用时,将内容存储为字符串并不是一个好主意。
如果期限可能超过一天,您需要更改显示差异的方式。