NULL-data processing.

  • Themenstarter Themenstarter Guest
  • Beginndatum Beginndatum
Status
Nicht offen für weitere Antworten.
G

Guest

Gast
Hi,

weiss jemand von Euch, ob folgendes Verhalten "normal" ist oder nicht
bzw. ob es ein Standardverhalten ist?

Es gibt zwei Tabellen (TabA und TabB) mit jeweils einer Spalte, nennen wir sie
mal strField.

TabA.strField
TabB.strField

Vergleicht man zwei Zeilen, die NULL sind, miteinander (in einem Join etc.),
dann liefert die Bedingung FALSE bzw. keine Datensätze zurück.
Code:
FROM Tabelle1 TabA, Tabelle2 TabB
WHERE ...
    AND TabA.strField = TabB.strField

Prüft man, ob beide NULL sind, dann ist das Ergebnis TRUE bzw. es werden paar
Datensätze zurückgegeben.

Code:
FROM Tabelle1 TabA, Tabelle2 TabB
WHERE ...
  AND TabA.strField IS NULL 
  AND TabB.strField IS NULL

Ist es bei allen Datenbanken so? Ich verwende SAPDB.
Nach meinem Verständnis sollte NULL = NULL immer TRUE sein.
 
Übrigens, Abhilfe schafft hier folgendes.
Code:
WHERE ...
  AND (
    (TabA.strField = TabB.strField) 
    OR (TabA.strField IS NULL AND TabB.strField IS NULL)
  )
Warum ein direkter Vergleich zweier NULL-Werte nicht möglich
ist, ist mir aber ein Rätsel.
 
Code:
FROM Tabelle1 TabA, Tabelle2 TabB
WHERE ...
    AND TabA.strField = TabB.strField
In diesem Fall machst du einen Join über 2 Tabellen, das heißt beide Tabellen werden, anhand der Whereklausel, miteinander verknüpft und die Ergebnismenge wird zurück geliefert.

Code:
FROM Tabelle1 TabA, Tabelle2 TabB
WHERE ...
  AND TabA.strField IS NULL 
  AND TabB.strField IS NULL
Hier erstellst du ein Kreuzprodukt. Das bedeutet die beiden Tabellen werden ohne eine Bedingung miteinander verknüpft. Da du in der Whereklausel auf null prüfst bekommst du alle Datensätze bei denen diese Bedingung zutrifft.

P.S. SQL ist keine imperative sondern eine deklarative Sprache. Das bedeutet du definierst eine Ergebnismenge, anstatt einen konkreten Lösungsweg vorzugeben.
 
foobar hat gesagt.:
Was genau willst du denn machen?
Die Zeilen zweier "fast" gleicher Tabellen holen, die in bestimmten
Spalten übereinstimmen.
z.B.
Angenommen in Tabelle TabA steht folgendes
a=1, b=2, c=NULL, ...
In Tabelle TabB dann genau das gleiche
a=1, b=2, c=NULL, ...
Code:
WHERE TabA.a = TabB.a
  AND TabA.b = TabB.b
  AND TabA.c = TabB.c
sollte dann die Zeile mit den Spalten aus beiden Tabellen liefern.
Ist aber nicht der Fall, sobald ein Spaltenpaar NULL ist.
Für den Fall, wo sowas möglich ist, muss man immer diese
"komplizierten" Bedingungen schreiben.
Im obigen Fall
Code:
WHERE TabA.a = TabB.a
  AND TabA.b = TabB.b
  AND ((TabA.c = TabB.c) OR (TabA.c IS NULL AND TabB.c IS NULL))

Hat mich heute etwas Zeit mit dem Debugger gekostet,
dann habe ich die Abfragen erneut geprüft und bin auf
dieses Verhalten gestossen. 🙁
 
Dann mußt du einen Left-Join machen:
Code:
Select *
from taba a left join tabb b on (a.a = b.a)
where a.b = b.b
Dann bekommst du auch Datensätze in denen nulls in der zweiten Tabelle sind.
 
