Выберите только сегодняшние (с полуночи) временные метки - PullRequest
31 голосов
/ 15 марта 2012

У меня есть сервер с PostgreSQL 8.4, который перезагружается каждую ночь в 01:00 (не спрашивайте), и мне нужно получить список подключенных пользователей (т.е. их временные метки u.login > u.logout):

SELECT u.login, u.id, u.first_name
FROM pref_users u
WHERE u.login > u.logout and 
      u.login > now() - interval '24 hour'
ORDER BY u.login;

           login            |           id   | first_name
----------------------------+----------------+-------------
 2012-03-14 09:27:33.41645  | OK171511218029 | Alice
 2012-03-14 09:51:46.387244 | OK448670789462 | Bob
 2012-03-14 09:52:36.738625 | OK5088512947   | Sergej

Но сравнение u.login > now()-interval '24 hour' также доставляет пользователей до последнего 01:00, что плохо, особенно.по утрам.

Есть ли какой-нибудь эффективный способ получить логины со времени последнего 01: 00 без выполнения строковой акробатики с to_char()?

Ответы [ 5 ]

44 голосов
/ 15 марта 2012

Вдохновленный комментарием @ Фрэнка, я провел несколько тестов и соответственно адаптировал свой запрос. Это должно быть 1) правильно и 2) максимально быстро:

SELECT u.login, u.id, u.first_name
FROM   pref_users u
WHERE  u.login > u.logout
AND    u.login >= now()::date + interval '1h'
ORDER  BY u.login;

Поскольку в вашей таблице нет будущих временных отметок (я полагаю), вам не нужна верхняя граница.
date_trunc('day', now()) - почти то же самое, что и now()::date (или некоторые другие альтернативы, подробно описанные ниже), только то, что он возвращает timestamp вместо date. Оба результата в любом случае timestamp после добавления interval.


Ниже выражения работают немного по-другому. Они дают немного разные результаты, потому что localtimestamp возвращает тип данных timestamp, а now() возвращает timestamp with time zone. Но при приведении к date любой из них преобразуется в ту же локальную дату, и timestamp [without time zone] также предполагается в местном часовом поясе. Таким образом, по сравнению с соответствующим timestamp with time zone все они приводят к одной и той же временной метке UTC внутри. Подробнее об обработке часовых поясов в этом связанном вопросе .

Лучший из пяти. Протестировано с PostgreSQL 9.0. Повторяется с 9.1.5: согласованные результаты с погрешностью 1%.

SELECT localtimestamp::date     + interval '1h'  -- Total runtime: 351.688 ms
     , current_date             + interval '1h'  -- Total runtime: 338.975 ms
     , date_trunc('day', now()) + interval '1h'  -- Total runtime: 333.032 ms
     , now()::date              + interval '1h'  -- Total runtime: 278.269 ms
FROM   generate_series (1, 100000)

now()::date явно немного быстрее, чем CURRENT_DATE.

12 голосов
/ 15 марта 2012

Простой способ получить только отметки времени для текущего дня с 01:00 - отфильтровать с помощью CURRENT_DATE + interval '1 hour'

Таким образом, ваш запрос должен выглядеть так:это помогает.

8 голосов
/ 04 июля 2015
select * from termin where DATE(dateTimeField) >= CURRENT_DATE AND DATE(dateTimeField) < CURRENT_DATE + INTERVAL '1 DAY'

Это работает для меня - он выбирает ВСЕ строки с текущей датой.

7 голосов
/ 17 ноября 2015
select * from termin where DATE(dateTimeField) = '2015-11-17'

Это хорошо работает для меня!

3 голосов
/ 15 марта 2012
where 
    u.login > u.logout 
    and     
    date_trunc('day', u.login) = date_trunc('day', now()) 
    and 
    date_trunc('hour', u.login) >= 1
...