2010-02-03 83 views
12

我有一个DATE列,我想在查询中将其舍入到下一个较低的10分钟时间间隔(请参见下面的示例)。圆整日期到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:九点59     01.01.2010 10:00:00
01.01.2010 10:10:00     01.01.2010 10:10:00
2099年1月1日10:00 :33     2099年1月1日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

+0

约'SELECT CASE什么时,TO_CHAR(date_col的, 'MI')在0至10,则TO_DATE(TO_CHAR(date_col的, 'YYYY') ||' - '|| TO_CHAR(date_col,'MM')||' - '|| TO_CHAR(date_col,'DD')||''|| TO_CHAR(date_col,'HH')||':00' ,'YYYY-MM-DD HH:MI') END'? – 2010-02-03 18:29:52

+0

@OMG小马:对不起,但是当'0 <= MI <= 10'时返回整小时,否则返回NULL。 – 2010-02-04 07:04:17

+0

不想混淆其余的时间 – 2010-02-04 15:38:30

回答

10
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; 
+0

@Tom:欢迎来到StackOverflow!这两种方法似乎都有效,第一个方法是'04.18 s',第二个方法只是'03.33 s'!你的第二个查询的性能几乎与我原来的查询相同,但是避免了'TO_CHAR',所以我会接受你的答案。谢谢! – 2010-04-16 11:16:50

1

您可以将返回的值作为字符串并将其左侧的子字符串截至最后一分钟数字,并将其替换为0。除非你提供某种度量,否则我不会更确切地说这更好。

+1

SELECT SYSDATE,TO_DATE(SUBSTR(TO_CHAR(SYSDATE, 'YYYYMMDD HH24MI'),1,12)|| '0', 'YYYYMMDD HH24MI')FROM DUAL 他在SQL代码表示,也他关于表演,我不确定哪个会更好,但你的看起来会更简单。 – Craig 2010-02-03 14:23:03

+0

在已编辑的问题中查看性能测试。这种方法花了“04.32秒”。 – 2010-02-03 16:49:12

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 
+0

在已编辑的问题中查看性能测试。这种方法花了04.16秒。 – 2010-02-03 16:49:38

+0

接受,因为它很短,很可读。谢谢!虽然会坚持我的解决方案,因为它需要更少的时间。 – 2010-02-10 10:12:03

+0

@Tony Andrews:接受Tom的回答而不是你的回答,因为我觉得它更直观,性能更好。希望你不介意... – 2010-04-16 11:18:22

3

我通常讨厌做日期 - >字符 - >日期的转换时,它不是必需的。我宁愿使用数字。

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

这从当天提取分钟,截断他们下到10分钟的间隔,然后将其添加回让它再次约会。当然,你可以用任何你想要的日期替换sysdate。它比我想要的更信任隐式转换,但至少它可以用于任何NLS日期格式。

+0

在已编辑的问题中查看性能测试。这种方法花了04.39秒。 – 2010-02-03 16:50:14

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 
); 
+0

+1:另一种有用的方法。在我的测试中使用了'04.60 s',我猜'mod'使得它比我的方法慢。 – 2010-03-17 11:30:18

+0

我发布了一个替代方案,它删除了对trunc的调用。看看你的测试是否有任何不同,会很有趣。 – 2010-03-24 12:29:31

+0

@ar:对不起,没有得到有关您的更新通知。您的更新查询确实性能更好:'04.22 s' – 2010-04-16 11:04:14

0

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

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

我做这个和它的工作对我来说这将是有益的。

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

这是基于this岗位。

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; 
相关问题