Information ausblenden
Willkommen im Forum für alle Datenbanken! Registriere Dich kostenlos und diskutiere über DBs wie Mysql, MariaDB, Oracle, Sql-Server, Postgres, Access uvm

Outer Join mit (+)

Dieses Thema im Forum "Oracle" wurde erstellt von Kanubelkarl, 28 Dezember 2014.

  1. Kanubelkarl

    Kanubelkarl Benutzer

    Hi, ich habe gerade ein kleines Problem mit einem Statement das icht nicht ganz verstehen, also bräuchte eine erklärung.

    Die einfache Variante die ich auch verstehe ist
    select artikelnummer, artikel from artikel
    where lieferant not in (select lieferant_ID from lieferant where ort = 'Berlin')
    or lieferant is null;

    Also das mir alle Artikelnummern mit Artikel angezeigt werden, wo der Lieferant nicht aus Berlin ist, oder die keinen Lieferant haben. Jetzt habe ich noch ein Statement das schneller gehen soll.

    select a.artikelnummer, a.artikel, from artikel a, lieferant l
    where a.lieferant = l.lieferant_ID (+)
    and l.lieferant_id is null
    and l.ort (+)= 'Berlin'
    order by a.artikelnummer;

    laut unserem Lehrer soll beides Funktionieren, jedoch ist mit nicht klar wieso das funktioniert.
    PS:Mein Lehrer weis es auch nicht so recht

    Grüße
    Kanubelkarl
     
  2. akretschmer

    akretschmer Datenbank-Guru


    Das erstere ist ein Subselect, das andere ein Join. Joins sind oft, nicht immer, schneller. Schau Dir das Explain zu beiden Varianten an, dann wirst Du wohl unterschiedliche Pläne und Kosten sehen.
     
  3. Kanubelkarl

    Kanubelkarl Benutzer

    Ok, aber beim zweiten ist habe ich immer noch etwas Problem beim verstehen. Die WHERE beginnt ja mit einem join zwischen den Tabellen Artikel und Lieferant. Aber dann werden durch das "and l.lieferant_id is null" ja nur die joins genommen bei denen die id null ist, dann durch "and l.ort(+)= 'Berlin" alle bei deinen der ort Berlin ist oder keiner vorhanden ist. Aber ich will ja eigentlich die, wo der Lieferant nicht aus Berlin ist, oder die keinen Lieferant haben.
     
  4. akretschmer

    akretschmer Datenbank-Guru

    Ich komme, um ehrlich zu sein, mit dieser kruden Oraggle (+) - Syntax nicht klar. Im Where steht zum einen die Join-Condition und zum anderen das 'klassische' Where. Irgendwie sieht das verwirrend aus, ich habe auch kein Oraggle, um das zu testen.

    Für das, was Du willst, sehe ich (mindestens) diese 2 Wege, die 'richtige' SQL-Syntax sind:

    Code:
    test=*# select * from lieferant ;
     lieferant_id |  ort
    --------------+---------
      1 | Berlin
      2 | Dresden
    (2 rows)
    
    test=*# select * from artikel ;
     artikelnummer | artikel  | lieferant
    ---------------+----------+-----------
      1 | artikel1 |  1
      2 | artikel2 |  2
      3 | artikel3 |
    (3 rows)
    
    test=*# select artikelnummer, artikel from artikel where lieferant not in (select lieferant_id from lieferant where ort = 'Berlin') or lieferant is null;
     artikelnummer | artikel
    ---------------+----------
      2 | artikel2
      3 | artikel3
    (2 rows)
    
    test=*# select a.artikelnummer, a.artikel from artikel a left join lieferant l on a.lieferant=l.lieferant_id where l.ort != 'Berlin' or a.lieferant is null;
     artikelnummer | artikel
    ---------------+----------
      2 | artikel2
      3 | artikel3
    (2 rows)
    
     
  5. Distrilec

    Distrilec Datenbank-Guru

    Und das funktioniert auch ? (Ausprobiert?)

    Das sollte das Equivalent sein:
    Code:
    Select a.artikelnummer,
           a.artikel
    From   artikel a
    Where  l.lieferant_id Is Null
    Left Join lieferant l On a.lieferant = l.lieferant_id
    And  l.ort = 'Berlin'
    Order by a.artikelnummer;
    Und ich würde bezweifeln dass das funktioniert ^^

    (Aber man bedenke... Ich hatte noch keinen Kaffee)
     
  6. Distrilec

    Distrilec Datenbank-Guru

    Code:
    Select a.artikelnummer,
           a.artikel
    From   artikel a,
           lieferant l
    Where  a.lieferant = l.lieferant_id(+)
    And    l.lieferant <> 'Berlin'
    Order  By a.artikelnummer;
    So... Das sollte funktionieren :)
     
  7. Kanubelkarl

    Kanubelkarl Benutzer

    So, ich habe mir jetzt extra nochmal Oracle drauf gemacht und alles durch getestet.
    Es funktionieren beide Statements mit gleichem ergebnis. Aber ich versteh einfach nicht, wie das zweite Funktioniert.

    select a.artikelnummer, a.artikel, from artikel a, lieferant l
    where a.lieferant = l.lieferant_ID (+)
    and l.lieferant_id is null
    and l.ort (+)= 'Berlin'
    order by a.artikelnummer;

    Angezeigt werden alle Artikelnummern mit Artikel, bei denen der Lieferant nicht aus Berlin ist, oder die keinen Lieferant haben.
     
  8. Distrilec

    Distrilec Datenbank-Guru

    Ich hätte dir geglaubt, wenn du geschrieben hättest:
    "Angezeigt werden alle Artikelnummern mit Artikel, bei denen der Lieferant keinen Ort zugewiesen hat oder der Lieferant Null ist."

    Aus der Oracle Doku :)

    "If the WHERE clause contains a condition that compares a column from table B with a constant, then the (+) operator must be applied to the column so that Oracle returns the rows from table A for which it has generated nulls for this column."
    Quelle: http://docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm#SQLRF52338
     
  9. Kanubelkarl

    Kanubelkarl Benutzer

    Ja, so habe ich das auch gedacht, was auch Funktioniert, nur wird bei meinem statement das irgentwie umgekehrt. Ich habe jetzt mal alles aus meiner Datenbank raus kopiert

    SQL> select * from lieferant;

    LIEFERANT_ID NAME STRASSE HAUSN PLZ ORT

    -------------------------------- --------------- ------------------------- ----- ---------- -------------------------

    AAA Berlini Berlinerweg 17 12345 Berlin
    BBB Schlosser Schlosserweg 18 23456 Schlosserhausen
    CCC Fischer Fischersteig 19 34567 Fischerdorf

    SQL> select * from artikel;

    ARTIKELNUMMER ARTIKEL ANZAHL LIEFERANT
    ------------- ------------------------------ ---------- ---------------------------------
    10000 Rasenmäher Schafherde CCC
    10001 Rasenmäher Nagelschere BBB
    10002 Rasenmäher Elektro BBB
    10003 Rasenmäher Hand BBB
    10100 Heckenschere Elektro BBB
    10101 Heckenschere Hand klein BBB
    10102 Heckenschere Hand Teleskop BBB
    10103 Heckenschere Benzin BBB
    11000 Pflanze Heckenrose AAA
    11001 Pflanze Kletterrose AAA
    11002 Pflanze Rose rot AAA
    11003 Pflanze Rose gelb AAA
    11100 Pflanze Tulpe weiß AAA
    11101 Pflanze Tulpe gelb AAA
    11102 Pflanze Tulpe rot AAA
    11103 Pflanze Tulpe dunkelrot AAA
    12000 CCC
    12001 Rindenmulch klein
    12002 Blumenerde klein
    12003 Blumenerde groß


    SQL> select artikelnummer, artikel from artikel
    2 where lieferant not in
    3 (select lieferant_id from lieferant where ort ='Berlin')
    4 or lieferant is null;

    ARTIKELNUMMER ARTIKEL
    ------------- ------------------------------
    10000 Rasenmäher Schafherde
    10001 Rasenmäher Nagelschere
    10002 Rasenmäher Elektro
    10003 Rasenmäher Hand
    10100 Heckenschere Elektro
    10101 Heckenschere Hand klein
    10102 Heckenschere Hand Teleskop
    10103 Heckenschere Benzin
    12000
    12001 Rindenmulch klein
    12002 Blumenerde klein
    12003 Blumenerde groß


    SQL> select a.artikelnummer, a.artikel from artikel a, lieferant l
    2 where a.lieferant = l.lieferant_id (+)
    3 and l.lieferant_id is Null
    4 and l.ort (+)= 'Berlin'
    5 order by a.artikelnummer;

    ARTIKELNUMMER ARTIKEL
    ------------- ------------------------------
    10000 Rasenmäher Schafherde
    10001 Rasenmäher Nagelschere
    10002 Rasenmäher Elektro
    10003 Rasenmäher Hand
    10100 Heckenschere Elektro
    10101 Heckenschere Hand klein
    10102 Heckenschere Hand Teleskop
    10103 Heckenschere Benzin
    12000
    12001 Rindenmulch klein
    12002 Blumenerde klein
    12003 Blumenerde groß
     
    Zuletzt bearbeitet: 5 Januar 2015
  10. Distrilec

    Distrilec Datenbank-Guru

    Mit etwas Kaffee geht alles :)

    Selektiert alle Artikel und (wenn Ort = 'Berlin') werden Lieferantendaten hinzugefügt
    Code:
    Select a.*, l.*
    From  artikel a,
      lieferant l
    Where  a.lieferant = l.lieferant_id
    And  l.ort (+) = 'Berlin';
    Selektiert davon nur die Artikel, die keine Lieferant_Id haben
    Code:
    Select a.*, l.*
    From  artikel a,
      lieferant l
    Where  a.lieferant = l.lieferant_id
    And  l.ort (+) = 'Berlin'
    And  l.lieferant_id Is Null;
    (Zur veranschaulichung habe ich noch das l.* hinzugefügt. Wird dann beim ausführen etwas ersichtlicher.)

    Hier vllt. nochmal etwas "aufgedröselt" als equivalentes Left Join:
    Code:
    Select t.*
    From  (Select a.*, l.*
      From  artikel a
      Left Join lieferant l
      On  a.lieferant = l.lieferant_id
      And  l.lieferant_id = 'Berlin') t
    Where  t.lieferant_id Is Null;
     
  11. Kanubelkarl

    Kanubelkarl Benutzer

    Ah, vielen dank, ich hab es endlich verstanden.
    Im Grunde wird durch das l.ort (+) = 'Berlin' als Ort Berlin genommen und bei allen anderen steht sozusagen NULL in den Lieferantenfeldern, und mit l.lieferant_id is Null werden dann die Einträge raus genommen die noch Berlin drin stehen haben
    Also vielen dank für die Hilfe
     
  12. Distrilec

    Distrilec Datenbank-Guru

    Kein Problem :)
     
Die Seite wird geladen...

Diese Seite empfehlen

  1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies.
    Information ausblenden