Nein, es liefert auch falsche Ergebnisse.

Es sind zwei, von der Struktur her, gleiche Tabellen.
Die eine ist einer Art Template-Tabelle, die andere
enthält vom Benutzer modifizierte Daten, die
ursprünglich aus der globalen Vorlage kommen.
Der Wert der Spalte, die NULL enthalten kann, hat eine
spezielle Bedeutung. NULL = überall gültig, sonst abhängig
vom Benutzer.
Jetzt soll der Anwender die Möglichkeit haben, die modifizierten
Einträge in seiner lokalen Tabelle mit denen aus der globalen
Tabelle abzugleichen, wenn sich diese von der lokalen in
irgendeiner Form unterscheiden.
Das ganze läuft teilweise interaktiv, so dass ich zuerst alle
potentiellen Kandidaten für den Abgleich finden muss.
Es gibt dann zusätzlich Einträge, die der Anwender als "readonly"
gekennzeichnet hat. Diese sollen dann ignoriert bzw. nicht
upgedated werden.

Wenn's nicht genug wäre, es gibt da noch untergeordnete Tabellen,
die bei dem Vergleich auch eine Rolle spielen. *amocklauf*
 
Aber das würde dann ja bedeuten, daß jeder Benutzer eine eigene Tabelle hat. Was wiederum bedeutet, daß wenn du einen Benutzer anlegst du auch eine Tabelle anlegen mußt. Warum machst du nicht eine Tabelle für die Userdaten mit einer Spalte, die dann einen Benutzer referenziert? Was soll denn Ziel des ganzen sein?
 
Es sind zwei Tabellen.

Die Tabelle mit den Anwender-spezifischen Modifikationen
hat einen eindeutigen Verweis (FK) auf den entsprechenden
Anwender. Es ist nicht pro Anwender eine Tabelle. Solche
Schweinereien mach' ich nicht 🙂
Eigentlich wäre es auch möglich alles in eine Tabelle zu packen,
lässt sich aber in zwei getrennten Tabellen besser verwalten.
Da sind auch unterschiedliche Leute für die Datenbankpflege zuständig.
Nicht jeder darf an den globalen Daten herumfummeln.

Wie ich schon schrieb, das hier funktioniert (auch bei den NULL-Spalten)
Code:
WHERE TabA.a = TabB.a 
  AND TabA.b = TabB.b 
  AND ((TabA.c = TabB.c) OR (TabA.c IS NULL AND TabB.c IS NULL))
Soll einfach heissen. Beide gleich oder beide NULL.

Aber wenn beide NULL sind, dann sind sie auch gleich.

OK das ganze wird langsam zu philosofisch 🙂
 
Wenn du in beiden Spalten Null-Werte hast brauchst du einen Full Left Join, damit bekommst du alle Daten egal in welcher der Tabellen nulls enthalten sind. Ich weiß aber nicht ob es diesen Join bei SAPDB gibt.
 
Ja, FULL JOIN wird in SAPDB auch unterstützt, ist aber grauenhaft langsam,
wenn die Tabellen viele Daten enthalten 🙂

Habe etwas mit der Join-Syntax experimentiert.
LEFT JOIN tut's auch und ist schnell genug.
Code:
SELECT ...
FROM Tabelle1 TabA LEFT JOIN Tabelle2 TabB ON (TabB.a = TabA.a AND TabB.b = TabA.b AND TabB.c = TabA.c)
WHERE TabA.userId = ... weitere Bedingungen

Danke. Deine Antworten haben meine grauen Zellen etwas aufgeweckt 🙂
 
Ehmmm... war quatsch. Habe bei dem Ergebnis nicht richtig hingeschaut.
Ich brauche doch die Daten aus beiden Tabellen. 😳

Es bleibt bei der Variante:
Code:
WHERE TabA.a = TabB.a 
  AND TabA.b = TabB.b 
  AND ((TabA.c = TabB.c) OR (TabA.c IS NULL AND TabB.c IS NULL))
 
Status
Nicht offen für weitere Antworten.

Zurück
Oben