Sonntag, Juni 09, 2013

Outer Join Einschränkungen

Eine Notiz aus dem Kontext der SQL-Grundlagen, die das Verhalten von Einschränkungen in den Klauseln ON und WHERE beim Outer Join behandelt. Sie beantwortet die Frage, wie sich eine Einschränkung der Form "Spalte=Konstante" in diesen beiden Klauseln in einem Outer Joins auswirkt. Der Bezug auf ON macht deutlich, dass hier von ANSI-Syntax die Rede ist, aber das Verhalten ist das gleiche, wenn Oracles (+)-Operator im Spiel ist. Gegeben sind zwei sehr einfache Tabellen:

-- Oracle 11.2.0.1.0; was aber keine Rolle spielen sollte
drop table t1;
drop table t2;

create table t1
as
select rownum id
  from dual
connect by level <= 10;

create table t2
as
select rownum id
     , trunc((rownum + 1)/2) col2
  from dual
connect by level <= 5;

select * 
  from t1;

        ID
----------
         1
         2
         3
         4
         5
         6
         7
         8
         9
        10

select *
  from t2;

        ID       COL2
---------- ----------
         1          1
         2          1
         3          2
         4          2
         5          3

Dabei ist t1 also doppelt so groß wie t2. Wenn ich beide Tabellen über die id-Spalten und einen Left Outer Join verknüpfe, dann erhalte ich ein Ergebnis mit den zehn Sätzen aus t1, wobei den ersten fünf Sätzen, die entsprechenden t2-Sätze zugeordnet sind:

select t1.id
     , t2.id
     , t2.col2
  from t1
  left outer join
       t2
    on t1.id = t2.id
 order by t1.id;

   ID         ID       COL2
----- ---------- ----------
    1          1          1
    2          2          1
    3          3          2
    4          4          2
    5          5          3
    6
    7
    8
    9
   10

So weit ist das keine Überraschung. Was aber passiert, wenn ich eine zusätzliche Einschränkung für die zweite Spalte col2 in einer WHERE-Bedingung ergänze?

select t1.id
     , t2.id
     , t2.col2
  from t1
  left outer join
       t2
    on t1.id = t2.id
 where t2.col2 = 1
 order by t1.id;

   ID         ID       COL2
----- ---------- ----------
    1          1          1
    2          2          1

Eine solche Query ist ein ziemlich klares Indiz dafür, dass der Autor nicht genau wusste, was er tat, denn durch die zusätzliche Bedingung wird der Outer Join nutzlos: hier wird zunächst der (Outer) Join erzeugt und anschließend erfolgt die Filterung auf die Ergebnissätze, die der zusätzlichen Bedingung entsprechen. Da aber alle Sätze aus t1, zu denen es in t2 keine Entsprechung gab, für die t2-Spalten NULL-Werte enthalten, kann keine von ihnen der zusätzlichen Bedingung genügen. Die Query liefert also notwendigerweise das gleiche Ergebnis, das ein Inner Join der Tabellen liefern würde. Um die Filterung von t2 vor dem Outer Join durchzuführen (bzw. eigentlich in ihm), muss die Einschränkung in der ON-Klausel erfolgen:

select t1.id
     , t2.id
     , t2.col2
  from t1
  left outer join
       t2
    on t1.id = t2.id and t2.col2 = 1
 order by t1.id;

   ID         ID       COL2
----- ---------- ----------
    1          1          1
    2          2          1
    3
    4
    5
    6
    7
    8
    9
   10

Nachtrag 17.04.2014: inzwischen ist mir klar geworden, dass die hier vorgestellte Interpretation zumindest unvollständig ist - wie hier nachzulesen ist.

Keine Kommentare:

Kommentar veröffentlichen