Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Datenbanken (https://www.delphipraxis.net/15-datenbanken/)
-   -   Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN (https://www.delphipraxis.net/203926-interbase-merkwuerdiges-verhalten-bei-left-outer-join.html)

HeZa 7. Apr 2020 17:19

Datenbank: Interbase • Version: 2017 • Zugriff über: IBDAC

Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Hallo,

ich verliere gerade ein bisschen den Glauben daran das Interbase in Bezug auf LEFT OUTER JOIN korrekt arbeitet. Folgendes Script
Code:
create table test (id int);

insert into test (id) values (1);

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t1.id = 1
  left outer join test t3 on t3.id = t1.id and t1.id = 1;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t1.id = 0
  left outer join test t3 on t3.id = t1.id and t1.id = 0;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t1.id = 1
  left outer join test t3 on t3.id = t1.id and t1.id = 0;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t1.id = 0
  left outer join test t3 on t3.id = t1.id and t1.id = 1;

drop table test;
Erwarten würde ich, dass mir die 4 SELECTs folgendes Ergebnis liefern:
Code:
SELECT ID1, ID2, ID3
   1    1    1    1
   2    1   NULL NULL
   3    1    1   NULL
   4    1   NULL  1
Das ist zu mindestens auch das was ich auf der Seite SQL Fiddle für jede angebotene Datenbank erhalte. Interbase 2017 liefert mir nun folgendes Ergebnis:
Code:
SELECT ID1, ID2, ID3
   1    1    1    1
   2      <no row>
   3      <no row>
   4    1   NULL  1
Was ist hier los? Wie sieht das bei Firebird aus (reines interesse)? Die Zugrffskomponenten sind raus, ich habe das mit IBExpert (IBDAC) und SQL Workbench /J (JAVA) geteste. Beides mal das gleiche Ergebnis. Auch wenn man 3 verschiedene Tabellen nimmt, ändert sich nichts.

Kann da einer Licht in diese dunkle Stunde bringen?

Ciao HeZa

Uwe Raabe 7. Apr 2020 18:08

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Das Verhalten finde ich zumindest auch merkwürdig. SQL-Server liefert das erwartete Ergebnis. Interbase 2020 kann ich auch nur mit dieser Version das erwünschte Ergebnis entlocken:
SQL-Code:
select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t2.id = 1
  left outer join test t3 on t3.id = t1.id and t3.id = 1;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t2.id = 0
  left outer join test t3 on t3.id = t1.id and t3.id = 0;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t2.id = 1
  left outer join test t3 on t3.id = t1.id and t3.id = 0;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id and t2.id = 0
  left outer join test t3 on t3.id = t1.id and t3.id = 1;
Ich finde, das sollte zumindest mal im QP gemeldet werden.

Delphi.Narium 7. Apr 2020 18:09

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
FireBird 3.0 liefert das von Dir erwartete Ergebnis.

Getestet mit FlameRobin.

FlameRobin kann doch auch Interbase, wenn ich mich recht erinnere.

mkinzler 7. Apr 2020 18:59

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Liste der Anhänge anzeigen (Anzahl: 2)
Fb 3.0.5:

p80286 7. Apr 2020 19:03

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Wie wäre es mal Klammern zu setzen?
wenn
SQL-Code:
 test t1
  left outer join test t2 on t2.id = t1.id and t1.id = 1
  left outer join test t3 on t3.id = t1.id and t1.id = 0;
als
SQL-Code:
test t1
  left outer join test t2 on t2.id = t1.id
  left outer join test t3 on t3.id = t1.id
 where
  t1.id = 0 and and t1.id = 1;
interpretiert wird, kann ich das Ergebnis verstehen.

Gruß
K-H

jobo 8. Apr 2020 00:58

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Also ich muss zugeben, ich finde das Ergebnis von interbase gar nicht so schlecht. (Ist natürlich etwas schwammig) Bedeutet, alle anderen Ergebnisse finde ich auch eher falsch!

Ich kann mir vorstellen, dass es eigentlich nicht wirklich definiert ist, was da raus kommen soll, denn die gängigen Definitionen der Outer Joins betreffen ja erstmal die JOIN Kriterien untereinander. Hier ist das Kriterium erweitert und zwar als Filter, nicht als Join...
Hab mir jetzt nicht die Mühe gemacht, nach den ANSI Definitionen zu suchen.

Ich muss aber andererseits auch sagen, ich würde nie auf die Idee kommen, ein solches Select Statement wie im P1 zu schreiben. Der Vorschlag von p80286 geht da in Richtung meiner Bedenken.

Die Left Join Condition für sich genommen, bringt ja erstmal kein Problem. Und die Erweiterung der Left Join Condition auf mehr Kriterien dient ja in der Regel dazu, auf elegante Art eine Filter für die rechte Seite anzugeben (unter Wahrung des gewollten Outer Effects > alle Datensätze der linken Seite werden angezeigt auch ohne passenden rechten Datensatz).

Wenn man LEFT JOIN so nutzen wollte, wie ich es verstehe, besonders bezogen auf den 2. Teil der jeweiligen JOIN Clause, dann würde man hier jeweils ein Kriterium angeben, das auch die "OUTER" Table betrifft und dann würde man das in P1 erwartete Ergebnis erhalten. Das Statement sähe so aus wie Uwe Raabe umformuliert hat.

Die in P1 dargestellten Selects wären m.E. analog zu:

PHP-Quellcode:
select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t2.id = t1.id
  left outer join test t3 on t3.id = t1.id
where t1.id = 1
  and t1.id = 1;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t1.id = t2.id
  left outer join test t3 on t1.id = t3.id
 where t1.id = 0
   and t1.id = 0;


select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t1.id = t2.id
  left outer join test t3 on t1.id = t3.id
 where t1.id = 1
   and t1.id = 0;


select t1.id as id1, t2.id as id2, t3.id as id3 from
  test t1
  left outer join test t2 on t1.id = t2.id
  left outer join test t3 on t1.id = t3.id
 where t1.id = 0
   and t1.id = 1
Und damit wäre auch das IB Ergebnis nicht ok... :|


Demokratisch gesehen sprechen einige DB gegen das was ich schreibe. Ich bin aber auch nicht ganz auf der Seute von IB. Dass es Ergebnis 2 als leere Menge darstellt, okay. Dass Ergebnis 3 ebenfalls leer ist, könnte man argumentieren, Ergebnis 4 ist dann aber inkonsistent zu 3.

p80286 8. Apr 2020 11:35

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Zitat:

Outer join syntax requires that you specify the type of join to perform. There are three possibilities:

A left outer join retrieves all rows from the left table in a join, and retrieves any rows from the right table that match the search condition specified in the ON clause.
Wenn man es genau liest, dann hat T1.ID=irgendwas an der angegebenen Stelle nichts zu suchen. Wenn andere DB damit klarkommen, sie sind halt anders.

Gruß
K-H

Uwe Raabe 8. Apr 2020 13:16

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Ich denke auch, das ist interpretationsfähig. Eine klare Vorgabe das irgendwie umzusetzen kann ich auch nirgendwo finden.

Delphi.Narium 8. Apr 2020 13:48

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Irgendwie ist mir eigentlich garnicht klar, was genau gewünscht ist.
SQL-Code:
create table test (id int);

insert into test (id) values (1);

create view v1_1 as select * from test t1 where t1.id = 1;
create view v1_0 as select * from test t1 where t1.id = 0;
create view v1_1_0 as select * from test t1 where t1.id = 1 or t1.id = 0;

select t1.id as id1, t2.id as id2, t3.id as id3 from
  v1_1 t1 -- mit der Beispieltabelle eigentlich eher sinnfrei
  left outer join test t2 on t2.id = t1.id
  left outer join test t3 on t3.id = t1.id; -- steht alles schon im ersten left ...

select t1.id as id1, t2.id as id2, t3.id as id3 from
  v1_0 t1 -- mit der Beispieltabelle eigentlich eher sinnfrei
  left outer join test t2 on t2.id = t1.id
  left outer join test t3 on t3.id = t1.id; -- steht alles schon im ersten left ...

select t1.id as id1, t2.id as id2, t3.id as id3 from
  v1_1_0 t1 -- mit der Beispieltabelle eigentlich eher sinnfrei
  left outer join test t2 on t2.id = t1.id
  left outer join test t3 on t3.id = t1.id; -- steht alles schon im ersten left ...

-- hier müsste man mit 'nem "drumgelegten" select ggfls. noch Sätze mit gleicher id1 zusammenfassen
-- sum, max ... und group by id1
select t1.id as id1, t2.id as id2, null as id3 from
  v1_1 t1
  left outer join test t2 on t2.id = t1.id
union
select t1.id as id1, null as id2, t3.id as id3 from
  v1_0 t1
  left outer join test t3 on t3.id = t1.id;

oder

oder

oder

...
Das Beispiel ist zwar geeignet um festzustellen, dass x und y zum gleichen Ergebnis kommen, während z was anders behauptet, aber es ist nicht geeignet um zu verifizieren ob überhaupt eines der Ergebnis der umzusetzenden Aufgabenstellung entspricht, geschweige denn nach sinnvollen und verifizierbaren Alternativen zu suchen.

Bitte einfach mal die Aufgabenstellung verbal beschreiben, dann können wir weitersehen, welche Lösungsmöglichkeiten existieren.

Heimlich 8. Apr 2020 15:56

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Zitat:

Zitat von p80286 (Beitrag 1461546)
Wie wäre es mal Klammern zu setzen?

Erstmal das erledigen.
Danach bitte noch dem LEFT OUTER JOIN mitteilen, dass es auch ein LEFT OUTER JOIN ist.

p80286 8. Apr 2020 17:43

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1461595)
Irgendwie ist mir eigentlich garnicht klar, was genau gewünscht ist.

Einfach nur formale Spielerei?
Eine Tabelle mit einem Datensatz und zwei Aliassen(?) ist ja eher sinnfrei.

Und ich glaube was er erreichen wollte hat der TE erreicht. Diskussion

Zitat:

Danach bitte noch dem LEFT OUTER JOIN mitteilen, dass es auch ein LEFT OUTER JOIN ist.
??? was meinst Du damit? gibt es da noch irgendwelche Fehler?

Gruß
K-H

jobo 8. Apr 2020 19:07

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Ich bin mir nicht sicher, ob man die Fragen von Heimlich ernst nehmen muss.

Laut Eröffnungspost hat Uwe Raabe ja bereits ein adaptiertes Statement gezeigt, das die Daten liefert, die der TE erwartet. Die Sache könnte hier zuende sein.

Ob es nun mehr um Erwartungen geht oder mehr um Grundsatzfragen oder Fehleranalyse oder freudiges Tüfteln kann man derzeit nicht genau erkennen.

Ich könnte an der Stelle anführen, dass es sich um einen "Best Practice Fall", eine best practice Verletzung sozusagen. Die Verwendung von Left Outer Joins wird hier nicht im gedachten Sinne, also nicht ausgetestet, nicht wie gedacht eingesetzt.

HeZa 9. Apr 2020 13:17

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Hallo,

erst mal allen vielen Dank.

Ich hatte gehofft, dass es einen simplen Work Around gibt. Darum hatte ich den Hinweis zu Klammern auch gleich mal ausprobiert. Das ändert aber leider nicht das Ergebnis.

Das Beispiel was ich gezeigt habe war so reduziert, um die Problematik zu zeigen.

Warum ich so etwas verwenden wollte, hängt mit den Gegebenheiten des Datenbankdesigns zusammen. Ich erspare es mir jetzt Gründe aufzuzählen warum manchmal eine komplexe SQL-Abfrage einer Änderung des Datenbankdesigns vorgezogen wird.

Für die Interessierten folgt ein SQL-Script, das die Auslösende Problematik besser wieder gibt. Die Basis Tabelle hat ein Referenzfeld. Diese Referenz kann abhängig von einem Typ-Feld auf zwei verschieden Tabellen verweisen, deren Ids auch noch die gleichen Werte haben können.

Interessant dabei ist, dass das 2. SELECT von Interbase mit einer Fehlermeldung quitiert wird und nur das 3.SELECT zum von mir erwarteten Ergebnis führt.
Code:
create table test (id int, ref_typ int, ref int);
create table test_1 (ref1 int, data1 int);
create table test_2 (ref2 int, data2 int);
 
insert into test (id, ref_typ, ref) values (1, 1, 1);
insert into test (id, ref_typ, ref) values (2, 2, 1);
insert into test (id, ref_typ, ref) values (3, 1, null);
insert into test (id, ref_typ, ref) values (4, 2, null);
insert into test_1 (ref1, data1) values (1, 100);
insert into test_2 (ref2, data2) values (1, 200);
 
-- führt zum erwarteten Ergebniss in MySQL, Oracle, PostgreSQL, SQLite, MS-SQL
select
  id, ref_typ, ref, coalesce(data1, data2) as data
from
  test
  left outer join test_1 on ref1 = ref and ref_typ = 1
  left outer join test_2 on ref2 = ref and ref_typ = 2;
 
-- führt zum erwarteten Ergebniss in MySQL, Oracle, PostgreSQL, SQLite, MS-SQL
select
  id, ref_typ, ref,
  case
    when ref_typ = 1 then (select data1 from test_1 where ref1 = ref)
    when ref_typ = 2 then (select data2 from test_2 where ref2 = ref)
  end as data
from
  test;
 
-- führt zum erwarteten Ergebniss in MySQL, Oracle, PostgreSQL, SQLite, MS-SQL, Interbase
select
  t.id, t.ref_typ, t.ref,
  case
    when t.ref_typ = 1 then (select t1.data1 from test_1 t1 where t1.ref1 = t.ref)
    when t.ref_typ = 2 then (select t2.data2 from test_2 t2 where t2.ref2 = t.ref)
  end as data
from
  test t;
 
drop table test;
drop table test_1;
drop table test_2;
Ich verwende jetzt eine Variante des 3. SELECT. Finde ich nicht schön, funktioniert aber.

Ciao HeZa

jobo 9. Apr 2020 17:45

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Ah, jetzt versteht man sogar wofür das Ganze.

Es ändert nichts an meiner Auffassung, ich würde solche Joins nicht machen. (Mit der Idee im Hirn, vielleicht jetzt schon, aber nein)
Interessant finde ich Deine Anmerkungen zur bevorzugten Lösung. Am Ende ist ja das, was Du wollen würdest und womit Du Dich abfinden musst doch relativ nah aneinander. Nicht was den Join angeht, aber die "Vorverarbeitung" zur Ausgabe des finalen Wertes.

Einmal entscheidet NULL über die Auswahl des ausgegebenen Wertes,
einmal ein separates Feld.

Auch wenn die Funktion (coalesce versus case) unterschiedlich ist, der Mechanismus ist nahezu gleich.
Die CASE Variante ist sogar aufschlussreicher für die Nachwelt (würde ich sagen).

jobo 10. Apr 2020 08:32

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Was mir noch eingefallen ist:
Vielleicht findest Du auf den Outer Tables (rechte Seite) Ersatzfelder für das Flag.
Annahme wäre, dass man nicht aus Spaß zwei unterschiedliche Tabellen referenziert, was sich am Ende auch in Struktur und Inhalte niederschlagen sollte.
Damit könntest Du dann den Vorschlag von Uwe verfolgen. Das typisierende Outerjoin Kriterium, das jetzt noch nach links zeigt, auf die "Muttertabelle", ersetzen durch einen "äquivalenten" TypIndikator in der Outertabelle rechts. Muss natürlich 100 Pro wasserdicht sein.
Dann hättest, was Du haben willst.

Jumpy 14. Apr 2020 12:02

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Ich verstehe bei der ganzen Konstruktion nicht, warum es nötig ist bei den Joins auf den Ref-Typ Bezug zu nehmen. Warum den Join einschränken?

SQL-Code:
select
  id, ref_typ, ref,
  case when ref_typ=1 then test_1.data else test_2.data end as data
from test
  left outer join test_1 on ref1 = ref
  left outer join test_2 on ref2 = ref
Sollte doch je nachdem performanter sein als die vielen Subselects der Variante 3.

HeZa 14. Apr 2020 14:05

AW: Interbase: Merkwürdiges Verhalten bei LEFT OUTER JOIN
 
Zitat:

Zitat von Jumpy (Beitrag 1461995)
Sollte doch je nachdem performanter sein als die vielen Subselects der Variante 3.

Genau so ist es. Deswegen hatte ich auch im Endeffekt so umgesetzt.


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:36 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz