【问题标题】:Convert VARCHAR2 into Number将 VARCHAR2 转换为数字
【发布时间】:2013-05-29 11:32:39
【问题描述】:

我有一个表,其中有一列名为 duration。它的数据类型是VARCHAR2

我想对duration 列求和。

00:56:30
02:08:40
01:01:00

总计=>04:05:10

如何使用 ANSI SQL 或 Oracle SQL 做到这一点?

【问题讨论】:

  • 如果总数超过99:59:59怎么办?

标签: sql oracle


【解决方案1】:

你可以使用SUBSTR分隔小时、分钟和秒,然后SUM向上,最后使用NUMTODSINTERVAL函数将其转换为INTERVAL类型。

SELECT NUMTODSINTERVAL (SUM (total_secs), 'second')
  FROM (SELECT   SUBSTR (duration, 1, 2) * 3600
               + SUBSTR (duration, 4, 2) * 60
               + SUBSTR (duration, 7, 2) total_secs
          FROM user_tab);

【讨论】:

  • 不错的解决方案。虽然我认为除非输入总是格式正确,否则使用正则表达式会更安全。
  • 感谢大家对我的帮助 :) Function Numtodsinterval for Oracle 真的很有用。
【解决方案2】:

我认为最好先将您的字符串转换为INTERVAL,然后将这些值添加为日期值。大致如下:

select   to_dsinterval('0 00:56:30') 
       + to_dsinterval('0 02:08:40') 
       + to_dsinterval('0 01:01:00') myinterval from dual;

MYINTERVAL
-------------------
+000000000 04:06:10

【讨论】:

  • 不幸的是,我发现 sum 聚合函数不适用于 INTERVAL 数据类型,因此您应该使用 PL/SQL 代码遍历所有记录以聚合 INTERVAL 值,或编写您自己的聚合函数,如 Oracle OTN 论坛上的 herehere(问 Tom)所述。
【解决方案3】:

对于甲骨文

select 
numtodsinterval(sum(
  to_char(to_date(duration, 'HH24:MI:SS'), 'HH24') * 3600 + 
  to_char(to_date(duration, 'HH24:MI:SS'), 'MI') * 60+
  to_char(to_date(duration, 'HH24:MI:SS'), 'SS')
  ), 'second'
) as SUMTOTAL
from tbl;

第二次查询

select 
numtodsinterval(hr+mn+sc, 'second')
from 
(
select 
sum(to_char(to_date(duration, 'HH24:MI:SS'), 'HH24') * 3600) as hr,
sum(to_char(to_date(duration, 'HH24:MI:SS'), 'MI') * 60) as mn,
sum(to_char(to_date(duration, 'HH24:MI:SS'), 'SS'))as sc
from tbl) tmp

FIDDLE

在 SQL FIDDLE 中返回对象的示例。在你的机器上试试

对于 MYSQL

试试这个

select sec_to_time(sum(time_to_sec(duration))) from tbl

FIDDLE

| SEC_TO_TIME(SUM(TIME_TO_SEC(DURATION))) |
-------------------------------------------
|          January, 01 1970 04:06:10+0000 |

【讨论】:

  • 虽然 OP 包含 oracle 标签 ;-)
  • 我回答问题后OP更改了标签.......已更改答案。
  • 问题有always been tagged Oracle...现在你已经更新了答案,这并不重要。
  • 感谢您的回答;请务必注意一些小细节,例如某人将来使用的语言/DBMS。
【解决方案4】:

为了好玩,我编写了自己的聚合函数,可以对区间求和(参见@Yasir 的帖子)。这可以修改为在内部进行 varchar 到间隔的转换,但我现在会尽可能简单)。

首先创建对象类型规范:

CREATE OR REPLACE TYPE SumInterval 
AS OBJECT (

runningSum INTERVAL DAY(9) TO SECOND(9),

STATIC FUNCTION ODCIAggregateInitialize
  ( actx IN OUT SumInterval
  ) RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateIterate
  ( self  IN OUT SumInterval,
    val   IN       DSINTERVAL_UNCONSTRAINED
  ) RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateTerminate
  ( self             IN   SumInterval,
    returnValue  OUT DSINTERVAL_UNCONSTRAINED,
    flags           IN   NUMBER
  ) RETURN NUMBER,

MEMBER FUNCTION ODCIAggregateMerge
  (self  IN OUT SumInterval,
   ctx2 IN      SumInterval
  ) RETURN NUMBER

);

还有物体主体:

CREATE OR REPLACE TYPE BODY SumInterval AS

STATIC FUNCTION ODCIAggregateInitialize
  ( actx IN OUT SumInterval
  ) RETURN NUMBER IS 
  BEGIN
    IF actx IS NULL THEN
      actx := SumInterval (INTERVAL '0 0:0:0.0' DAY TO SECOND);
    ELSE
      actx.runningSum := INTERVAL '0 0:0:0.0' DAY TO SECOND;
    END IF;
    RETURN ODCIConst.Success;
  END;

MEMBER FUNCTION ODCIAggregateIterate
  ( self  IN OUT SumInterval,
    val   IN     DSINTERVAL_UNCONSTRAINED
  ) RETURN NUMBER IS
  BEGIN
    self.runningSum := self.runningSum + val;
    RETURN ODCIConst.Success;
  END;

MEMBER FUNCTION ODCIAggregateTerminate
  ( self        IN  SumInterval,
    ReturnValue OUT DSINTERVAL_UNCONSTRAINED,
    flags       IN  NUMBER
  ) RETURN NUMBER IS
  BEGIN
    returnValue := self.runningSum;
    RETURN ODCIConst.Success;
  END;

MEMBER FUNCTION ODCIAggregateMerge
  (self IN OUT SumInterval,
   ctx2 IN     SumInterval
  ) RETURN NUMBER IS
  BEGIN
    self.runningSum := self.runningSum + ctx2.runningSum;
    RETURN ODCIConst.Success;
  END;

END;

最后是使用这个对象类型的函数:

CREATE OR REPLACE FUNCTION sum_interval( x DSINTERVAL_UNCONSTRAINED) 
RETURN DSINTERVAL_UNCONSTRAINED  PARALLEL_ENABLE
AGGREGATE USING SumInterval;

现在您可以按如下方式使用新的“sum_interval”:

with x as (
select to_dsinterval('0 00:56:30') as duration from dual
union
select to_dsinterval('0 02:08:40') as duration from dual
union
select to_dsinterval('0 01:01:00') as duration from dual
)
select sum_interval(duration)
from x;

输出:

SUM_INTERVAL(DURATION)
+00 04:06:10.000000

它的另一个好处是它可以像典型的聚合函数一样使用。例如,我们可以作为组函数使用:

with x as (
select 'FL' as state, to_dsinterval('0 00:56:30') as duration from dual
union
select 'FL' as state, to_dsinterval('0 02:08:40') as duration from dual
union
select 'GA' as state, to_dsinterval('0 01:01:00') as duration from dual
)
select state, sum_interval(duration)
from x
group by state;

输出:

STATE   SUM_INTERVAL(DURATION)
FL  +00 03:05:10.000000
GA  +00 01:01:00.000000

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-13
    • 1970-01-01
    • 1970-01-01
    • 2021-10-03
    • 2011-02-11
    • 1970-01-01
    • 2021-03-18
    • 1970-01-01
    相关资源
    最近更新 更多