Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Delphi Trigger (https://www.delphipraxis.net/216568-trigger.html)

Walter Landwehr 19. Jan 2025 10:21

Datenbank: Firebird • Version: 2.0 • Zugriff über: IBO

Trigger
 
Hallo ich habe folgenden Code im Trigger:
Delphi-Quellcode:
  if (new.geburtsdatum > '') then
    begin
       new.geburtstag = extract(day from new.geburtsdatum);
       new.geburtsmonat_zahl = extract(Month from new.geburtsdatum);
       if new.geburtsmonat_zahl = 1 then
         if new.geburtsmonat = 'Januar';

    end
Bei if new.geburtsmonat_zahl = 1 then kommte ein Parsing error. Was ist hier falsch?

DeddyH 19. Jan 2025 10:28

AW: Trigger
 
Sicher, dass nicht stattdessen das sinnlose „if“ in der nachfolgenden Zeile moniert wird?

hes 19. Jan 2025 10:34

AW: Trigger
 
Hab mit Firebird noch nie was gemacht, aber ist es nicht wie z.b. in C, dass du == machen musst?

DeddyH 19. Jan 2025 10:37

AW: Trigger
 
Auf jeden Fall kann es auch nicht schaden, den Ausdruck zu klammern
Code:
if (…) then

Walter Landwehr 19. Jan 2025 11:59

AW: Trigger
 
Danke

So funktioniert es:
Delphi-Quellcode:
  if (new.geburtsdatum > '') then
    begin
       new.geburtstag = extract(day from new.geburtsdatum);
       new.geburtsmonat_zahl = extract(Month from new.geburtsdatum);
       if (new.geburtsmonat_zahl = 1) then
         new.geburtsmonat = 'Januar';

    end

Walter Landwehr 19. Jan 2025 13:24

AW: Trigger
 
Leider immer noch ein Problem. Hier mal der Ganze Trigger.
Delphi-Quellcode:
as
    declare variable Monat Integer;
    declare variable Tag Integer;
begin
  if (new.ZAHLUNGSPFLICHTIG = 'J') then
    if (((new.ZAHLUNGSART is null) or (new.ZAHLUNGSART = '')) or ((new.ZAHLUNGSZEITPUNKT) is null or (new.ZAHLUNGSZEITPUNKT = ''))) then
        exception EXCP_INVALID;

    if (new.geburtsdatum > '') then
    begin
       Tag = extract(day from new.geburtsdatum);
       Monat = extract(Month from new.geburtsdatum);

       if (Monat = 1) then
         New.geburtsmonat = 'Januar';
       if (Monat = 2) then
         new.geburtsmonat = 'Februar';
       if (Monat = 3) then
         new.geburtsmonat = 'März';
       if (Monat = 4) then
         new.geburtsmonat = 'Aprol';
       if (Monat = 5) then
         new.geburtsmonat = 'Mai';
       if (Monat = 6) then
         new.geburtsmonat = 'Juni';
       if (Monat = 7) then
         new.geburtsmonat = 'Juli';
       if (Monat = 8) then
         new.geburtsmonat = 'August';
       if (Monat = 9) then
         new.geburtsmonat = 'September';
       if (Monat =10) then
         new.geburtsmonat = 'Oktober';
       if (Monat = 11) then
         new.geburtsmonat = 'November';
       if (Monat = 12) then
         new.geburtsmonat = 'Dezember';
       Old.geburtstag = Tag;
       Old.geburtsmonat_zahl = Monat;
    end
end
Der Trigger lässt sich nicht kompilieren. Keine Ahnung warum. Vielleicht sieht jemand den Fehler.

joachimd 19. Jan 2025 13:37

AW: Trigger
 
ist das richtig so, dass Du old ändern willst? Steht das überhaupt schreibbar zur Verfügung?

Walter Landwehr 19. Jan 2025 14:25

AW: Trigger
 
Ja stimmt ist natürlich falsch. Hab ich geändert nun lässt sich der Trigger kompilieren. Leider kann ich aber weder einen Daten Satz ändern noch neu anlegen. Muss glaub ich irgendwie mit den Variablen zu tun haben.

Hier muss der Fehler liegen.
Tag = extract(day from new.geburtsdatum);
Monat = extract(Month from new.geburtsdatum);
Jahr = extract(year from new.geburtsdatum);
aber was ist falsch?

Sharky 19. Jan 2025 17:46

AW: Trigger
 
Hallo Walther,

auch wenn Firebird bei mir viele Jahre her ist...
Aber deine 12 if then Statements solltest Du auch so schreiben können:

Code:
New.geburtsmonat = case
               when Monat = 1 then 'Januar'
               when Monat = 2 then 'Februar'
               when Monat = 3 then 'März''
               when Monat = 4 then 'April'
               when Monat = 5 then 'Mai'
               when Monat = 6 then 'Juni'
               when Monat = 7 then 'Juli'
               when Monat = 8 then 'August'
               when Monat = 9 then 'September'
               when Monat = 10 then 'Oktober'
               when Monat = 11 then 'November'
               when Monat = 12 then 'Dezember'
         end;
Macht das Ganze etwas übersichtlicher.

Jasocul 20. Jan 2025 05:48

AW: Trigger
 
Zitat:

Zitat von Walter Landwehr (Beitrag 1545404)
Hier muss der Fehler liegen.
Tag = extract(day from new.geburtsdatum);
Monat = extract(Month from new.geburtsdatum);
Jahr = extract(year from new.geburtsdatum);
aber was ist falsch?

Das halte ich für unwahrscheinlich, falls geburtsdatum ein Datumstyp ist. Falls es ein varchar ist, kann es Interpretationsfehler durch die DB geben. Allerdings lässt nicht jede DB dann noch dieses extract zu. Wie es in Firebird ist, weiß ich nicht.
Außerdem machst du noch ein extract auf das Jahr, was in deinem Code für den Trigger nicht enthalten ist. Ist der Code, den du uns zeigst vielleicht unvollständig und wie sehen daher gar nicht alle potentiellen Fehlerstellen?

Bitte folgendes genau prüfen:
Code:
if (((new.ZAHLUNGSART is null) or (new.ZAHLUNGSART = '')) or ((new.ZAHLUNGSZEITPUNKT) is null or (new.ZAHLUNGSZEITPUNKT = ''))) then
    exception EXCP_INVALID;
Läuft der Trigger vielleicht in die Exception?
Abgesehen davon ist beim Zahlungszeitpunkt nicht richtig geklammert.
Um es zu vereinfachen, kannst du die Prüfung wie folgt ändern:
Code:
(new.ZAHLUNGSART is null) or (new.ZAHLUNGSART = '')
-- wird zu:
coalesce(new.ZAHLUNGSART, '') = ''
-- und
(new.ZAHLUNGSZEITPUNKT) is null or (new.ZAHLUNGSZEITPUNKT = '')
-- wird zu:
coalesce(new.ZAHLUNGSZEITPUNKT, '') = ''
Das sollte dann so aussehen:
Code:
if ((coalesce(new.ZAHLUNGSART, '') = '') or (coalesce(new.ZAHLUNGSZEITPUNKT, '') = '')) then
    exception EXCP_INVALID;
Und bei der Gelegenheit noch Aprol in April ändern :wink:

Walter Landwehr 20. Jan 2025 07:02

AW: Trigger
 
OK hier nochmals der ganze Trigger:
Delphi-Quellcode:
as
    declare variable Monat Integer;
    declare variable Tag Integer;
    declare variable Jahr Integer;
begin
  if (new.ZAHLUNGSPFLICHTIG = 'J') then
    if (((new.ZAHLUNGSART is null) or (new.ZAHLUNGSART = '')) or ((new.ZAHLUNGSZEITPUNKT) is null or (new.ZAHLUNGSZEITPUNKT = ''))) then
        exception EXCP_INVALID;

    if (new.geburtsdatum > '') then
    begin
       Tag = extract(day from new.geburtsdatum);
       Monat = extract(Month from new.geburtsdatum);
       Jahr = extract(year from new.geburtsdatum);

       if (Monat = 1) then
         New.geburtsmonat = 'Januar';
       if (Monat = 2) then
         new.geburtsmonat = 'Februar';
       if (Monat = 3) then
         new.geburtsmonat = 'März';
       if (Monat = 4) then
         new.geburtsmonat = 'April';
       if (Monat = 5) then
         new.geburtsmonat = 'Mai';
       if (Monat = 6) then
         new.geburtsmonat = 'Juni';
       if (Monat = 7) then
         new.geburtsmonat = 'Juli';
       if (Monat = 8) then
         new.geburtsmonat = 'August';
       if (Monat = 9) then
         new.geburtsmonat = 'September';
       if (Monat =10) then
         new.geburtsmonat = 'Oktober';
       if (Monat = 11) then
         new.geburtsmonat = 'November';
       if (Monat = 12) then
         new.geburtsmonat = 'Dezember';
       new.geburtstag = Tag;
       new.geburtsmonat_zahl = Monat;
       new.geburtsjahr = Jahr;
    end
end
Ich befürchte das es mit dem Geburtsdatum zu tun hat. Die ist in der Datenbank ein Datumsfeld (Date).

mkinzler 20. Jan 2025 07:02

AW: Trigger
 
Falsche Position der Klammer

SQL-Code:
((new.ZAHLUNGSZEITPUNKT) is null or (new.ZAHLUNGSZEITPUNKT = ''))) then
müsste

