【问题标题】:Oracle sqlSubtract between two dateOracle sqlSubtract 两个日期之间
【发布时间】:2012-04-05 07:22:44
【问题描述】:

我需要帮助来编写查询执行以下操作: 在两列(开始日期和结束日期)之间减去,请注意列的类型是 char 而不是 date,这是确切的格式:10 -MAR-12 11.11.40.288389000 AM),然后得到结果的平均值。

【问题讨论】:

  • 首先,标准免责声明。在VARCHAR2 列中存储日期和时间戳是一个可怕的想法。最终,有人会以不同的格式存储日期,而您的查询将会爆炸。其次,您希望结果是什么数据类型和单位?你想要INTERVAL DAY TO SECOND 吗?你想要日期之间的天数吗?秒数?纳秒数?
  • ..我知道这很可怕,但这是我在 DB 中发现的(它与我的工作有关,我不是设计这个 DB 的人)..谢谢你们俩,我会回来尝试明天。

标签: oracle


【解决方案1】:

我认为这是家庭作业,所以一些提示...

首先不要将日期存储为varchar,它会给你和优化器带来各种各样的问题。

其次,Oracle 的date 数据类型只能存储到秒精度,并且您的字符串只有几分之一秒,因此您正在查看timestamp 而不是date。您可以使用to_timestamp() 函数将您的字符串转换为时间戳,并传递一个合适的format mask。哦,好吧,我感觉很慷慨:

select to_timestamp(start_date, 'DD-Mon-RR HH.MI.SS.FF9 AM') from your_table;

第三,减去两个时间戳会给你一个interval 数据类型,你需要从中提取你想要的可读格式的信息。在此站点或其他地方搜索时间戳减法,但我会以 this recent one 为例。

平均值有点棘手,因此您可能需要将间隔转换为数字;再次搜索之前的问题,如this one。间隔的大小、您实际关心的精度以及您希望输出格式化的方式等都会对您要采用的方法产生一些影响。


如果您需要一个近似结果,那么@Joachim Isaksson 的答案会给您 - 因为四舍五入而得出的“近似值”;例如,小于一秒的持续时间将显示为零。将时间戳转换为日期也可以看到相同的效果,这也会丢失小数秒:

select 24*60*60*avg(
    cast(to_timestamp(step_ending_time, 'DD-Mon-RR HH.MI.SS.FF9 AM') as date)
        - cast(to_timestamp(step_starting_time, 'DD-Mon-RR HH.MI.SS.FF9 AM') as date)
    ) as avg_duration
from process_audit;

可以通过提取时间戳的各个组成部分来找到更准确的答案,就像我之前链接的一个问题一样。如果你知道你的持续时间总是少于一个小时,你可能不需要它们,但是如果你需要一个以上(即如果持续时间可能超过一分钟),那么使用中间公用表表达式可以简化事情位:

with cte as (
    select to_timestamp(step_ending_time, 'DD-Mon-RR HH.MI.SS.FF9 AM')
        - to_timestamp(step_starting_time, 'DD-Mon-RR HH.MI.SS.FF9 AM') as duration
    from process_audit
)
select avg(extract(second from duration)
    + extract(minute from duration) * 60
    + extract(hour from duration) * 60 * 60
    + extract(day from duration) * 60 * 60 * 24) as avg_duration
from cte;

有两个样本行,一个间隔正好是 1 秒,一个间隔正好是 1.5 秒,这给出了结果 1.25

【讨论】:

  • 不,这不是家庭作业。它与我的工作有关,我想为我们系统中的服务准备一个性能报告,因此我需要计算步骤的开始日期和结束日期之间的间隔的平均时间。我会回来向你展示我的尝试。谢谢
【解决方案2】:

关于在 VARCHAR 中存储时间的评论放在一边; Oracle 的to_date 进行救援;这应该可以让您显示两次之间的平均秒数。由于您对精度的细节有点低,我没有在意“亚秒”;

SELECT 24*3600*AVG(
  to_date(enddate,   'DD-Mon-YY HH.Mi.SS.????????? AM') -
  to_date(startdate, 'DD-Mon-YY HH.Mi.SS.????????? AM')) avg_seconds
FROM TableA;

演示here.

【讨论】:

  • 非常感谢,它似乎正是我需要的,迫不及待地想明天测试它,我会回来反馈。
  • 亲爱的,我试试你的代码,但是字符串格式出现错误,你能检查一下有什么问题吗? ![错误][1] [1]: i.stack.imgur.com/mnE4C.png
  • @Rona 您的秒数精度为 9 位(11.11.40.288389000),但在您的查询中,您只输入了 3 个问号。您需要输入所有 9 个问号,因为 to_date 需要完全匹配。
  • @Rona - 您还使用MM 而不是Mon 作为月份部分。还要注意舍入的影响 - 例如,任何小于一秒的持续时间都将显示为零。如果您的持续时间范围很广,这可能没问题,但如果它们都是亚秒级,那么您将不会得到非常有用的结果。
猜你喜欢
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 2021-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多