PDA

View Full Version : SQL - Wie bekomme ich die Genauigkeit hin?



Seiten : [1] 2

Lucky662
26-07-22, 13:58
Dieser SQL funktioniert wie erwartet:

select 367.4400/5.00 as EK from SYSIBM.sysdummy1;
Das Ergebnis ist 73.488!

Ich habe unter 7.3 im SQL folgendes Problem:
EKPR as (select POS,
HERK,
KALKZ,
sum(MENGE*EK) as SUMEK,
sum(MENGE) as SUMMENG,
case when sum(MENGE) != 0
then sum(EK*MENGE)/sum(MENGE)
end as EKPR
from POSB
group by POS,
HERK,
ALKZ),
REKPR as (select POIDPO,
HERK,
ALKZ,
EKPR,
SUMEK/SUMMENG as REKPR
from EKPR)
select * from REKPR


Das Ergebnis ist:
EKPR REKPR
73,48 73,48

Obwohl bei Abfrage auf EKPR
SUMEK : 367,4400 und
SUMMENG: 5,00
als Ergebnis geliefert wird.

Es sollte doch 73,488 zurückgeliefert werden! (siehe oben)

Woran kann das liegen?

Es ist egal ob ich die Abfrage im STRSQL absetze oder im RUNSQLSTM von Client Access Solution.

Fuerchau
26-07-22, 14:49
Wie sind die Feldtypen genau? Es werden in den Zwischenergebnissen z.T. große Felder erstellt, die dann relativ viele NK haben.
Bei der Division kann es dann zu Kürzungen der Nachkomma geben.

Andreas_Prouza
26-07-22, 14:52
Also der Vergleichsoperant "!=" ist in SQL mit "<>" anzugeben.
Du hast in der CASE Anweisung auch ein ELSE.
Beides führt zu ungewolltem Verhalten.

lg Andreas

Lucky662
26-07-22, 14:59
EK ist packed 9,2!
Ich habe die Lösung aber jetzt doch gefunden :)
float(sum(EK*MENGE))
Es ist dann egal ob ich in einer Rechnung dividiere oder erst hinterher.

Lucky662
26-07-22, 15:02
Hi Andreas,
das != wird nur vom Greenscreen nicht akzeptiert, da müsste es ^= sein.
Aber ich glaube auch dass liegt am Zeichensatz.
LG Andreas

Fuerchau
26-07-22, 16:41
!= wird im IBM i SQL inzwischen wie <> behandelt.
Float ist ein schechter Cast da dieser nur 7-stellig genau ist. Double wäre da besser, da es 15 Stellen kann.
Zusätzlich wäre dann noch ein round(...) empfehlenswert.

Lucky662
27-07-22, 08:36
Danke für den Hinweis auf double. Für den round() mach ich das Ganze ;), da vorher die Ergebnisse auf 2 Stellen abgeschnitten wurden und somit bei 73.488 nur 73.48 anstatt 73.49 raus kam.

Fuerchau
27-07-22, 13:02
Das Problem ist, dass für die Summenfelder ggf. das Maximum als Zwischenergebnis verwendet wird, also Dec(31, 2).
Bei Dec(31, 2) / Dec(31, 2) gibt es leider zu wenig Nachkommastellen.
Wenn man allerdings weiß, dass die Summe nicht größer als 15 Stellen haben wird, ist es besser diese zu casten, also dec(sum(....), 15, 2).
Dann klappt es auch mit der Division. Vorteil: Double ist im Nachkommabereich relativ ungenau.

Nachtrag zur Performance:

case when sum(MENGE) != 0
then sum(EK*MENGE)/sum(MENGE)
end as EKPR

ersetzen durch:
sum(EK*MENGE)/nullif(sum(MENGE), 0) as EKPR

Lucky662
27-07-22, 14:20
Habe ich dann im EKPR, wenn die sum(Menge) = 0 ist, als Ergebnis 0 oder null?

Fuerchau
27-07-22, 17:35
Da dein Case keinen Else hat ist da auch das Ergebnis NULL.
Wenn du im Ergebnis 0 brauchst, dann geht das wiederum so:

coalesce( sum(EK*MENGE) / nullif(sum(MENGE), 0), 0 ) as EKPR