SQL-Code:
((new.ZAHLUNGSZEITPUNKT is null) or (new.ZAHLUNGSZEITPUNKT = ''))) then
lauten.

Neumann 20. Jan 2025 07:06

AW: Trigger
 
Ist das wirklich Firebird 2? Aktuell ist Firebird 5, wobei der Umstieg nicht besonders schwierig ist.

Wenn da ein eigenes Programm mit der Datenbank arbeitet, ist es wesentlich einfacher die Delphi Datumsroutinen zu verwenden als so einen relativ komplizierten Trigger zu bauen. Auch braucht man 4 Felder in der Datenbank, wo eigentlich eines reicht, wovon 3 berechnete Werte speichern. Das hat wahrscheinlich geringen Einfluss auf Größe und Performance der Datenbank, ist aber unschön.

Braucht man die Werte z.B. für Export von Daten, könnte man sie auch über eine Stored Procedure abfragen.

Jasocul 20. Jan 2025 07:23

AW: Trigger
 
Ich weiß nicht, ob man FB debuggen kann, aber falls nicht, würde ich aus dem Trigger erstmal eine User Defined Function oder Stored Procedure machen.
Mit entsprechenden Parametern und Rückgabewerten kann man dann prüfen, an welcher Stelle es hakt.
Damit hättest du auch die Möglichkeit, dir einen Soll-Ist-Vergleich zu erstellen.

IBExpert 20. Jan 2025 07:48

AW: Trigger
 
debuggen kann man so was in ibexpert, aber das bringt nur wenig erkenntnisse wenn man grundlegende
vergleiche sinnlos codiert.

Code:
    if (new.geburtsdatum > '') then
warum soll ein datum >'' sein?

entweder kommt da rechts auch ein datum rein oder du prüfst auf not null

firebird liefert auch brauchbare fehler, in einigermaßen aktuellen firbeird versionen
auch gleich mit zeilennummer (die o.a. zeile ist in meinem test genau zeile 12)

Code:
Overflow occurred during data type conversion.
conversion error from string "".
At trigger 'TESTX_BU0' line: 12, col: 5.
----------------------------------------------
SQLCODE: -413
SQLSTATE: 22018
GDSCODE: 335544334
so funktioniert das

Code:
    if (new.geburtsdatum > '1.1.1900') then

Walter Landwehr 20. Jan 2025 08:51

AW: Trigger
 
Danke an Holger Klemt, das war der entscheidende Tipp.

Benmik 20. Jan 2025 14:05

AW: Trigger
 
Zitat:

Zitat von IBExpert (Beitrag 1545414)
Code:
    if (new.geburtsdatum > '1.1.1900') then

Der älteste lebende Mensch wurde 1908 geboren, also passt das tatsächlich.

joachimd 20. Jan 2025 14:56

AW: Trigger
 
Zitat:

Zitat von Benmik (Beitrag 1545423)
Zitat:

Zitat von IBExpert (Beitrag 1545414)
Code:
    if (new.geburtsdatum > '1.1.1900') then

Der älteste lebende Mensch wurde 1908 geboren, also passt das tatsächlich.

Datenbank NULL entspricht diesem Datum

mkinzler 20. Jan 2025 15:29

AW: Trigger
 
Zitat:

Zitat von joachimd (Beitrag 1545426)
Zitat:

Zitat von Benmik (Beitrag 1545423)
Zitat:

Zitat von IBExpert (Beitrag 1545414)
Code:
    if (new.geburtsdatum > '1.1.1900') then

Der älteste lebende Mensch wurde 1908 geboren, also passt das tatsächlich.

Datenbank NULL entspricht diesem Datum

Ein Windowsdatum von 0 (nicht NULL) entspricht 31.12.1899. Der 01.01.1900 wäre dann 1.

Uwe Raabe 20. Jan 2025 15:43

AW: Trigger
 
Zitat:

Zitat von mkinzler (Beitrag 1545430)
Ein Windowsdatum von 0 (nicht NULL) entspricht 31.12.1899. Der 01.01.1900 wäre dann 1.

Bei Firebird steht aber:
Zitat:

The DATE data type in Dialect 3 stores only date without time. The available range for storing data is from January 01, 1 to December 31, 9999.
Intern sieht das noch etwas anders aus:
Zitat:

In storage, a date value or date-part of a timestamp is represented as the number of days elapsed since date zero — November 17, 1898

IBExpert 20. Jan 2025 16:42

AW: Trigger
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1545431)
Zitat:

Zitat von mkinzler (Beitrag 1545430)
Ein Windowsdatum von 0 (nicht NULL) entspricht 31.12.1899. Der 01.01.1900 wäre dann 1.

Bei Firebird steht aber:
Zitat:

The DATE data type in Dialect 3 stores only date without time. The available range for storing data is from January 01, 1 to December 31, 9999.
Intern sieht das noch etwas anders aus:
Zitat:

In storage, a date value or date-part of a timestamp is represented as the number of days elapsed since date zero — November 17, 1898

kann man auch ganz einfach benutzen um die anzahl der tage seit dem 0 datum zu berechnen

Code:
select current_date-cast('30.12.1899' as date) from rdb$database
ergebnis 45677

die range ist dabei nicht das problem weil der wert ja auch negativ sein kann.

auch das hier geht
Code:
select cast('01.01.0001' as date)-cast('30.12.1899' as date) from rdb$database
ergebnis -693593

Ich finde das verfahren sehr gut gelöst, weil die darstellung sprich umrechnung in tag/monat/jahr ob mit oder ohne schaltjahr unabhängig vom wert ist, der ja nur anzahl tage vor oder hinter 0 darstellt. ich kann mich aus grauer vorzeit noch daran erinnern, das mysql mit einem datum 30.2. nie probleme hatte, auch wenn das immer unsinn war. mag aber sein, das die das mittlerweile auch anders machen.

und ergänzende infos: als timestamp ist das identisch nur mit nachkommastelle, d.h. mittags um 12 ist plus 0,5 usw. später kam dann auch noch die zeitzone mit in die daten. das die nicht negative jahre vor dem jahr 0 unterstützen kann ich nachvollziehen, das braucht auch nicht jede branche und bis zum enddatum im jahr 9999 haben wir noch circa 3mio tage verfügbar, das sollte für fast alle sinnvollen aufgaben auch reichen. Zumindest aus unserer heutigen sicht ;-)

IBExpert 20. Jan 2025 17:06

AW: Trigger
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1545431)
Intern sieht das noch etwas anders aus:
Zitat:

In storage, a date value or date-part of a timestamp is represented as the number of days elapsed since date zero — November 17, 1898

mag ja technisch für binary storage in der datenbank wirklich so sein, wird man aber nirgendwo als tag 0 so finden

Code:
select current_date-45677 from rdb$database
ergibt den 30.12.1899


Alle Zeitangaben in WEZ +1. Es ist jetzt 10:19 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