Abfragen von Zeitstempenl aus PostgreSQL Tabelle in Java verwirklichen

Hallo PGSQL Gemeinde,

Kurze Istzustandsbeschreibung:
Ich arbeite an einem Projekt, bei welchem ich eine kleine Java Applikation schreibe die als Informationslogger dient. Die Informationen werden mit einem Zeitstempel in der Datenbanktabelle gespeichert. Diese läuft ständig im Hintergrund. Eine andere kleine Applikation wird nur bei Bedarf aufgerufen, liest die Infos aus der Datenbank heraus und soll die Daten der letzten 30 Minuten darstellen. Ich bin ein Anfänger in Java und in PostgreSQL, habe die letzten Wochen viel gelernt und gearbeitet, mir geht nun aber langsam die Zeit aus um mir alles selber anzulesen, deshalb muss ich nun doch jemanden zu Rate ziehen der weiß was er tut.

Das ganze Projekt steht im Prinzip schon, die Datenbankverbindung, einlesen, auslesen, anzeigen klappt alles. Nur bei den 30 Minuten komme ich noch nicht klar. Bis jetzt war meine Idee, den Zeitstempel in Millisekunden in der Datenbank abzuspeichern. Damit lässt sich in Java gut arbeiten und in der Datenbank kann ich recht einfach auf “Zeitstempel > < = Irgendwas” abfragen. Das ganze ist rein theoretisch möglich, aber es scheitert an der enorm großen Zahl des “timeInMillis”. Mit kleineren Zahlen habe ich es getestet, da würde es funktionieren.

Beispiel:
Query query = manager.createQuery("SELECT a FROM Logfile a WHERE a.timestamp > "+ (GetTimeInMillis - THIRTY_MINS));

Meine Frage, woher kommt diese Grenze? Kann ich dieses Problem umgehen?

Als Alternative habe ich mir überlegt mit Date-Objekten aus Java zu arbeiten. Aber dann müsste ich jede Zeile aus der Datenbank auslesen, umwandeln, vergleichen ob Datum/Zeit passt und dann entscheiden ob ich das ganze anzeige oder nicht. Kommt mir etwas unpraktisch/uneffizient vor!?

Dann habe ich mirüberlegt dass es bestimmt Befehle gibt, welche ich als Query an die Datenbank übergeben kann, wo dann die ganze Berechnung, ob der Eintrag älter als 30 Minuten ist, in der Datenbank statt findet und ich nicht jede Zeile einzeln überprüfen muss. Aber genau da scheitere ich Mangels Erfahrung, Zeit und für mich verständlicher Dokumentation und bitte euch deshalb um Hilfe.

Wie kann ich das am schlausten machen? Oder gibt es noch eine viel einfachere Lösung die ich vor lauter in eine Richtung rennenübersehen habe?

Dank und Grüße,
SQLDud

select … from table a where a.timestamp >= now() - ‘30minutes’::interval

Und dazu ein Index auf die Spalte.


Andreas

Danke für die schnelle Antwort.

Das mit dem Index ist klar. So wie du den/die/das Query geschrieben hast muss der timestamp in der Datenbank auch als “sql timestamp” vorliegen? Das habe ich im Beispiel wohl etwas doof fomuliert, bei mir ist der timestamp noch als BIGINT für TimeInMillis deklariert.

Im Moment füge ich alle Informationen (unter anderem auch den Timestamp) mit INSERT in die Tabelle ein. Wenn ich den SQL Timestamp nutzen will ist das nun aber nicht mehr nötig? Wie übergebe ich das, dass jede Zeile automatisch einen SQL Zeitstempel bekommt?

SQLDud



test=*# create table sqldude(t1s timestamp default now(), ts2 timestamp default statement_timestamp(), value int);
CREATE TABLE
Time: 61,934 ms
test=*# insert into sqldude (value) values (1);
INSERT 0 1
Time: 0,379 ms
test=*# insert into sqldude (value) values (2);
INSERT 0 1
Time: 0,247 ms
test=*# insert into sqldude (value) values (3);
INSERT 0 1
Time: 0,260 ms
test=*# select * from sqldude ;
            t1s             |            ts2             | value
----------------------------+----------------------------+-------
 2012-08-10 09:44:47.040841 | 2012-08-10 10:53:51.613665 |     1
 2012-08-10 09:44:47.040841 | 2012-08-10 10:53:53.27977  |     2
 2012-08-10 09:44:47.040841 | 2012-08-10 10:53:55.09927  |     3
(3 rows)

Die eine Funktion, now(), liefert den Timestamp zu Begin der aktuellen Transaktion, die andere Funktion das, was der Name vermuten läßt.

Andreas

Den Zeitstempel hab ich nun in der Datenbank drin. Anstatt BIGINT zu übergeben übergebe ich “now()” und schon tuts! Das Problem wäre gelöst. Wenn ich aber das ganze als abfrage basteln will, um die passenden Zeilen heraus zu lesen, dann wirft Java ne Exception, weil Java das now() nicht mag.

Query query = manager.createQuery(“SELECT a FROM Alarmlog WHERE a.timestamp < now()”); //Das < ist nicht sinnvoll, nur zu Testzwecken

Exception:

javax.servlet.ServletException: java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager: Exception Description: Syntax error parsing the query [SELECT a FROM Alarmlog a WHERE a.timestamp < now()], line 1, column 48: unexpected token [(]. Internal Exception: NoViableAltException(83@[()* loopback of 383:9: (d= DOT right= attribute )*]) com.vaadin.terminal.gwt.server.AbstractApplicationServlet.handleServiceException(AbstractApplicationServlet.java:1010) com.vaadin.terminal.gwt.server.AbstractApplicationServlet.service(AbstractApplicationServlet.java:548) javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

Ich hab es mit “default now()”,“timestamp default now()” “now”, etc versucht. Beim schreiben in die Tabelle funktioniert “now()”, beim auslesen nicht!?

SQLDud

Was soll a.timestamp sein? Die Tabelle heißt doch Alarmlog, nicht a? Laß das a mal weg.

Andreas