PDA

View Full Version : SQL UDF



KingofKning
15-08-14, 14:53
Hallo *all,
ich habe mir eine UDF geschrieben die mir kundenspezifische Preise ermitteln soll.

Dummerweise läuft das Teil auf Fehler.

Fehlermeldung

Nachrichten-ID . . . . : SQL0305 Bewertung . . . . . . : 30
Nachrichtenart . . . . : Diagnose
Sendedatum . . . . . . : 15.08.14 Sendezeit . . . . . . : 15:45:56

Nachricht . . . : Anzeigervariable erforderlich.
Ursache . . . . : Eine Anweisung FETCH, eine eingebettete Anweisung SELECT,
eine Anweisung CALL, GET DESCRIPTOR, SET oder VALUES INTO hatte einen
Nullwert zur Folge, für Host-Variable SQLP_L2.RETURNVAL wurde jedoch keine
Anzeigervariable angegeben. Die relative Position der Host-Variablen in der
Klausel INTO oder der Parameterliste ist 2. Ist der Name der Host-Variablen


Die UDF sieht so aus:


CREATE FUNCTION rptrade/artpreis3
( ARTIKELNR dec(10),
Kundennr dec(10)
) RETURNS
CHAR(10) LANGUAGE SQL READS SQL DATA BEGIN
DECLARE RETURNVAL CHAR ( 10 ) NOT NULL DEFAULT '0,00' ;
DECLARE preis1 dec ( 10 ) ;
DECLARE preis2 dec ( 10 ) ;
FOR CSRC1 AS C1 CURSOR
FOR SELECT SOEIPR
FROM rptrade/artpreis1
where SOID2 = ARTIKELNR
and (sodnbi = 99999999
or sodnbi >= YEAR(CURRENT DATE)*10000 +
MONTH(CURRENT DATE)*100 +
DAY(CURRENT DATE))
order by soid2, sodnbi
desc fetch first row only
DO SET preis1 = SOEIPR;
END FOR ;
FOR CSRC1 AS C1 CURSOR
FOR SELECT SOEIPR
FROM rptrade/artpreis2
where SOID4 = ARTIKELNR
and soid1 = kundennr
and (sodnbi = 99999999
or sodnbi >= YEAR(CURRENT DATE)*10000 +
MONTH(CURRENT DATE)*100 +
DAY(CURRENT DATE))
order by soid4, sodnbi
desc fetch first row only
DO SET preis1 = SOEIPR;
END FOR ;
if preis2 > 0 then set preis1 = preis2 ; end if ;
SET RETURNVAL = cast(preis1 as char(10));
RETURN LTRIM(RETURNVAL) ;
END


Jetzt vermute ich ja mal das ein SQL Statement kein Ergebniss liefert und daher z.B. Preis2 nicht gefüllt ist.

Was will er mir mit dem Stichwort Anzeigevariable sagen?
Für Hilfe dankbar

