在SQL中嵌入'ad hoc'函数

时间:2013-04-16 12:47:54

标签: oracle oracle11g

我想用HH:MM格式格式化部分日期(两个日期之间的差异)。

为此,我汇总了以下逻辑:

LTRIM(TO_CHAR(TRUNC((DATE_DIFFERENCE) * 24),'00')) || ':' || LTRIM(TO_CHAR(MOD(ROUND((DATE_DIFFERENCE)*24*60),60),'00'))

我需要将这个逻辑应用于多个区间,因此使用函数键入DRY是很好的。

有没有办法在SQL语句中嵌入这个逻辑(可能使用Java),而不必求助于创建Oracle函数?

**编辑**

DATE_DIFFERENCE可以是负数且超过24小时。我想包括标志,如果是负数,但也代表小时和分钟的差异,即使DATE_DIFFERENCE是> 24小时。

1 个答案:

答案 0 :(得分:2)

从查询中访问的Java函数比SQL函数要多得多,所以我不完全确定你的意思。当您混合使用SQL和PL / SQL上下文时,不能使用查询声明函数。

您的转化看起来不必要地复杂化;你可以这样做:

substr(numtodsinterval(date_difference, 'DAY'), 12, 5)

numtodsinterval function获取您的日期差异并将其转换为区间数据类型,substr获取涵盖小时和分钟的部分。

它的行为略有不同,因为它会截断而不是围绕分钟:

with tmp as (
    select to_date('2013-04-11 13:17:15', 'YYYY-MM-DD HH24:MI:SS')
        - to_date('2013-04-11 12:57:38', 'YYYY-MM-DD HH24:MI:SS')
        as date_difference
    from dual
    union all
    select to_date('2013-04-11 11:11:35', 'YYYY-MM-DD HH24:MI:SS')
        - to_date('2013-04-10 22:40:45', 'YYYY-MM-DD HH24:MI:SS') 
    from dual
    union all
    select to_date('2013-04-11 00:59:59', 'YYYY-MM-DD HH24:MI:SS')
        - to_date('2013-04-11 00:00:00', 'YYYY-MM-DD HH24:MI:SS') 
    from dual
)
select LTRIM(TO_CHAR(TRUNC((DATE_DIFFERENCE) * 24),'00')) || ':' ||
        LTRIM(TO_CHAR(MOD(ROUND((DATE_DIFFERENCE)*24*60),60),'00')),
    substr(numtodsinterval(date_difference, 'DAY'), 12, 5)
from tmp;

LTRIM(T SUBSTR(NUMTODSINTERV
------- --------------------
00:20   00:19
12:31   12:30
00:00   00:59

这些的完整间隔是:

NUMTODSINTERVAL(DATE_DIFFERENCE,'DAY')
---------------------------------------------------------------------------
+000000000 00:19:37.000000000
+000000000 12:30:50.000000000
+000000000 00:59:59.000000000

很明显,第一个会转到00:20,但会截断为00:19。正如Egor Skriptunoff在评论中指出的那样,你对第三个的计算给出了一个不正确的答案,这就是我现在把它包括在内的原因。

这会在几分钟内完成,但会更长一点:

to_char(round(date '2001-01-01' + date_difference, 'MI'), 'HH24:MI')

我使用date '2001-01-01'的文字中使用的实际日期并不重要,可以是任何一天,例如,您可以使用trunc(sysdate)。它只允许您将差异转换回DATE对象,然后您可以使用内置的round(date) function。为了比较:

with tmp as (...)
select LTRIM(TO_CHAR(TRUNC((DATE_DIFFERENCE) * 24),'00')) || ':' ||
        LTRIM(TO_CHAR(MOD(ROUND((DATE_DIFFERENCE)*24*60),60),'00')),
    substr(numtodsinterval(date_difference, 'DAY'), 12, 5),
    to_char(trunc(date '2001-01-01' + date_difference, 'MI'), 'HH24:MI'),
    to_char(round(date '2001-01-01' + date_difference, 'MI'), 'HH24:MI')
from tmp;

LTRIM(T SUBSTR(NUMTODSINTERV TO_CH TO_CH
------- -------------------- ----- -----
00:20   00:19                00:19 00:20
12:31   12:30                12:30 12:31
00:00   00:59                00:59 01:00

这些实际上都没有给你你想要的东西,一个嵌入式的ad hoc函数,但至少如果逻辑更清晰,那么重用它可能不是那么担心。尽管如此,将它包装在SQL函数中仍然可能不是一个糟糕的选择。