it-swarm.com.de

PostgreSQL: dazwischen mit datetime

Ich verwende PostgreSQL 8.4.11 und finde einen seltsamen Fehler. Wenn ich frage:

SELECT "documents_document"."given_on" 
FROM "documents_document" 
WHERE (EXTRACT('month' FROM "documents_document"."given_on") = 1
       AND "documents_document"."given_on" 
       BETWEEN '1-01-01 00:00:00' and '1-12-31 23:59:59.999999') 
ORDER BY "documents_document"."created_on" DESC

Ich bekomme Ergebnisse:

  given_on  
------------
 2002-01-16
 2011-01-25
 2012-01-12
 2012-01-12
 2012-01-12
 2012-01-20
 2012-01-19
 2012-01-13
 2012-01-31
 2012-01-16
 2012-01-31
 2012-01-12
 ...

Warum?

Ich würde Datumsangaben im Intervall 1-01-01 ... 1-12-31 erwarten.

11
Denis SkS

Sie haben 1-01-01 ... 1-12-31 erwartet ... aber wie soll PostgreSQL wissen, was Sie damit meinen?

Zeichenkettenliterale werden entsprechend Ihren aktuellen Ländereinstellungen interpretiert, insbesondere lc_time, wenn sie in timestamp oder date umgewandelt werden. Ich zitiere das Handbuch hier :

lc_time (string)

Legt das Gebietsschema fest, das zum Formatieren von Datum und Uhrzeit verwendet werden soll, beispielsweise mit der to_char-Funktionsfamilie. Zulässige Werte sind Systemabhängig; Weitere Informationen finden Sie in Abschnitt 22.1. Wenn diese Variable Auf die leere Zeichenfolge (Standardeinstellung) gesetzt ist, wird der Wert Von der Ausführungsumgebung des Servers systemabhängig Geerbt.

In Ihrem Fall wird das verstümmelte Zeitstempel-Literal 1-12-31 23:59:59 offensichtlich wie folgt interpretiert:

D-MM-YY h24:mi:ss

Während Sie gehofft hätten:

Y-MM-DD h24:mi:ss

3 Optionen

  1. Setzen Sie lc_time auf ein Gebietsschema, das ein solches Literal auf dieselbe Weise interpretiert wie Sie. Nicht sicher, dass es einen gibt.

  2. Verwenden Sie to_timestamp() , um das Zeichenfolgenliteral auf eine definierte Weise zu interpretieren - unabhängig vom aktuellen Gebietsschema. Viel besser.

    SELECT to_timestamp('1-12-31 23:59:59', 'D-MM-YY h24:mi:ss')
    
  3. Besser noch, verwenden Sie ISO 8601-Format (YYYY-MM-DD) für alle Datetime-Literale. Das ist eindeutig mit jedem Gebietsschema .

    SELECT '2001-12-31 23:59:59'::timestamp
    

Abfrage umschreiben

Schließlich ist Ihre Abfrage zunächst fehlerhaft. Behandeln Sie eine Bereichsabfrage anders. Schreiben Sie Ihre Anfrage erneut an:

SELECT d.given_on 
FROM   documents_document d
WHERE  EXTRACT('month' FROM d.given_on) = 1
AND    d.given_on >= '2001-01-01 0:0'
AND    d.given_on <  '2002-01-01 0:0'
ORDER  BY d.created_on DESC;

Oder noch einfacher:

SELECT d.given_on 
FROM   documents_document d
WHERE  d.given_on >= '2001-01-01 0:0'
AND    d.given_on <  '2001-02-01 0:0'
ORDER  BY d.created_on DESC;

Die neuen Typen von PostgreSQL 9.2 könnten für Sie von Interesse sein.

22

SELECT '1-12-31 23:59:59.999999'::timestamp; gibt 2031-01-12 23:59:59.999999 zurück, anscheinend betrachtet Postgres das Jahr ohne Jahrhundert nicht als erstes Element des Datums.

1
lanzz

Sie haben nicht gesagt, in welchem ​​Format Sie es haben wollten. Es gibt also das native Format zurück. Vielleicht haben Sie sogar angenommen, dass jeder die Zeit so bezeichnet, wie Sie es tun? Sehen Sie sich die möglichen Formate an. http://www.postgresql.org/docs/8.2/static/functions-formatting.html

1
Sjuul Janssen