2012-03-15 19 views
20

Tengo un servidor con PostgreSQL 8.4 que se reinicia todas las noches a la 01:00 (no pregunte) y necesita obtener una lista de usuarios conectados (es decir, sus marcas de tiempo son u.login > u.logout) :Seleccione las marcas de tiempo de hoy (desde medianoche) solo

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 

Pero comparando u.login > now()-interval '24 hour' también ofrece a los usuarios antes de la última 1:00, lo cual es malo, esp. en las mañanas.

¿Hay alguna manera eficiente de obtener los inicios de sesión desde la última 01:00 sin hacer acrobacias con to_char()?

+1

Hihi, me encanta el "no preguntes" :) – Mattis

Respuesta

30

Inspirado por el comentario de @ Frank Realicé algunas pruebas y adapté mi consulta en consecuencia. Esto debería ser 1) correcto y 2) lo más rápido posible:

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; 

Como no hay marcas de tiempo futuros en su mesa (supongo), no se necesita ninguna cota superior.
date_trunc('day', now()) es casi lo mismo que now()::date (u otras alternativas que se detallan a continuación), solo que devuelve timestamp en lugar de date. Ambos dan como resultado un timestamp de todos modos después de agregar un interval.


Las expresiones siguientes funcionan de forma ligeramente diferente. Producen resultados sutilmente diferentes porque localtimestamp devuelve el tipo de datos timestamp mientras que now() devuelve timestamp with time zone. Pero cuando se envía a date, se convierte a la misma local fecha, y se supone que un timestamp [without time zone] también se encuentra en la zona horaria local. Por lo tanto, cuando se compara con el timestamp with time zone correspondiente, todos resultan en la misma marca de tiempo UTC internamente. Más detalles sobre el manejo de zona horaria en this related question.

Lo mejor de cinco. Probado con PostgreSQL 9.0. Repetido con 9.1.5: resultados consistentes dentro del margen de error del 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 es, obviamente, un poco más rápido que CURRENT_DATE.

+0

Gracias. ¿Un reparto de fecha a marca de tiempo cuesta algo? –

+0

@AlexanderFarber: Por supuesto que sí, incluso si es muy poco. –

+0

@Erwin Brandstetter: Pero 'date_trunc ('day', now())' puede costar aún más, ¿no crees? –

3
where 
    u.login > u.logout 
    and  
    date_trunc('day', u.login) = date_trunc('day', now()) 
    and 
    date_trunc('hour', u.login) >= 1 
9

Una manera fácil de conseguir sellos de tiempo para el día actual desde 1:00 es filtrar con CURRENT_DATE + interval '1 hour'

Así que la consulta debería tener este aspecto:

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; 

la esperanza de que ayuda

3
select * from termin where DATE(dateTimeField) >= CURRENT_DATE AND DATE(dateTimeField) < CURRENT_DATE + INTERVAL '1 DAY' 

Esto funciona para mí: selecciona TODAS las filas con la fecha de hoy.

4
select * from termin where DATE(dateTimeField) = '2015-11-17' 

¡Esto funciona bien para mí!

Cuestiones relacionadas