Query Postgresql tra intervalli di date


126

Sto cercando di interrogare il mio db postgresql per restituire risultati in cui una data è in un determinato mese e anno. In altre parole vorrei tutti i valori per un mese-anno.

L'unico modo in cui sono stato in grado di farlo finora è così:

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

Il problema con questo è che devo calcolare la prima e l'ultima data prima di interrogare la tabella. C'è un modo più semplice per farlo?

Grazie


L'intervallo è sempre un mese o potrebbe essere che inizi forse il 15 e finisci il 7 del mese successivo?
dal

Risposte:


202

Con le date (e gli orari) molte cose diventano più semplici se usi >= start AND < end.

Per esempio:

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

In questo caso devi ancora calcolare la data di inizio del mese che ti serve, ma dovrebbe essere semplice in molti modi.

Anche la data di fine è semplificata; basta aggiungere esattamente un mese. Nessun problema con il 28, 30, 31, ecc.


Questa struttura ha anche il vantaggio di poter mantenere l'uso degli indici.


Molte persone possono suggerire un modulo come il seguente, ma non usano gli indici:

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

Ciò comporta il calcolo delle condizioni per ogni singola riga nella tabella (una scansione) e non l'utilizzo di index per trovare l'intervallo di righe che corrisponderà (una ricerca di intervallo).


1
Il primo approccio deve pasticciare con mesi (invece di giorni) per es. 2014-12-01& 2015-01-01. Anche il secondo può essere indicizzato, ma non è banale, lo ammetto, EXTRACT()sembra più compatibile.
pozs

1
È possibile evitare il calcolo della data nell'applicazione utilizzando l'intervallo. es: WHERE login_date> = '2014-02-01' AND login_date <'2014-02-01' :: date + INTERVAL '1 month' Questo utilizza ancora gli indici mentre semplifica il tuo codice.
baswell

53

Da PostreSQL 9.2 sono supportati i tipi di intervallo . Quindi puoi scrivere questo come:

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

questo dovrebbe essere più efficiente del confronto tra stringhe


23

Nel caso in cui qualcuno atterri qui ... dalla 8.1 puoi semplicemente usare:

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

Dai documenti:

BETWEEN SYMMETRIC è uguale a BETWEEN tranne che non è necessario che l'argomento a sinistra di AND sia minore o uguale all'argomento a destra. Se non lo è, questi due argomenti vengono scambiati automaticamente, in modo che sia sempre implicito un intervallo non vuoto.


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

La parola chiave Between funziona eccezionalmente per una data. si presume che l'ora sia alle 00:00:00 (cioè mezzanotte) per le date.


-14

Leggi la documentazione.

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

Ho usato una query come questa:

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

o

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

Juanitos Ingenier.


2
Questo non risponde esattamente alla domanda. La domanda richiede date basate su mese e anno.
Ram
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.