Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi '24:00' Uhr als Parameter an Query übergeben (https://www.delphipraxis.net/155093-24-00-uhr-als-parameter-query-uebergeben.html)

MatthiasR 8. Okt 2010 08:29

Datenbank: PostgreSQL • Version: 8,.4 • Zugriff über: UniDAC

'24:00' Uhr als Parameter an Query übergeben
 
Wir verwenden die UniDAC-Komponenten, um auf eine PostgreSQL-Datenbank zuzugreifen. In der Datenbank existieren verschiedene Tabellen, in die Uhrzeiten eingetragen werden (Datentyp: time without time zone). Es handelt sich immer um Anfangs- und Endzeiten, wobei die Endzeiten auch den Wert '24:00' Uhr annehmen können. PostgreSQL unterscheidet 0 Uhr und 24 Uhr voneinander, ich weiß nicht, wie es sich da bei anderen DBMS verhält. Bei Delphi gehört 24 Uhr ja quasi schon zum nächsten Tag, da der Nachkommawert eines TDateTime dann wieder voll ist. Daher kann 24 Uhr auch nicht als TDateTime-Parameter übergeben werden.

Aus diesem Grund übergeben wir time-Werte bei Abfragen immer als string-Parameter an die Query und casten den string innerhalb des SQL-Statement auf einen time-Wert. Also z.B. in der Form:

Code:
SELECT * FROM tabelle WHERE uhrzeit BETWEEN cast(:anfang AS time) AND cast(:ende AS time)
Die Parameter belegen wir dann folgendermaßen:

Code:
Query.ParamByName('anfang').AsString := '18:00';
Query.ParamByName('ende').AsString := '24:00';
Sobald die Query jedoch geöffnet wird, wird ein EConvertError ausgelöst der besagt:

"Hour is out of range."

Was ich mich an der Stelle frage, ist, an was die Query hier festmacht, dass der übergebene Parameter einen Zeittyp darstellt, ich übergebe ihn ja explizit als string. Ich hab auch schon versucht, den FieldType der Parameter hart auf ftString zu setzen, hat aber nichts gebracht.

Was ich halt auch nicht weiß, ob das eine "Spezialität" der UniDAC-Komponenten ist, oder ob das Verhalten von einer Delphi-Basisklasse wie dem TDataSet geerbt wurde und sich somit alle Query so verhalten.

Wie kann ich das Beheben, ohne auf die Verwendung von Parametern verzichten zu müssen? Wenn ich die "24:00" hart in das SQL-Statement reinschreibe, dann klappt der Aufruf nämlich.

mirage228 8. Okt 2010 08:35

AW: '24:00' Uhr als Parameter an Query übergeben
 
Landet auch 24:00 in der Datenbank? Bei MySQL war es so, dass 24:00 Uhr eigentlich 00:00 Uhr ist und der Zeit-Datentyp demzufolge nur von 0:00 - 23:59:59 geht ... Geht es wenn Du aus "24:00" eine "0:00" machst? Kannst Du nicht die Delphi-Referenz durchsuchenStrToTime-Funktion von Delphi verwenden, um die Zeit auch wirklich als Zeit-Wert zu erhalten?
Also ich frage mich gerade nur, wie das dann intern auseinandergehalten werden soll von PostgreSQL...

Viele Grüße

MatthiasR 8. Okt 2010 08:48

AW: '24:00' Uhr als Parameter an Query übergeben
 
Also wie das intern auseinander gehalten wird von Postgres weiß ich leider nicht, aber Fakt ist, es geht! Wenn in der Tabelle ein Zeitraum abgespeichert wird, der von 18 - 24 Uhr geht, dann steht auch 24 Uhr in der Tabelle! Wenn Postgres daraus 0 Uhr machen würde, dann wäre das beispielsweise für meine genannte Abfrage fatal:
Code:
select cast('19:00' as time) between cast('18:00' as time) and cast('24:00' as time)
liefert bei Postgres nämlich "True" zurück...
Code:
select cast('19:00' as time) between cast('18:00' as time) and cast('00:00' as time)
logischerweise "False", da der Zeitraum von 0 - 18 Uhr betrachtet wird.

StrToTime bringt mir da leider überhaupt nichts, weil die Funktion sicherlich denselben EConvertError erzeugen dürfte, sollte man ihr "24:00" übergeben.

mirage228 8. Okt 2010 08:55

AW: '24:00' Uhr als Parameter an Query übergeben
 
Hm, Versuch das ganze mal als Integer zu übergeben. Also
Delphi-Quellcode:
.AsInteger := 180000;
.AsInteger := 240000;
Kann Postgre laut Doku auch mit umgehen

MatthiasR 8. Okt 2010 09:26

AW: '24:00' Uhr als Parameter an Query übergeben
 
Muss ich leider verneinen...
Code:
FEHLER: kann Typ integer nicht in Typ time without time zone umwandeln
LINE 1: select cast('19:00' as time) between cast(180000 as time) an...

Sir Rufo 8. Okt 2010 09:36

AW: '24:00' Uhr als Parameter an Query übergeben
 
Zitat:

Zitat von MatthiasR (Beitrag 1054438)
Code:
SELECT * FROM tabelle WHERE uhrzeit BETWEEN cast(:anfang AS time) AND cast(:ende AS time)
Was ich mich an der Stelle frage, ist, an was die Query hier festmacht, dass der übergebene Parameter einen Zeittyp darstellt, ich übergebe ihn ja explizit als string. Ich hab auch schon versucht, den FieldType der Parameter hart auf ftString zu setzen, hat aber nichts gebracht.

Code:
cast(:ende AS time)
Das legt fest, dass der Parameter als Time interpretiert werden soll (muss).

Wenn du abfragen möchtest, was in der Zeit von 18-0 Uhr gewesen ist und es bei anderen Abfragen keine Überschneidungen geben soll, dann müsste die Abfrage ja eigentlich lauten
Code:
00:00 <= Zeit < 09:00
09:00 <= Zeit < 18:00
18:00<= Zeit < 24:00
BETWEEN fragt aber so ab
Code:
00:00 <= Zeit <= 09:00
09:00 <= Zeit <= 18:00
18:00<= Zeit <= 24:00
Somit würden alle Einträge auf den Zeitgrenzen in den Abfragen quasi doppelt erscheinen.
Besser (und damit stressfreier) wäre es mit BETWEEN die Stunde abzufragen
Code:
0 <= Stunde( Zeit ) <= 8
9 <= Stunde( Zeit ) <= 17
18 <= Stunde( Zeit ) <= 23

mirage228 8. Okt 2010 09:56

AW: '24:00' Uhr als Parameter an Query übergeben
 
Zitat:

Zitat von MatthiasR (Beitrag 1054445)
Muss ich leider verneinen...
Code:
FEHLER: kann Typ integer nicht in Typ time without time zone umwandeln
LINE 1: select cast('19:00' as time) between cast(180000 as time) an...

Was ist wenn Du den Typecast nach "TIME" weglässt und nur die Zahl übergibst sodass die Umwandlung implizit erfolgt?

hoika 8. Okt 2010 10:55

AW: '24:00' Uhr als Parameter an Query übergeben
 
Hall,

versuche mal today

siehe auch



8.5.1.5

MatthiasR 8. Okt 2010 11:24

AW: '24:00' Uhr als Parameter an Query übergeben
 
Zitat:

Zitat von Sir Rufo (Beitrag 1054447)
Code:
cast(:ende AS time)
Das legt fest, dass der Parameter als Time interpretiert werden soll (muss).

War mir an der Stelle nicht bewusst, aber damit scheinst du Recht zu haben und das hat mich wiederum auf einen Lösungsansatz gebracht, der wohl funktioniert. Statt "cast(:ende as time)" schreibe ich im SQL-Statement einfach "cast(cast(:ende as text) as time)" und der Fisch ist geputzt. "24:00" wird nun zuerst mal als String interpretiert und daher auch angenommen, und anschließend erst von Postgres in einen time-Wert umgewandelt.
Zitat:

Zitat von Sir Rufo (Beitrag 1054447)
Wenn du abfragen möchtest, was in der Zeit von 18-0 Uhr gewesen ist und es bei anderen Abfragen keine Überschneidungen geben soll, dann müsste die Abfrage ja eigentlich lauten
Code:
00:00 <= Zeit < 09:00
09:00 <= Zeit < 18:00
18:00<= Zeit < 24:00
BETWEEN fragt aber so ab
Code:
00:00 <= Zeit <= 09:00
09:00 <= Zeit <= 18:00
18:00<= Zeit <= 24:00
Somit würden alle Einträge auf den Zeitgrenzen in den Abfragen quasi doppelt erscheinen.
Besser (und damit stressfreier) wäre es mit BETWEEN die Stunde abzufragen
Code:
0 <= Stunde( Zeit ) <= 8
9 <= Stunde( Zeit ) <= 17
18 <= Stunde( Zeit ) <= 23

Der "between"-Aufruf sollte lediglich ein Beispiel sein an der Stelle und wird in der Form nicht in meiner Anwendung verwendet. Drum brauchst du da nicht weiter drüber nachzudenken. Aber mir ist die Tatsache bewusst, dass "between" sowohl den Anfangs-, als auch den Endzeitpunkt als zum Zeitraum zugehörig ansieht.
Zitat:

Zitat von mirage228 (Beitrag 1054453)
Was ist wenn Du den Typecast nach "TIME" weglässt und nur die Zahl übergibst sodass die Umwandlung implizit erfolgt?

Das hätte ich als nächstes ausprobiert, wobei ich dann eher "24:00" als Parameter übergeben würde, als "240000". Bei "between" könnte das noch funktionieren, bei der von mir ebenfalls verwendeten "overlaps"-Funktion von Postgres aber sicher nicht, die erwartet nämlich eindeutige time-Werte und im Falle des Falles einen expliziten Typcast.
Zitat:

Zitat von hoika (Beitrag 1054473)
versuche mal today

Denke ich nicht, dass das klappt, da "today" laut der von dir angegebenen Tabelle nur an die Typen "date, timestamp" zugewiesen werden kann, nicht jedoch time.


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:41 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz