Postgresql-Abfrage zwischen Datumsbereichen

126

Ich versuche, meine postgresql-Datenbank abzufragen, um Ergebnisse zurückzugeben, bei denen ein Datum in einem bestimmten Monat und Jahr liegt. Mit anderen Worten, ich möchte alle Werte für ein Monat-Jahr.

Der einzige Weg, wie ich es bisher geschafft habe, ist folgender:

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

Das Problem dabei ist, dass ich das erste und das letzte Datum berechnen muss, bevor ich die Tabelle abfrage. Gibt es einen einfacheren Weg, dies zu tun?

Vielen Dank

John
quelle
Ist das Intervall immer ein Monat oder könnte es sein, dass Sie vielleicht am 15. beginnen und am 7. des folgenden Monats enden?
Frlan

Antworten:

201

Mit Datum (und Uhrzeit) werden viele Dinge einfacher, wenn Sie verwenden >= start AND < end.

Beispielsweise:

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

In diesem Fall müssen Sie noch das Startdatum des gewünschten Monats berechnen, dies sollte jedoch in vielerlei Hinsicht einfach sein.

Das Enddatum wird ebenfalls vereinfacht. füge einfach genau einen Monat hinzu. Kein Herumspielen mit dem 28., 30., 31. usw.


Diese Struktur hat auch den Vorteil, dass die Verwendung von Indizes beibehalten werden kann.


Viele Leute schlagen möglicherweise ein Formular wie das folgende vor, verwenden jedoch keine Indizes:

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

Dies beinhaltet die Berechnung der Bedingungen für jede einzelne Zeile in der Tabelle (ein Scan) und nicht die Verwendung des Index, um den übereinstimmenden Zeilenbereich zu finden (eine Bereichssuche).

MatBailie
quelle
1
Der erste Ansatz muss mit Monaten (anstelle von Tagen) f.ex. 2014-12-01& 2015-01-01. Der zweite kann ebenfalls indiziert werden, aber das ist nicht trivial, ich gebe zu - EXTRACT()scheint kompatibler zu sein.
pozs
1
Sie können Datumsberechnungen in Ihrer Anwendung vermeiden, indem Sie Intervalle verwenden. Beispiel: WHERE login_date> = '2014-02-01' AND login_date <'2014-02-01' :: date + INTERVAL '1 month' Hierbei werden weiterhin Indizes verwendet, während der Code vereinfacht wird.
Baswell
53

Von PostreSQL 9.2 Bereichstypen werden unterstützt. Sie können dies also wie folgt schreiben:

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

Dies sollte effizienter sein als der Zeichenfolgenvergleich

Ana María Martínez Gómez
quelle
22

Nur für den Fall, dass jemand hier landet ... seit 8.1 können Sie einfach verwenden:

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

Aus den Dokumenten:

ZWISCHEN SYMMETRISCH ist dasselbe wie ZWISCHEN, außer dass es nicht erforderlich ist, dass das Argument links von UND kleiner oder gleich dem Argument rechts ist. Ist dies nicht der Fall, werden diese beiden Argumente automatisch ausgetauscht, sodass immer ein nicht leerer Bereich impliziert wird.

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

Das Schlüsselwort Between funktioniert ausnahmsweise für ein Datum. Es wird davon ausgegangen, dass die Uhrzeit für Daten um 00:00:00 Uhr (dh Mitternacht) liegt.

Chaudhary Sarimurrab
quelle
-14

Lesen Sie die Dokumentation.

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

Ich habe eine solche Abfrage verwendet:

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

oder

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

Juanitos Ingenier.

Juan Garfias
quelle
2
Dies beantwortet die Frage nicht genau. Die Frage fragt nach Daten basierend auf Monat und Jahr.
Ram