Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Firebird Procedure liefert null (https://www.delphipraxis.net/192588-firebird-procedure-liefert-null.html)

Delix 3. Mai 2017 09:19

Datenbank: Firebird • Version: 2.5 • Zugriff über: IBDAC

Firebird Procedure liefert null
 
Hallo zusammen!

Ich habe eine Procedure mit einem numerischen Rückgabewert erstellt, welche mir einen Lagerwert per Stichtag liefern soll. Dabei habe ich folgendes Problem:

Die Procedure läuft intern korrekt ab, was ich über eine Tabelle protokolliert habe. Wenn ich die Datenmenge, die zu berechnen ist einschränke, Laufzeit ca. 2 Minuten, wird der korrekte Wert geliefert. Schränke ich die Daten nicht ein, Laufzeit ca. 8-10 Minuten, liefert die Procedure Null zurück. Lt. Internem Prtokoll ist aber alles korrekt bis zum Schluss berechnet worden.

Fehlermeldungen gibt es keine, auch nicht in firebird.log

Hat jemand eine Idee?

Schönen Gruß

jobo 3. Mai 2017 09:40

AW: Firebird Procedure liefert null
 
Was für eine schöne Glaskugelfrage. Gibt es auch Code zu der Procedure? Wenn nicht, Null Code liefert zwangsläufig auch Null Ergebnis und Null Antworten auf Fragen.;)

Ernst:
Null Rückgaben kommen häufig dadurch zustande, dass ein Join ins Leere läuft. Wenn eine kleine Datenmenge zufällig durch die Einschränkung passende Joins findet, alles ok, wenn im Großen nicht die passenden Join Daten da sind, alles NULL.

Viel mehr kann man dazu glaub ich ohne Code nicht sagen.

sko1 3. Mai 2017 09:41

AW: Firebird Procedure liefert null
 
Zitat:

Procedure mit einem numerischen Rückgabewert erstellt,
procedure (ohne Rückgabe) oder function (mit Rückgabe)?

Poste das Teil doch bitte mal!

Ciao
Stefan

ZOD 3. Mai 2017 10:57

AW: Firebird Procedure liefert null
 
eventuell hilft die Verwendung von
Code:
coalesce()
im SQL statement ..

https://firebirdsql.org/refdocs/lang...-coalesce.html

Jumpy 3. Mai 2017 11:04

AW: Firebird Procedure liefert null
 
Oder in deinen Berechnungen fließt ein Datensatz mit Null-Wert ein, so dass auch das Ergebnis Null wird.

Delix 3. Mai 2017 11:20

AW: Firebird Procedure liefert null
 
Hallo,

mit den bisherigen Antworten kann ich leider wenig anfangen, da eine meiner Aussagen nicht berücksichtigt wird:

Die Procedure läuft intern absolut korrekt ab. Das habe ich aus der Procedure heraus protokolliert. Die Rückgabe-Variable ist bis zum Schluss absolut korrekt berechnet! Da fallen joins's oder Nullwerte wohl aus.

hier die Procedure:


SQL-Code:
ALTER PROCEDURE P_GETLAGERWERT ( DATUM DATE )
RETURNS ( LGWERT NUMERIC(12,2) )
AS
DECLARE ARTNR VARCHAR(50);
DECLARE BEREINH NUMERIC (10,3);
DECLARE LGNR INTEGER;
DECLARE LE_EK NUMERIC (12,4);
DECLARE ART_EKNETTO NUMERIC (12,4);
DECLARE BESTAND NUMERIC (11,3);
DECLARE BER_BESTAND NUMERIC (11,3);
DECLARE BEST_OHNE_RECHNUNG NUMERIC (11,3);
DECLARE ART_WERT NUMERIC (12,3);

