PDA

View Full Version : sql update (Verständnis-)Problem



Marc_w
02-10-19, 17:07
Hallo,

ein Artikel hat mehrere verschiedene Gewichtungswerte abhängig vom Typ.
Die Tabellenstruktur sieht wie folgt aus
Artnr | Jahr | Typ | Wert

Der Schlüssel ist Artnr, Jahr, Typ

Ich möchte numerische Werte innerhalb eines Jahres von einem Typ in den Nächsten übertragen mit einer Veränderung (teilweise Addition, teilweise Subtraktion).

Mein erster Versuch des Updates vom Typ 2 in den Typ N sah wie folgt aus:


update table as a
set a.Wert=(
(select b.Wert from table as b
where b.Jahr = 2020 and b.Typ = '2' and
a.Jahr = b.Jahr and a.Artnr = b.Artnr
)+1.8
)
where a.Jahr = 2020 and a.Typ = 'N'


Dieses Update hat aber nicht immer fuktioniert und ist manchmal in einen Fehler


Nullwerte für Spalte oder Variable WERT nicht zulässig.
gelaufen.

Nach mehreren Versuchen habe ich nun diesen Update zusammengebaut:


update table as a
set a.Wert=(
(select b.Wert from table as b
where b.Jahr = 2020 and b.Typ = '2' and
a.Jahr = b.Jahr and a.Artnr = b.Artnr
)+1.8
)
where a.Jahr = 2020 and a.Typ = 'N' and
exists(select b.Wert
from table as b
where b.Jahr = 2020 and b.Typ = '2' and
a.Jahr = b.Jahr and a.Artnr = b.Artnr
)


Hier meine Fragen:
Ist der doppelt verwendete Alias "b" korrekt?
Ist durch die Verknüpfung im Subselect der SET-Klausel nicht gewährleistet, dass a und b eindeutig verbunden sind und daraus folgend Variante 1 ausreichend?
Wenn ich den Subselect alleine ausführe kommen zwar Werte wie 0,00 aber keine NULL Werte. Daraus habe ich geschlossen, dass nur zulässige Werte geschrieben werden. Woher kommen dann die Nullwerte?

Grüße

Marc

Fuerchau
02-10-19, 17:39
Für den Subselect kannst du eine Klammerstufe weglassen, da nur der Select-Ausdruck in Klammern zu setzen ist.
Ein Alias betrifft nur den jeweiligen Kontext, in deinem Fall nur die Subselects. Der eine Subselect hat mit dem Anderen nichts zu tun.

Nun zur Reihenfolge:

Die Where-Klausel des Hauptselects schließt nur die Zeilen ein, die für den Update relevant sein sollen.
Der 1. Subselect hat aber eine andere Beziehung als der Hauptwhere und somit kann es eben vorkommen, das zu dem zu ändernden Satz das Pendant gar nicht vorhanden ist. Also nicht für jeden Typ-N-Satz gibt es auch einen Typ-2-Satz.
Und genau dann kommt es zum NULL-Ergebnis.

Der 2. Subselect (exists) stellt nun sicher, das für jeden zu ändernden Satz auch ein Pendant als Quelle vorhanden ist und somit NULL-Werte ausgeschlossen werden (solange nicht NULL auf Feldebene zulässig wäre).

Du könntest den 2. Subselect weglassen, wenn du den 1. in "coalesce((select ...) + 1.8, a.Wert)" änderst. Dies führt aber u.U. zu mehr unnötigen Änderungen, da ja der Satz ohne pendant mit sich selbst überschrieben wird.

Zu guter Letzt, betrachte mal deinen Inner-Where:
where b.Jahr = 2020 and b.Typ = '2' and
a.Jahr = b.Jahr and a.Artnr = b.Artnr

Da du im Hauptwhere bereits auf 2020 einschränkst, kann die zusätzliche Einschränkung im Subselect doch entfallen.

Generell gilt beim Subselect:
Ist kein Ergebnis zu finden, wird NULL gemeldet, also genau das selbe wie auch beim Left Join.
Einen "Inner-Join"-Subselect gibt es nicht.
Es gibt daher auch immer mal wieder viele Joblog-Hinweise, dass NULL-Indikatoren fehlen:

select count(*) into : MyCount
from table
where ....

Da hierfür kein Cursor verwendet wird, betrachtet SQL dies wie einen Subselect und liefert NULL falls die Whereklausel nichts findet.
Machst du das selbe per Cursor (wie z.B. via STRSQL), bekommst du ganz normal 0 geliefert.
Besser wäre dann hier:

select coalesce(count(*), 0) into : MyCount
from table
where ....

oder eben einen NULL-Anzeiger (nicht zu vergessen, den NULL-Anzeiger abzufragen oder das Zielfeld vorher zu löschen, da es im NULL-Fall den vorherigen Wert behält).

Marc_w
14-10-19, 14:01
Hallo,

sorry für die späte Antwort. Ich hatte Schwierigkeiten mich im Forum anzumelden und nach vielen erfolglosen Versuchen es heute erst wieder probiert.
Vielen Dank für die ausführliche Antwort. Ich muss das ganze noch ein paar Mal testen/üben, bis es auch ganz verinnerlicht ist. Jedenfalls habe ich jetzt eine sehr gute Anleitung zum nachschlagen.

Grüße

Marc

Fuerchau
14-10-19, 15:29
Das Forum war leider eine Weile "out of order". Also nicht nur du konntest dich nicht anmelden.