Pikachu
15-08-14, 14:58
Guckst du hier (http://www.newsolutions.de/forum-systemi-as400-i5-iseries/threads/16089-SQL-Fehler-free-rpg)

B.Hauser
15-08-14, 16:33
Anzeiger-Variable meint meist, dass ein NULL-Wert irgendwo verwendet oder verglichen wird. Geprüft werden NULL-Werte i.d.R. über Anzeiger-Variablen.

Wo berechnest Du eigentlich Preis2?
Soweit ich das sehen kann nirgends. Preis2 wird mit einem NULL-Wert inititalisiert und anschließend wird dieser NULL-Wert mit 0 verglichen (IF Preis2 > 0) und das funktioniert nicht.

1. Initialisiere alle deklarierte Variablen
2. Anstatt das numerische Tagesdatum in den Cursorn zu berechnen würde ich eine separate variable definieren und nur einmalig initialisieren.
3. Anstatt der Cursor mit For-Schleifen würde ich ein einfaches SELECT ... INTO verwenden.
4. Sicherheitshalber würde ich den Preis über COALESCE in einen Default-Wert (z.B. 0) konvertieren.

Etwa so:

CREATE FUNCTION rptrade/artpreis3 ( ARTIKELNR dec(10),
Kundennr dec(10) )
RETURNS CHAR(10)
LANGUAGE SQL
READS SQL DATA
BEGIN
DECLARE RETURNVAL CHAR ( 10 ) NOT NULL DEFAULT '0,00' ;
DECLARE preis1 dec ( 10, 0 ) NOT NULL Default 0;
DECLARE Preis2 dec ( 10, 0 ) Not NULL Default 0;
Declare DateNum Dec( 8, 0 ) Not NULL Default 0;

Set DateNum = Dec(VarChar_Format(Current_Timestamp, 'YYYYMMDD'), 8, 0);

Select Coalesce(SOEIPR, 0) into Preis1
From RPTRADE/ArtPreis1
Where SOID2 = ARTIKELNR
and ( sodnbi = 99999999
or sodnbi >= DateNum)
order by sodnbi desc
fetch first row only;

Select Coalesce(SOEIPR, 0) into Preis2
From RPTRADE/ArtPreis2
where SOID4 = ARTIKELNR
and soid1 = kundennr
and ( sodnbi = 99999999
or sodnbi >= DateNum)
order by sodnbi desc
fetch first row only;

if Preis2 > 0 then set preis1 = Preis2;
end if ;
SET RETURNVAL = cast(preis1 as char(10));
RETURN LTRIM(RETURNVAL) ;
END

Birgitta

KingofKning
15-08-14, 17:10
Soviel zum Thema Copy & Paste. Beim 2. Select sollte natürlich Preis2 den Wert erhalten

Ich werde morgen versuchen Deine Vorschläge umzusetzen, erstmal Danke für Deine Hinweise

GG

KingofKning
16-08-14, 07:03
Hallo Birgitta,
danke für Deine Hilfe, beim testen bekomme ich jetzt die Meldung

Nachrichten-ID . . . . : SQL0171 Bewertung . . . . . . : 30
Nachrichtenart . . . . : Diagnose
Sendedatum . . . . . . : 16.08.14 Sendezeit . . . . . . : 08:01:5

Nachricht . . . : Argument 2 der Funktion VARCHAR_FORMAT ungültig.
Ursache . . . . : Datenart, Länge oder Wert des Arguments 2 der Funktion
VARCHAR_FORMAT ist ungültig.

Das müßte sich ja jetzt auf dieses Statement beziehen.
Wo kann ich die richtige Syntax nachschauen?

Set DateNum = Dec(VarChar_Format(Current_Timestamp, 'YYYYMMDD')
8, 0);

GG

Ich habe jetzt nochmal hier im Forum geschaut und h´gehofft das ich das ,8,0 weglassen könnte, das funktioniert aber leider nicht

B.Hauser
16-08-14, 15:24
Unter welchem Release arbeitest Du?
Kannst Du den VarChar_Format-Befehl interaktiv (z.B. mit STRSQL) ausführen?
In älteren Releasen ist die VarChar_Format-Funktion vielleicht noch nicht vorhanden.
Etwa so:

select Dec(VarChar_Format(Current_Timestamp, 'YYYYMMDD'), 8, 0)
From sysibm/sysdummy1

Sofern die Ausführung nicht möglich ist, musst Du das numerische Tagesdatum anderweitig ermittelt, evtl. auch so wie in Deinem ersten Beispiel, nur halt im SET-Statement.
Etwa so:

Set DateNum = Dec(Year(Current_Date) * 10000 + Month(Current_Date) * 100 + Day(Current_Date), 8, 0);

KingofKning
16-08-14, 17:03
Hallo Birgitta,
ich habe das einzig wahre OS

V5R4

vermutlich noch für 2 Jahre. TöTö TöTö TöTö Tschingbumm.
Also das 1. Statement funktioniert dort nicht.
Das 2. läuft wie angenommen
GG

KingofKning
17-08-14, 07:38
Heavy standing on the wire....

gelöst, falsche Parameterreihenfolge

Fuerchau
18-08-14, 07:33
Dann bist du ja schon mal weiter als ich:).
Ich schlage mich noch auf unabsehbare Zeit mit V5R2 und da noch nicht mal mit den letzten PTF's herum da keiner die Kiste mehr wartet.