View Full Version : SQL set oder select into mit dynamischer Selektion
Deine komplizierte Abfrage ist da schon eher mit Dieters Beispiel "between" ablösbar.
Schade, dass Dir mein Beispiel zu kompliziert ist!
Dieters Abfrage wird nur die Zeilen auswählen die auch einen echten Wert haben, jedoch nicht die Zeilen, die einen NULL-Wert haben.
Wenn Du also von *LOVAL zu *HIVAL alles selektierst gehen Dir die NULL-Werte durch die Lappen, d.h. Du musst zusätzlich eine IS NULL-Abfrage hinzufügen um alle Sätze zu bekommen!
... und genau das umgehe ich mit dem IS NOT DISTINCT FROM!
Die darauffolgende CASE-Anweisung sorgt nur dafür, dass entweder nur der übergebene Wert oder eben alle Werte (inkl. NULL-Werten) ausgewählt werden.
Ansonsten hätte schon mein erstest Beispiel mit der CASE-Anweisung wahlweise die ausgewählten Werte oder alle Zeilen zurückgebracht (da hätte man Deine Lösung, die i.Ü. Dieter Schröder gleich in der ersten Antwort gebracht hat, und die abgelehnt wurde nicht nochmal gebraucht!)
... und außerdem ist nicht jedes Eingabe-Feld alphanumerisch, was jeweils in Deiner Lösung auch korrekt berücksichtigt werden sollte!
Das war m.E. die ursprüngliche Frage, die anschließend nochmal korrigiert wurde, nämlich dahingehend, dass bei NICHT-Eingabe alles ausgewählt wird.
Was man durch ein bei 64 Auswahlen wahrscheinlich wesentlich komplizierteres dynamisches SQL lösen wollte.
Bei der (gnadenlosen) Konvertierung mit COALESCE (in den WHERE-Bedingung) kann nicht mehr sauber zwischen NULL-Wert und Default-Wert unterschieden werden.
Da in dem ursprünglichen Beispiel lediglich ein Count(*) ausgeführt wird, werden grundsätzlich alle Sätze gezählt und ein COALESCE ist unnötig. Bei nicht gefunden wird auch nichts ausgegeben!
... aber Du hast recht warum sollte man alles verkomplizieren (z.B. mit dynamischem SQL und/oder Indikator-Variablen, die dann in 64 IFs geprüft und genauso in 64 Zeilen gesetzt werden müssen) wenn man es auch einfach haben kann?
Nun ja, er sprach von 64 Kombinationen und nicht von 64 Variablen.
Von NULL-Werten war nicht die Rede und es zeigt, dass du meine Variante nicht verstanden hast, denn ich wollte keine NULL-Werte abfragen.
Es wurde auch interpretiert, dass die Variablen Inhalte haben könnten, die aber nicht relevant wären, was man eben mit NULLInd lösen kann, da dann der Inhalt nicht zählt.
DISTINCT löst auch nur das Gleichheitsproblem, allerdings nicht Vergleiche mit Like, <, >, usw.
Was hast du also gegen (:P = ('' | 0) or Feld = :P), wobei das = eben auch mit allen anderen Vergleichen funktioniert. Ich habe sogar schon (:P = '' or Feld in Split(:p:P, ',')) ausgeführt um Mehrfachauswahlen zu lösen. P enthält dann eine kommaseparierte Liste von Werten.
Phänomenal das Ganze. Und jetzt schreib nicht wieder, dass es Split so nicht gibt. Das weiß ich ja.
Und wenn du NULL haben willst, füge doch einfach einen "or Feld is Null" hinzu.
Und bevor du fragst: ('' | 0) soll heißen typgerecht entweder '' oder 0.
Und was solls. Es ist doch einfacher einen statischen SQL zu bauen, der alle Variablen enthält und die Prüfung ob relevant ganz einfach ist als einen dynamischen SQL zu bauen, der auch auch die verschiedenen Varianten abfragen muss um ihn zu bauen und außerdem nicht mit Parametern sondern mit Stringkonstanten arbeiten muss, %edit, oder das O'Hara-Problemen lässt grüßen.
Auch CCSID-Probleme mit Unicode (1200) oder SBCS (1141) kommen noch dazu, was Parameter eben erleichtern. Du müsstest den prepared String nämlich besser als Unicode (1200) aufbauen.
Ich baue meine Abfragen schon seit Jahrzehnten genau so auf und erstaunlicherweise funktionieren sie auch noch schnell.
... ich bin immer für einfache Lösungen: Nullvalues sind Datenbank interne Konstrukte und haben in den externen Sichten nix verloren. Die werden im Viewlayer rausmaskiert.
D*B
Vielen Dank für die vielen Ausführungen.
Unser Entwickler hat sich für die 'between' Variante entschieden.
Performance ist OK
Warum *Count!
Der Anwender kann in einem Subfile Im CTRL-Satz für jede Spalte einen Filter setzen
Ist der Filter leer, ist der Feldinhalt egal
Bei 6 Spalten sind also 64 Kombinationen möglich.
Im Kopf steht i.d.R wieviel Sätze betroffen sind.
Im Subfile wird Seitenweise mit Fetch eingelesen.
NULL Werte haben wir nicht.
Also bilden wir 2 sql, eins mit Count(*), das wir dank eurer Hilfe jetzt lösen konnten und eins
das wir entsprechend der gewählten Selektion bilden und mittels declare / Prepare / Fetch lesen.
Leider haben wir die Lösung von Herrn Fuerchau nicht verstanden.
Lt. Entwicker hat er verschiedenes getestet (2 Werte) aber nicht das ergebnis bekommen.
Vielen Dank
Dietlinde Beck
NULL Werte haben wir nicht.
Dietlinde Beck
... verwendet ihr keine joins?
Noch eine Anmerkung zu dem count: wenn während der Ausführung Sätze eingefügt, oder gelöscht werden, dann stimmt der count nicht mit dem Resultset überein.
D*B
dschroeder
02-10-25, 09:40
Ich habe die Lösung von Baldur zunächst auch nicht verstanden. Aber ich habe mal die KI gefragt. Die konnte es mir erklären.
Mein bisheriges Wissen war, dass man Null-Indikatoren beim Fetch angeben kann, damit das System darin mitteilen kann, ob ein gelesenes Feld NULL ist.
Was ich nicht wusste ist, dass es umgekehrt auch geht. Ich kann hinter eine Hostvariable (z.B. im where) einen Null-Indikator schreiben, um dem System damit zu sagen, dass die Hostvariable den Wert NULL hat. Das ist notwendig, wenn die Hostvariable selber nicht NULL-fähig ist.
Ich hoffe, ich habe es richtig verstanden und korrekt beschrieben.
Das hast du nun korrekt verstanden;-).
Das geht nicht nur beim Where sondern auch beim Insert oder Update.
Im Gegensatz zu Dieter bin ich überzeugt, dass NULL-Werte durchaus Sinn machen.
Bei Aggregaten werden NULL's z.B. ignoriert und belasten vor allem Min/Max/Avg/STDV o.ä. eben nicht.
Ich kann aber 0 nicht generell ausschließen.
NULL heißt eben "nicht existent", so nach dem Motto beim Auswählen: Ja, Nein, Weiß nicht.
Ich habe die Lösung von Baldur zunächst auch nicht verstanden. Aber ich habe mal die KI gefragt. Die konnte es mir erklären.
Mein bisheriges Wissen war, dass man Null-Indikatoren beim Fetch angeben kann, damit das System darin mitteilen kann, ob ein gelesenes Feld NULL ist.
Was ich nicht wusste ist, dass es umgekehrt auch geht. Ich kann hinter eine Hostvariable (z.B. im where) einen Null-Indikator schreiben, um dem System damit zu sagen, dass die Hostvariable den Wert NULL hat. Das ist notwendig, wenn die Hostvariable selber nicht NULL-fähig ist.
Ich hoffe, ich habe es richtig verstanden und korrekt beschrieben.
Das wird gebraucht, um NULL values zu erzeugen.
Nehmen wir mal ein kleines, typisches Beispiel:
- im Auftragskopf steht eine Kundennummer
- für dieses Feld erlaube ich Null values
- dann lege ich eine referential constraint drauf, die schützt, dass da keine Kundennummern reinpassen, die es nicht gibt.
- füge ich einen Barverkauf ein, dann hat der keinen Kunden
- dafür brauche ich dann in manchen Programmiersprachen (RPG) eine Krücke, da null reinzuschreiben.
et voila!
Beim Vergleich (where clause) ist "where Feld = null" nicht erlaubt, das muss dann "where feld is null" heißen.
Wenn der Compiler oder die runtime das anders sieht und das nicht merkt, dann ist das nicht "schön" sondern "doof".
Wenn das jemand trotzdem benutzt, dann ist das nicht "clever", sondern "blöd", weil das nicht mehr funzt, wenn der Compiler und/oder die runtime den Fehler beheben. Dann ist auch beschweren, dass das früher doch ging, zwar einen Versuch wert, bringt aber nix.
D*B
Das hast du nun korrekt verstanden;-).
Das geht nicht nur beim Where sondern auch beim Insert oder Update.
Im Gegensatz zu Dieter bin ich überzeugt, dass NULL-Werte durchaus Sinn machen.
Bei Aggregaten werden NULL's z.B. ignoriert und belasten vor allem Min/Max/Avg/STDV o.ä. eben nicht.
Ich kann aber 0 nicht generell ausschließen.
NULL heißt eben "nicht existent", so nach dem Motto beim Auswählen: Ja, Nein, Weiß nicht.
Lieber Baldur,
ich bin seit (gefühlt) 1870 Verfechter von Null values und referential constraints und habe das in zahlreichen SQL Kursen gepredigt und Ignoranten ausgeschiimpft (in vielen Beiträgen in Foren zu finden).
Schönen Tag noch
Dieter
Ich habe noch nicht erlebt, dass man NULL anders als "is Null" gezielt abfragen kann.
Allerdings hilft dies eben ungemein mit NULL gezielt zu vergleichen, wenn man das als negatives Ergebnis wünscht.
Besonders wenn man dies dann auch noch mit Or-Klauseln verknüpft.
Beispiel left join vs. inner join:
select *
from filea a
inner join fileb b on ...
inner join filec c on ...
where b.Feld = 'X'
or c.Feld = 'Y'
Wir wissen nun, dass Inner join nur die Zeilen selektiert, die auf beiden Seiten vorhanden sind.
Somit liefert das Ergebnis nur die Zeilen, die in fileb und in filec vorhanden sind.
Wenn aber in fileb oder in filec Zeilen auch fehlen dürfen, muss ich halt left join verwenden.
select *
from filea a
left join fileb b on ...
left join filec c on ...
where b.Feld = 'X'
or c.Feld = 'Y'
Weiterhin gilt, dass b.Feld = 'X' sein muss. Wenn aber die b.Zeile fehlt, ist b.Feld dann NULL und somit wird b.Feld(Null) = 'X' negativ und die Or-Bedingung wird geprüft.
Lange Rede kurzer Sinn:
Ein Vergleich NULL mit Irgengwas ist legitim und kann mittles NULL-Anzeiger im RPG gezielt ebenso verwendet werden.
Wenn du eine Prozedur/Funktion schreibst und Variablen deklarierst, können diese eben auch NULL haben, wenn du NOT NULL nicht anwendest.