我在oracle 10数据库中有一个Varchar字段,人们可以手动输入工作时间。我需要开发模糊逻辑,将信息转换为小时数,以便在函数中求和。
9 HOURS
6.0 Hrs
4.5 hours
14 HOURS 30 MIN
17 HOURS 15 MINUTES
10.75 Days
我正在使用以下代码来创建一个等式,但我无法将其转换为数字。有人曾经这样做过吗?
select
replace(
replace (
replace(
translate(upper('3 Day 3.2 Hours 6 Min '),'DHMAFBCEFGIJKLNOPQRSTUVWXYZ','DHM')
, 'H', '*1+'),
'M', '/60'),
'D','*24+')
from dual
答案 0 :(得分:2)
这是执行此操作的“脏”方法(不更改当前设置中的任何内容)。我同意其他人认为这是一个非常糟糕的模型,最好改变它。
解决方案的复杂程度取决于您愿意在输入中允许的灵活性(自由文本)。我假设数字可以是任何格式3 3.5 3.0 12. 0.3 .33(但没有符号,+或 - );一个数字后面可以跟零个或多个空格;任何时间成分(限于天,小时和分钟)可能存在或不存在;并且组件由跟随它们的单词的第一个字母“标记”:D,H或M.(因此,这也是语言相关的,如果您允许其他语言中的自由文本,则系统的另一个弱点。)D, H或M可以是大写或小写,可以跟随任何其他字母(DAY,Days,dy,dd等)
with
inputs ( str ) as (
select '9 HOURS' from dual union all
select '6.0 Hrs' from dual union all
select '4.5 hours' from dual union all
select '14 HOURS 30 MIN' from dual union all
select '17 HOURS 15 MINUTES' from dual union all
select '10.75 Days' from dual union all
select '.5days 30m' from dual union all
select '30. h' from dual union all
select '2 days 1 hour 30 min' from dual
)
-- End of simulated inputs (for testing only, not part of the solution).
-- Use your actual table and column names in the SQL query below.
select str,
nvl(to_number(regexp_substr(str, '(\d+(\.\d*)?|\.\d+)\s*D', 1, 1, 'i', 1)), 0)*24 +
nvl(to_number(regexp_substr(str, '(\d+(\.\d*)?|\.\d+)\s*H', 1, 1, 'i', 1)), 0) +
nvl(to_number(regexp_substr(str, '(\d+(\.\d*)?|\.\d+)\s*M', 1, 1, 'i', 1)), 0)/60
as hours_worked
from inputs;
STR HOURS_WORKED
-------------------- ------------
9 HOURS 9.00
6.0 Hrs 6.00
4.5 hours 4.50
14 HOURS 30 MIN 14.50
17 HOURS 15 MINUTES 17.25
10.75 Days 258.00
.5days 30m 12.50
30. h 30.00
2 days 1 hour 30 min 49.50
答案 1 :(得分:0)
我的建议是添加新列并逐步更新。
ALTER TABLE WORKING_TIME_TABLE ADD (WORKING_INTERVAL INTERVAL DAY(3) TO SECOND(0));
UPDATE WORKING_TIME_TABLE
SET WORKING_INTERVAL = REGEXP_REPLACE(WORKING_TIME, 'HOURS$', NULL, 1,1,'i') * INTERVAL '1' HOUR
WHERE WORKING_INTERVAL IS NULL
AND (REGEXP_LIKE(WORKING_TIME, '^\d+ HOURS$', 'i')
OR REGEXP_LIKE(WORKING_TIME, '^\d+\.\d+ HOURS$', 'i')) ;
UPDATE WORKING_TIME_TABLE
SET WORKING_INTERVAL = REGEXP_REPLACE(WORKING_TIME, 'Hrs$', NULL, 1,1,'i') * INTERVAL '1' HOUR
WHERE WORKING_INTERVAL IS NULL
AND (REGEXP_LIKE(WORKING_TIME, '^\d+ Hrs$', 'i')
OR REGEXP_LIKE(WORKING_TIME, '^\d+\.\d+ Hrs$', 'i') );
UPDATE WORKING_TIME_TABLE
SET WORKING_INTERVAL = REGEXP_SUBSTR(WORKING_TIME, '^\d+') * INTERVAL '1' HOUR + REGEXP_SUBSTR(WORKING_TIME, '\d+', 1,2) * INTERVAL '1' MINUTE
WHERE WORKING_INTERVAL IS NULL
AND REGEXP_LIKE(WORKING_TIME, '^\d+ HOURS \d+ MIN(UTES)?$', 'i');
UPDATE WORKING_TIME_TABLE
SET WORKING_INTERVAL = REGEXP_SUBSTR(WORKING_TIME, '^\d+\.\d+') * INTERVAL '1' DAY
WHERE WORKING_INTERVAL IS NULL
AND REGEXP_LIKE(WORKING_TIME, '^\d+\.\d+ Days$', 'i');
etc.
当然,在您成功更新所有WORKING_INT
后,请更改您的应用程序以强制执行适当的间隔值!