it-swarm-eu.dev

Vergleichen Sie ein Datum und einen Zeitstempel mit der Zeitzone mit now () in derselben Abfrage?

Ich habe mehrere Datenbankserver, die ich mit einer Abfrage abfrage, die eine Ablaufspalte mit now() vergleicht. Das Problem ist, dass eine der Ablaufspalten der Server ein timestamp with time zone Ist und der Rest einfach date ist. Ich kann dies nicht ändern, da ich keinen Administratorzugriff habe und tatsächlich nur die Ansicht abfrage. Postgres ist für mich ziemlich neu, daher verstehe ich nicht wirklich, wie Datum und Uhrzeit miteinander funktionieren.

Wenn ich versuche, den Server mit timestamp with time zone Abzufragen, indem ich timestamp als date umwandle:

...
WHERE
    (
        status_code = '30000'
        OR status_code = '30005'
    )
AND CAST(expiration AS DATE) > now()

Es funktioniert, aber die Verwendung derselben Abfrage auf den Servern, auf denen expiration bereits ein date ist, schlägt fehl:

[Err] ERROR: Ungültige Eingabesyntax für Typdatum: "Kein Enddatum"

Jede Hilfe wäre dankbar, ich würde wirklich lieber keine Ausnahme für diesen einen DB-Server fest codieren.

6
Chris

Dies sollte niemals fehlschlagen (ich habe es ein bisschen vereinfacht):

WHERE status_code IN ('30000','30005')
AND   expiration > now() 

PostgreSQL kann date und timestamp (mit oder ohne Zeitzone) automatisch vergleichen. Wenn man ein date ist, wird es automatisch in timestamp umgewandelt (0: 0 Stunden).

Die Fehlermeldung erzählt eine andere Geschichte. Sie versuchen tatsächlich, ein date mit ungültiger Syntax einzugeben.

Ich habe kürzlich eine detaillierte Antwort zum Umgang mit Zeitstempeln mit oder ohne Zeitzone in PostgreSQL geschrieben - falls dies das Problem sein sollte:


Wie sich herausstellt, ist expiration eine text Spalte. Sie müssen es in date oder timestamp umwandeln (je nachdem, was Ihren Anforderungen entspricht). Wenn es in einem gültigen Format ist:

...
AND   expiration::timestamptz > now() 

Wenn Sie ungültige Zeichenfolgen wie "Kein Enddatum" in dieser Textspalte haben, müssen Sie die Quelle bereinigen oder diese speziell in einem CASE -Konstrukt behandeln:

...
AND   CASE WHEN expiration::text = 'No End Date' THEN 'infinity'::timestamp
           WHEN expiration::text = 'foo' THEN '-infinity'::timestamp
           ELSE expiration::timestamp
      END > now()

Das Handbuch zum Sonderwert infinity.

Die Umwandlung in Text (::text) Ist mit text redundant, aber der Ausdruck funktioniert auch mit date/timestamp -Werten.

Wenn das Format des Zeitstempelliteral mehrdeutig sein kann, verwenden Sie to_date() oder to_timestamp() und definieren Sie das Format explizit:

to_date('07/08/2013', 'DD/MM/YYYY')

Verwenden Sie das Konstrukt AT TIME ZONE , wenn expiration ein lokaler Zeitstempel von einem anderen Zeitzone sein soll:

expiration::timestamp AT TIME ZONE 'UTC' -- desired time zone here

Wenn expiration mehrdeutig/nicht standardisiert ist, verwenden Sie to_timestamp() :

to_timestamp(expiration::text, 'yyyy-mm-dd')
8