圆形日期间隔为10分钟

时间:2010-02-03 14:05:33

标签: sql oracle date rounding

我有一个DATE列,我希望在查询中舍入到下一个较低的10分钟间隔(参见下面的示例)。

我设法通过截断秒数然后减去分钟的最后一位数来实现。

WITH test_data AS (
        SELECT TO_DATE('2010-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2010-01-01 10:05:00', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2010-01-01 10:09:59', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2010-01-01 10:10:00', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2099-01-01 10:00:33', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
)
-- #end of test-data
SELECT
  d, TRUNC(d, 'MI') - MOD(TO_CHAR(d, 'MI'), 10) / (24 * 60)
FROM test_data

结果如下:

  

01.01.2010 10: 00:00 01.01.2010 10: 00:00
  01.01.2010 10: 05:00 01.01.2010 10: 00:00
  01.01.2010 10: 09:59 01.01.2010 10: 00:00
  01.01.2010 10: 10:00 01.01.2010 10: 10:00
  01.01.2099 10: 00:33 01.01.2099 10: 00:00

按预期工作,但是有更好的方法吗?

修改

我对性能很好奇,所以我用500.000行和(不是真的)随机日期进行了以下测试。我将把结果作为注释添加到提供的解决方案中。

DECLARE
  t       TIMESTAMP := SYSTIMESTAMP;
BEGIN
  FOR i IN (
    WITH test_data AS (
      SELECT SYSDATE + ROWNUM / 5000 d FROM dual
      CONNECT BY ROWNUM <= 500000
    )
    SELECT TRUNC(d, 'MI') - MOD(TO_CHAR(d, 'MI'), 10) / (24 * 60)
    FROM test_data
  )
  LOOP
    NULL;
  END LOOP;
  dbms_output.put_line( SYSTIMESTAMP - t );
END;

这种方法花了03.24 s

7 个答案:

答案 0 :(得分:11)

select
  trunc(sysdate, 'mi')
  - numtodsinterval(mod(EXTRACT(minute FROM cast(sysdate as timestamp)), 10), 'minute')
from dual;

甚至

select
  trunc(sysdate, 'mi')
  - mod(EXTRACT(minute FROM cast(sysdate as timestamp)), 10) / (24 * 60)
from dual;

答案 1 :(得分:4)

我一般不喜欢约会 - &gt;字符 - &gt;没有必要时的日期转换。我宁愿使用数字。

select trunc((sysdate - trunc(sysdate))*60*24,-1)/(60*24)+trunc(sysdate) from dual;     

这会从当天提取分钟,将它们截断到10分钟的间隔,然后重新添加它们以使其再次成为日期。当然,您可以将sysdate替换为您想要的任何日期。它比我想要的更多地信任隐式转换,但至少它适用于任何NLS日期格式。

答案 2 :(得分:1)

您可以将返回的值作为字符串,并将左侧的子字符串向上移动到最后一位数字,并将其替换为0。除非你提供某种指标,否则我不会更好地说这些。

答案 3 :(得分:1)

不一定更好,但另一种方法:

WITH test_data AS (
        SELECT TO_DATE('2010-01-01 10:00:00', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2010-01-01 10:05:00', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2010-01-01 10:09:59', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2010-01-01 10:10:00', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
  UNION SELECT TO_DATE('2099-01-01 10:00:33', 'YYYY-MM-DD HH24:MI:SS') d FROM dual
)
-- #end of test-data
SELECT
  d, TRUNC(d) + FLOOR((d-TRUNC(d))*24*6)/(24*6)
FROM test_data

答案 4 :(得分:1)

另一种方法,

select my_date - mod( (my_date-trunc(my_date))*24*60, 10)/24/60
from (
  select sysdate my_date from dual
);

替换它可能会更快,因为它删除了对trunc的调用。

select my_date - mod( (my_date-to_date('1970', 'yyyy'))*24*60, 10)/24/60
from (
  select sysdate my_date from dual
);

答案 5 :(得分:0)

要返回下一个高10分钟的间隔,我使用了以下查询。我希望它有用,因为我不能简单地做一个

trunc(sysdate, 'mi') + mod(EXTRACT(minute FROM cast(sysdate as timestamp)), 10) / (24 * 60)

我这样做了,它对我有用。

&#13;
&#13;
select 
case when mod(EXTRACT(minute FROM cast(sysdate as timestamp)),5) between 1 and 4
      then trunc(sysdate,'mi')+((5*TRUNC(EXTRACT(minute FROM cast(sysdate as timestamp))/5,
0)+5)-EXTRACT(minute FROM cast(sysdate as timestamp)))/1440
      else trunc(sysdate,'mi')
end
from dual
&#13;
&#13;
&#13;

这基于this帖子。

答案 6 :(得分:0)

我认为要解决这个问题,可以更轻松,更快速地进行下一个10秒,1分钟,10分钟等间隔。尝试使用SUBSTR()操作您的时间戳作为字符串,如下所示:

SELECT 
SUBSTR(datetime(d),1,18)||'0' AS Slot10sec, 
SUBSTR(datetime(d),1,17)||'00' AS Slot1min, 
SUBSTR(datetime(d),1,15)||'0:00' AS Slot10min, 
SUBSTR(datetime(d),1,14)||'00:00' AS Slot1h, 
MY_VALUE
FROM MY_TABLE;