Выберите только сегодняшние (с полуночи) временные метки
У меня есть сервер с 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()
?
6 ответов
Вдохновленный комментариями @Frank, я провел несколько тестов и соответственно адаптировал свой запрос. Это должно быть 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
,
select * from termin where DATE(dateTimeField) = '2015-11-17'
Это хорошо работает для меня!
select * from termin where DATE(dateTimeField) >= CURRENT_DATE AND DATE(dateTimeField) < CURRENT_DATE + INTERVAL '1 DAY'
Это работает для меня - он выбирает ВСЕ строки с сегодняшней датой.
Простой способ получить только отметки времени для текущего дня с 01:00 - это выполнить фильтрацию с CURRENT_DATE + interval '1 hour'
Итак, ваш запрос должен выглядеть так:
SELECT u.login, u.id, u.first_name
FROM pref_users u
WHERE u.login > u.logout AND
u.login > CURRENT_DATE + interval '1 hour'
ORDER BY u.login;
Надеюсь, это поможет.
where
u.login > u.logout
and
date_trunc('day', u.login) = date_trunc('day', now())
and
date_trunc('hour', u.login) >= 1
Все ответы до сих пор неверны, потому что они дают неправильный ответ между 0,00 и 1,00. Поэтому, если вы запустите запрос в этот период времени, вы не получите никаких результатов. Основываясь на ответе @ErwinBrandstetter, вам нужно следующее:
WHERE u.login > u.logout
AND u.login >= CASE WHEN NOW()::time < '1:00'::time THEN NOW()::date - INTERVAL '23 HOUR' ELSE NOW()::date + INTERVAL '1 HOUR' END;
Я хотел бы обойтись без условного, но не нашел способа.
Редактировать: @ErwinBrandstetter сделал это без условного выражения, оставив это здесь для полноты картины.