BEGIN

  LGWERT = 0;
 
  DELETE FROM DBPROC WHERE PROCNAME = 'P_GETLAGERWERT';
 
  for Select AL.Artnr, AL.LgNr, AR.BEREINH, AR.EKNETTO from Artl al
    LEFT JOIN ARTIKEL ar ON al.ARTNR = ar.ARTNR                    
    LEFT JOIN LAG ON LAG.LGNR = AL.LGNR
      Where (cast( al.LgNr as Integer) >0 ) and ( ar.artgrp <= 59 )                                        
       AND ar.Aktiv='J'
       AND ar.Bestfrg ='J'
       AND LAG.BESTSUM = 'J'
       AND AL.BEST>0
    Group by al.Artnr, al.LgNr, Ar.BEREINH, AR.EKNETTO
    ORDER BY AL.LGNR, AL.ARTNR
    INTO :ARTNR, :LGNR, BEREINH, ART_EKNETTO
    DO
    BEGIN
      BESTAND = (SELECT BESTAND from P_GETBEST_ATDATE(:ArtNr, :LGNR, '*', '*', :DATUM));
      BEST_OHNE_RECHNUNG = (Select MENGE from P_ELPO_OHNE_RECHNG (:ARTNR, :LGNR, :DATUM));

      IF ( BESTAND is NULL ) THEN
        BESTAND = 0;
       
      IF (BEST_OHNE_RECHNUNG IS NULL) THEN
          BEST_OHNE_RECHNUNG = 0;

      LE_EK = (SELECT LE_EK FROM P_GET_LEEK_STICHTAG(:ARTNR, :LGNR, :DATUM));
      IF (LE_EK <= 0 ) THEN
        LE_EK = ART_EKNETTO;
       
      IF ((BEREINH IS NULL) OR (BEREINH = 0)) THEN
        BEREINH = 1;
   
      IF (BESTAND IS NULL) THEN
        BESTAND=0;
   
      BER_BESTAND = BESTAND - BEST_OHNE_RECHNUNG;
      IF ( BER_BESTAND < 0 ) THEN
        BER_BESTAND = 0;
         
      ART_WERT = ( BER_BESTAND * LE_EK / BEREINH);
       
      LGWERT = LGWERT + ART_WERT;

      /* Protokoll */
      INSERT INTO DBPROC(PROCNAME, ZEIT, WERT) VALUES ('P_GETLAGERWERT','NOW',
        :LGNR||';'||:ARTNR||';'||:BESTAND||';'||:BEST_OHNE_RECHNUNG||';'||:LE_EK||';'||:ART_WERT||';'||:LGWERT);
   
    END
 SUSPEND;                                                      
 
END
Wenn ich im Select die Datenmenge weiter beschränke, wird ein Wert zurückgegeben, so wie der Select jetzt steht ergibt er null. Im Protokoll ist in allen Fällen alles richtig und vollständig.

Schönen Gruß

kretabiker 3. Mai 2017 11:51

AW: Firebird Procedure liefert null
 
Ist ne Ewigkeit her, dass ich mich mit SPs unter Firebird befasst habe, aber was mir auffällt, sind die fehlenden ':' im INTO-Teil der ersten SQL-Abfrage: INTO :ARTNR, :LGNR, BEREINH, ART_EKNETTO - fehlen die nicht vor BEREINH und ART_EKNETTO?

Blup 3. Mai 2017 11:57

AW: Firebird Procedure liefert null
 
Die ":" fehlen bei den Variablen im Select.

Du prüfst zwei mal "BESTAND IS NULL" aber "LE_EK" wird nicht auf "NULL" geprüft.

bnreimer42 3. Mai 2017 12:06

AW: Firebird Procedure liefert null
 
Ich würde mal sagen, die Proc gibt nur NULL zurück, wenn
LE_EK = (SELECT LE_EK FROM P_GET_LEEK_STICHTAG(:ARTNR, :LGNR, :DATUM));
NULL ergibt.

Kann es sein, dass die Werte der Proc vom Client nicht abgerufen werden?
Wie wird die Proc im Programm aufgerufen.

jobo 3. Mai 2017 12:41

AW: Firebird Procedure liefert null
 
Zitat:

Zitat von Delix (Beitrag 1369996)
Hallo,

mit den bisherigen Antworten kann ich leider wenig anfangen, da eine meiner Aussagen nicht berücksichtigt wird:

Die Procedure läuft intern absolut korrekt ab.

Ja, das mag so sein, dass Du es protokolliert hast, aber nur für einen Fall (meinetwegen auch mehr) und Du hast bereits mehrere Antworten, wie es zu der Null kommen kann.
Am ehesten würde ich mal auf die Antwort von Jumpy tippen.
In SQL ist es idR so:
1+2+NULL=NULL

NULL steht für undefiniert, definierte Werte verrechnet oder verglichen mit undefinierten Werten ergibt immer undefiniert.
Woher kommt die NULL? Entweder eines der Felder enthält Null oder wie ich beschrieben habe führt ein Join ins Leere und "produziert" NULL Werte, die in der Berechnung alles mitreißen.

Jumpy 3. Mai 2017 12:43

AW: Firebird Procedure liefert null
 
Zitat:

Zitat von Delix (Beitrag 1369996)
Wenn ich im Select die Datenmenge weiter beschränke, wird ein Wert zurückgegeben, so wie der Select jetzt steht ergibt er null. Im Protokoll ist in allen Fällen alles richtig und vollständig.

Kannst du die Beschränkung dann nicht einmal invertieren und sehen, ob dann auch null rauskommt, um so dem Übeltäter auf die Spur zu kommen?

p80286 3. Mai 2017 13:43

AW: Firebird Procedure liefert null
 
Also die Null-Werte können wir vergessen da
SQL-Code:
  AND ar.Aktiv='J'
das [CODE=] AND ar.Aktiv is not null [/CODE] impliziert, warum dann ein LEFT JOIN ist mir auch nicht klar.

das SUSPEND hat mich stutzig gemacht. Wenn ich das Handbuch richtig verstanden habe, wäre hier ein EXIT angebrachter.

was bedeutet
Zitat:

Wenn ich im Select die Datenmenge weiter beschränke
im allg. beschränkst Du nicht die Menge sondern den Inhalt??

und was steht in Deinem Protokoll?
könnte es sein, das NULL-Sätze in der Anzeige unter den Tisch fallen?

gruß
K-H

Lemmy 3. Mai 2017 13:57

AW: Firebird Procedure liefert null
 
Zitat:

Zitat von p80286 (Beitrag 1370034)

das SUSPEND hat mich stutzig gemacht. Wenn ich das Handbuch richtig verstanden habe, wäre hier ein EXIT angebrachter.

und wie kommt dann das Ergebnis zum Client wenn nicht mit suspend?

bnreimer42 3. Mai 2017 14:59

AW: Firebird Procedure liefert null
 
Zitat:

Zitat von p80286 (Beitrag 1370034)
das SUSPEND hat mich stutzig gemacht. Wenn ich das Handbuch richtig verstanden habe, wäre hier ein EXIT angebrachter.

Nein, Suspend ist korrekt, denn damit werden die Ergebnisse an den Client gesendet, wenn er es denn nach dem SELECT wirklich abruft.

p80286 3. Mai 2017 15:42

AW: Firebird Procedure liefert null
 
Ich hab meine Weisheit von hier.
Zitat:

If the procedure is called from a EXECUTE PROCEDURE statement, then SUSPEND has the same effect as EXIT. This usage is legal, but not recommended.
Dann ist da wohl in der Zwischenzeit die Toleranz größer geworden?

Gruß
K-H

bnreimer42 3. Mai 2017 16:08

AW: Firebird Procedure liefert null
 
Zitat:

Zitat von p80286 (Beitrag 1370059)
Ich hab meine Weisheit von hier.
Zitat:

If the procedure is called from a EXECUTE PROCEDURE statement, then SUSPEND has the same effect as EXIT. This usage is legal, but not recommended.
Dann ist da wohl in der Zwischenzeit die Toleranz größer geworden?

Deshalb wäre es wichtig zu wissen, wie der Aufruf der Proc erfolgt.

Wenn die mit SELECT * FROM PROC aufgerufen wird, ist SUSPEND nötig. Und da die Proc einen Rückgabewert hat, lässt ein aktueller Firebird keine Proc ohne Suspend mehr zu.

hoika 3. Mai 2017 16:58

AW: Firebird Procedure liefert null
 
Hallo,

1.
INSERT INTO DBPROC(PROCNAME, ZEIT, WERT) VALUES ('P_GETLAGERWERT','NOW',
:LGNR||';'||:ARTNR||';'||:BESTAND||';'||:BEST_OHNE _RECHNUNG||';'||:LE_EK||';'||:ART_WERT||';'||:LGWE RT);

Kannst du das Ändern erweitern mit

if LGWERT is NULL

INSERT INTO DBPROC(PROCNAME, ZEIT, WERT) VALUES ('P_GETLAGERWERT','NOW',
:LGNR||';'||:ARTNR||';'||:BESTAND||';'||:BEST_OHNE _RECHNUNG||';'||:LE_EK||';'||:ART_WERT||';'||"NULL ")
else
das Original


Und du hast definitiv in DBProc als letzten Wert einen gültigen Wert drin?

2,
Was mich noch stutzig macht sind Deine verschiedenen Numeric(x,y)-Variablen,
probier mal komplett Double Precision.
Ab einem bestimmten Numeric(x,y) arbeitet Firebird automatisch mit Integer weiter ...

3.
es wird NULL oder 0 zurückgegeben?
Woher weisst du das?
Hast du die Query (Select * From Proc(xxx)) mal in IBExpert laufen lassen?

MichaelT 3. Mai 2017 17:09

AW: Firebird Procedure liefert null
 
Kurz mal durchgetestet.

LE_EK kleiner gleich 0 ist dann wird LE_EK NULL über ART_EKNETTO.

Alles andere kann ich so nicht sagen.

Reproduktion war einfach die Prozedur und alles NULL gesetzt. Erst wenn ich ART_EKNETTO auf 0 setzt wird das Ergebnis NOT NULL.

Ist nicht zwingend überraschend.


Zitat:

Zitat von Delix (Beitrag 1369963)

Schönen Gruß


MichaelT 3. Mai 2017 17:46

AW: Firebird Procedure liefert null
 
Eine Leerzeile vermutlich.

Zitat:

Zitat von hoika (Beitrag 1370075)
Hallo,


hoika 3. Mai 2017 19:04

AW: Firebird Procedure liefert null
 
Hallo,
Leerzeile?

aber mal weiter

Zitat:

Die Procedure läuft intern absolut korrekt ab. Das habe ich aus der Procedure heraus protokolliert. Die Rückgabe-Variable ist bis zum Schluss absolut korrekt berechnet! Da fallen joins's oder Nullwerte wohl aus.
Mach mal vorm Suspend ein LGWERT=21.0;
Und dahinter noch einen Protokolleintrag.

Kommt jetzt immer noch NULL raus als Ergebnis und steht die 21.0 im Log?

MichaelT 4. Mai 2017 11:27

AW: Firebird Procedure liefert null
 
Das ist einzige Platz in dem ein potentiell nicht initialisierter Wert zugewiesen wird.

IF (LE_EK <= 0 ) THEN
LE_EK = ART_EKNETTO;

Wäre LE_EK = NULL bspw. dann gilt die Bedingung nicht.

Soviel verbleibt nicht, als dass eine NULL zurückkäme.

Auf Businessebene ist der Satz nicht 'gültig' oder 'leer'. Testdatensätze, Fehlersätze oder wie auch immer. Zumal die ohne DATUMs Einschränkung offensichtlich zurückkommen und/oder insbesondere dann...

Auf ART_EKNETTO wird vermutlich einfach nicht hingeschreiben zuvor. NULL wird zugewiesen und das Logging liefert keine Ergebnis. So in etwas stelle ich mir das vor, rein auf Verdacht.

Zum Log
VALUE || NULL -> NULL



Code:
SET TERM ^ ;
CREATE PROCEDURE P_GETLAGERWERT (
    DATUM Date )
RETURNS (
    LGWERT Numeric(12,2) )
AS
DECLARE ARTNR VARCHAR(50);
DECLARE BEREINH NUMERIC (10,3);
DECLARE LGNR INTEGER;
DECLARE LE_EK NUMERIC (12,4);
DECLARE ART_EKNETTO NUMERIC (12,4);
DECLARE BESTAND NUMERIC (11,3);
DECLARE BER_BESTAND NUMERIC (11,3);
DECLARE BEST_OHNE_RECHNUNG NUMERIC (11,3);
DECLARE ART_WERT NUMERIC (12,3);
BEGIN
  LGWERT = 0;
 
   
    ARTNR = NULL;
    LGNR = NULL;
    BEREINH = NULL;
    ART_EKNETTO = 0;
     -- BESTAND = (SELECT BESTAND from P_GETBEST_ATDATE(:ArtNr, :LGNR, '*', '*', :DATUM));
      BESTAND = NULL;
      BEST_OHNE_RECHNUNG = NULL;
      IF ( BESTAND is NULL ) THEN
        BESTAND = 0;
       
      IF (BEST_OHNE_RECHNUNG IS NULL) THEN
          BEST_OHNE_RECHNUNG = 0;
      LE_EK = 0;
      IF (LE_EK <= 0 ) THEN
        LE_EK = ART_EKNETTO;
       
      IF ((BEREINH IS NULL) OR (BEREINH = 0)) THEN
        BEREINH = 1;
   
      IF (BESTAND IS NULL) THEN
        BESTAND=0;
   
      BER_BESTAND = BESTAND - BEST_OHNE_RECHNUNG;
      IF ( BER_BESTAND < 0 ) THEN
        BER_BESTAND = 0;
         
      ART_WERT = ( BER_BESTAND * LE_EK / BEREINH);
       
      LGWERT = LGWERT + ART_WERT;
      /* Protokoll */
   
 SUSPEND;
END^
SET TERM ; ^
GRANT EXECUTE
 ON PROCEDURE P_GETLAGERWERT TO SYSDBA;
Zitat:

Zitat von hoika (Beitrag 1370084)
Hallo,
Leerzeile?

aber mal weiter

Zitat:

Die Procedure läuft intern absolut korrekt ab. Das habe ich aus der Procedure heraus protokolliert. Die Rückgabe-Variable ist bis zum Schluss absolut korrekt berechnet! Da fallen joins's oder Nullwerte wohl aus.
Mach mal vorm Suspend ein LGWERT=21.0;
Und dahinter noch einen Protokolleintrag.

Kommt jetzt immer noch NULL raus als Ergebnis und steht die 21.0 im Log?


Jasocul 4. Mai 2017 12:40

AW: Firebird Procedure liefert null
 
Ich bin sicher nicht der Firebird-Spezi, aber was passiert eigentlich hier
Code:
(cast( al.LgNr as Integer) >0 )
wenn LgNr nicht als Integer ge-castet werden kann?

Kann es sein, dass dann für alle funktionierenden Datensätze ein Protokoll geschrieben wird, aber im Fehlerfall die SP im ungültigen Zustand abbricht und dann einen Null-Wert liefert?
Das Protokoll hätte dann zwar Daten, aber ob die vollständig sind, ist nicht geklärt, oder?


Folgendes ist mir auch noch aufgefallen:
SQL-Code:
INTO :ARTNR, :LGNR, BEREINH, ART_EKNETTO
Dort fehlen Doppelpunkte. Wurde zwar irgendwo schon geschrieben, aber ich habe keine Antwort darauf gesehen.

Die Folge könnte sein, das ART_EKNETTO Null ist.
In dem Fall wäre hierdurch
SQL-Code:
LE_EK = (SELECT LE_EK FROM P_GET_LEEK_STICHTAG(:ARTNR, :LGNR, :DATUM));
       IF (LE_EK <= 0 ) THEN
         LE_EK = ART_EKNETTO;
LE_EK auch Null, sobald LE_EK <= 0 ist.
Das muss aber wohl jemand mit genaueren Firebird-Kenntnissen klären.

MichaelT 4. Mai 2017 14:05

AW: Firebird Procedure liefert null
 
SQL-Code:
  IF (LE_EK <= 0 ) THEN
Wen LE_EK IS NULL, dann wird der Ausdruck false. Der ART_EKNETTO wird hernach nirgends mehr verwendet und auch nicht protokolliert. Ohne : gibt es keine Binding der Variable.

Selbst wenn liefert die Protokollzeile NULL durch '||'. (SQL)

Ich arbeite deswegen lieber mit Records und die innere Logik in eine eigene Funktion gepackt. Damit kann man einen Art Unittest machen.


Zitat:

Zitat von Jasocul (Beitrag 1370173)
Folgendes ist mir auch noch aufgefallen:
SQL-Code:
INTO :ARTNR, :LGNR, BEREINH, ART_EKNETTO
Dort fehlen Doppelpunkte. Wurde zwar irgendwo schon geschrieben, aber ich habe keine Antwort darauf gesehen.

Die Folge könnte sein, das ART_EKNETTO Null ist.
In dem Fall wäre hierdurch
SQL-Code:
LE_EK = (SELECT LE_EK FROM P_GET_LEEK_STICHTAG(:ARTNR, :LGNR, :DATUM));
       IF (LE_EK <= 0 ) THEN
         LE_EK = ART_EKNETTO;
LE_EK auch Null, sobald LE_EK <= 0 ist.
Das muss aber wohl jemand mit genaueren Firebird-Kenntnissen klären.



Alle Zeitangaben in WEZ +1. Es ist jetzt 15:28 Uhr.

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