web-dev-qa-db-fra.com

Sélectionnez les horodatages d'aujourd'hui (depuis minuit) uniquement

J'ai un serveur avec PostgreSQL 8.4 qui redémarre tous les soirs à 01h00 (ne demandez pas) et j'ai besoin d'obtenir une liste des utilisateurs connectés (c'est-à-dire que leurs horodatages sont 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

Mais la comparaison de u.login > now()-interval '24 hour' fournit également les utilisateurs avant le dernier 01:00, ce qui est mauvais, en particulier. les matins.

Existe-t-il un moyen efficace de obtenir les connexions depuis le dernier 01: sans faire d'acrobatie avec to_char()?

34
Alexander Farber

Inspiré par le commentaire de @ Frank, j'ai effectué quelques tests et adapté ma requête en conséquence. Cela devrait être 1) correct et 2) le plus rapidement possible:

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;

Comme il n'y a pas d'horodatage futur dans votre table (je suppose), vous n'avez pas besoin de limite supérieure.
date_trunc('day', now()) est presque la même chose que now()::date (ou quelques autres alternatives détaillées ci-dessous), seulement qu'elle renvoie timestamp au lieu d'un date. Les deux résultent en un timestamp de toute façon après avoir ajouté un interval.


Les expressions ci-dessous fonctionnent légèrement différemment. Ils donnent des résultats subtilement différents parce que localtimestamp renvoie le type de données timestamp tandis que now() renvoie timestamp with time zone . Mais lorsqu'il est converti en date, l'un ou l'autre est converti à la même date locale , et un timestamp [without time zone] Est présumé être dans le fuseau horaire local aussi. Ainsi, par rapport au timestamp with time zone Correspondant, ils entraînent tous le même horodatage UTC en interne. Plus de détails sur la gestion des fuseaux horaires dans cette question connexe .

Le meilleur des cinq. Testé avec PostgreSQL 9.0. Répété avec 9.1.5: résultats cohérents dans une marge d'erreur de 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 est évidemment légèrement plus rapide que CURRENT_DATE .

47
Erwin Brandstetter

Un moyen simple d'obtenir uniquement des horodatages pour la journée en cours depuis 01h00 consiste à filtrer avec CURRENT_DATE + interval '1 hour'

Votre requête devrait donc ressembler à ceci:

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;

J'espère que cela pourra aider.

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

Cela fonctionne pour moi - il sélectionne TOUTES les lignes avec la date d'aujourd'hui.

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

Cela fonctionne bien pour moi!

8
Vivegan
where 
    u.login > u.logout 
    and     
    date_trunc('day', u.login) = date_trunc('day', now()) 
    and 
    date_trunc('hour', u.login) >= 1
3
Clodoaldo Neto