Requête postgresql entre les plages de dates

126

J'essaie d'interroger ma base de données postgresql pour renvoyer des résultats où une date est dans un certain mois et une année. En d'autres termes, je voudrais toutes les valeurs pour un mois-année.

La seule façon dont j'ai pu le faire jusqu'à présent est comme ceci:

SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN '2014-02-01' AND '2014-02-28'

Le problème avec ceci est que je dois calculer la première date et la dernière date avant d'interroger la table. Existe-t-il un moyen plus simple de procéder?

Merci

John
la source
L'intervalle est-il toujours d'un mois ou pourrait-il être, que vous commenciez peut-être au 15 et vous terminiez le 7 du mois suivant?
frlan

Réponses:

202

Avec les dates (et les heures), beaucoup de choses deviennent plus simples si vous utilisez >= start AND < end.

Par exemple:

SELECT
  user_id
FROM
  user_logs
WHERE
      login_date >= '2014-02-01'
  AND login_date <  '2014-03-01'

Dans ce cas, vous devez toujours calculer la date de début du mois dont vous avez besoin, mais cela devrait être simple de plusieurs manières.

La date de fin est également simplifiée; il suffit d'ajouter exactement un mois. Pas de soucis avec les 28e, 30e, 31e, etc.


Cette structure présente également l'avantage de pouvoir maintenir l'utilisation d'index.


De nombreuses personnes peuvent suggérer un formulaire tel que celui-ci, mais n'utilisent pas d' index:

WHERE
      DATEPART('year',  login_date) = 2014
  AND DATEPART('month', login_date) = 2

Cela implique de calculer les conditions pour chaque ligne de la table (une analyse) et de ne pas utiliser d'index pour trouver la plage de lignes qui correspondra (une recherche par plage).

MatBailie
la source
1
La première approche doit jouer avec des mois (au lieu de jours) par ex. 2014-12-01& 2015-01-01. Le second peut être indexé aussi, mais ce n'est pas anodin, je l'admets - EXTRACT()semble plus compatible.
pozs
1
Vous pouvez éviter les calculs de date dans votre application en utilisant l'intervalle. par exemple: WHERE login_date> = '2014-02-01' AND login_date <'2014-02-01' :: date + INTERVAL '1 month' Ceci utilise toujours des index tout en simplifiant votre code.
baswell
53

Depuis PostreSQL 9.2 , les types de plage sont pris en charge. Vous pouvez donc écrire ceci comme:

SELECT user_id
FROM user_logs
WHERE '[2014-02-01, 2014-03-01]'::daterange @> login_date

cela devrait être plus efficace que la comparaison de chaînes

Ana María Martínez Gómez
la source
23

Juste au cas où quelqu'un atterrirait ici ... depuis 8.1, vous pouvez simplement utiliser:

SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN SYMMETRIC '2014-02-01' AND '2014-02-28'

À partir de la documentation:

BETWEEN SYMMETRIC est identique à BETWEEN, sauf qu'il n'est pas nécessaire que l'argument à gauche de AND soit inférieur ou égal à l'argument de droite. Si ce n'est pas le cas, ces deux arguments sont automatiquement échangés, de sorte qu'une plage non vide est toujours implicite.

HayrolR
la source
-1
SELECT user_id 
FROM user_logs 
WHERE login_date BETWEEN '2014-02-01' AND '2014-03-01'

Entre le mot-clé fonctionne exceptionnellement pour une date. il suppose que l'heure est à 00:00:00 (c'est-à-dire minuit) pour les dates.

Chaudhary sarimurrab
la source
-14

Lisez la documentation.

http://www.postgresql.org/docs/9.1/static/functions-datetime.html

J'ai utilisé une requête comme celle-ci:

WHERE
(
    date_trunc('day',table1.date_eval) = '2015-02-09'
)

ou

WHERE(date_trunc('day',table1.date_eval) >='2015-02-09'AND date_trunc('day',table1.date_eval) <'2015-02-09')    

Juanitos Ingenier.

Juan Garfias
la source
2
Cela ne répond pas exactement à la question. La question demande des dates basées sur le mois et l'année.
Ram