Круглая дата к интервалу 10 минут

У меня есть a 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.

14
задан Peter Lang 17 March 2010 в 11:27
поделиться

5 ответов

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;
11
ответ дан 1 December 2019 в 13:33
поделиться

Я вообще ненавижу преобразовывать дату -> символ -> дату, когда в этом нет необходимости. Я бы предпочел использовать числа.

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

Это извлекает минуты из текущего дня, обрезает их до 10-минутного интервала, а затем добавляет их обратно, чтобы снова сделать дату. Конечно, вы можете заменить sysdate любой датой, какой захотите. Он доверяет неявным преобразованиям намного больше, чем я хочу, но, по крайней мере, он будет работать для любого формата даты NLS.

4
ответ дан 1 December 2019 в 13:33
поделиться

Вы можете взять возвращаемое значение как строку и подстроку с левой стороны до последней цифры минуты и заменить ее на 0 . Я бы не сказал, что это лучше, если вы не предоставите какую-то метрику.

1
ответ дан 1 December 2019 в 13:33
поделиться

Не обязательно лучше, но другой метод:

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
1
ответ дан 1 December 2019 в 13:33
поделиться

Другой метод,

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
);
1
ответ дан 1 December 2019 в 13:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: