SQL-Befehle in Abfragen: Join Verbindung von Tabellen (Join) Die bisher betrachteten Beispiele haben sich jeweils nur auf eine Tabelle bezogen. Im Folgenden geht es um Select-Abfragen, die ihre Ergebnisse aus verschiedenen Tabellen beziehen. Eine wichtige Anforderung an relationale Datenbanken ist die Zerlegung der Informationen in verschiedene Tabellen. Dazu dient der Prozess der Normalisierung (1.-3. Normalstufe). Durch Abfragen werden die Informationen, die auf verschiedene Tabellen verteilt sind, zusammengeführt. Bei der Arbeit mit Access haben Sie gesehen, wie die Verbindung der Tabellen durch Beziehungen erfolgt (1:1 und 1:n-Beziehungen); die Tabellen werden über Primär- und Fremdschlüssel miteinander verbunden. Dass es Primär- und Fremdschlüssel in den Tabellen gibt, ist auch für Abfragen mittels SQL Vorbedingung. Die Verbindung der Tabellen muss aber durch entsprechende Befehle erfolgen, bzw. innerhalb des Select-Befehls muss dem Datenbanksystem mitgeteilt werden, welche Verbindung zwischen den Tabellen besteht - SQL "weiß" ja nichts vom Beziehungsfenster in Access, in welchem wir bisher die Beziehungen hergestellt und grafisch dokumentiert haben. Wenn Tabellen miteinander in Beziehung gesetzt werden, dann gibt es oft dieselben Feldnamen in Tabelle A und Tabelle B. Auch wenn es keine Anforderung an die Verbindung von Tabellen durch Primär- und Fremdschlüssel ist, dass die Felder, über die man die Verbindung herstellt, den selben Namen haben, dann macht man es oft der Übersichtlichkeit halber. Um klar zu machen, um welches Feld aus welcher Tabelle es sich handelt, muss dann entweder immer der komplette Tabellenname zusätzlich angegeben werden, abgetrennt durch einen Punkt, oder (besser) man verwendet Aliasnamen für die Tabellen. In der Regel verfährt man dabei so, dass man den Tabellennamen durch einen Buchstaben abkürzt, also z. B. die Tabelle Artikel durch A. (Beachten Sie den Unterschied: Die Aliasnamen, die wir bisher verwendet hatten, bezogen sich auf Spaltenüberschriften). Das folgende Beispiel zeigt dies, zunächst noch nicht auf die Verbindung von Tabellen bezogen. Sie sehen dabei an der linken Spalte mit Alias, dass der Aliasname A für die Tabelle Artikel erst in der zweiten Zeile vergeben wird, nachdem man ihn schon der ersten Zeile verwenden konnte! ohne Aliasname Verwendung von Aliasname für Tabelle SELECT Artikel.Bezeichnung from Artikel; SELECT A.Bezeichnung from Artikel A; Die Verwendung von Aliasnamen spart dann auch Zeit: Die Tabellen bekommen einen Buchstaben als Alias zugewiesen. Dann kann immer mit dem Buchstaben auf die Tabelle verwiesen werden, wenn gesagt werden muss, aus welcher Tabelle ein Feld stammt. Vor allem bei Abfragen, die aus vier, fünf oder mehr Zeilen bestehen (mit where- und having-Klauseln usw.), in denen immer wieder die Feldnamen angesprochen werden müssen, ist dies wichtig. Die folgenden Beispiele beziehen sich auf die Datenbank Firma, die mit Access erstellt wurde. Testen Sie dazu zunächst den sogenannten Cross Join, in dem jedes Feld der einen Tabelle mit der anderen Tabelle verbunden wird (kartesisches Produkt). Das Ergebnis macht tatsächlich keinen Sinn, weil alles mit jedem verbunden wird: SELECT A.Bezeichnung, L.Lieferant from Artikel A,Lieferant L; usw., 36 Zeilen bei 12 Artikeln und drei Lieferanten jeder Lieferant steht bei jedem Artikel! 1 Bezeichnung Lieferant Haube für Tastatur Meyer OHG Haube für Tastatur Computer-Versand Haube für Tastatur Schmitz AG Disketten 3 1/2 DD Meyer OHG Disketten 3 1/2 DD Computer-Versand Disketten 3 1/2 DD Schmitz AG SQL-Befehle in Abfragen: Join Wenn die Gleichsetzung über das Feld, welches in beiden Tabellen vorkommt (Lieferantennummer), gemacht wird, dann ist ein sinnvolles Ergebnis zu sehen. Man nennt es Equi Join: Bezeichnung Lieferant Haube für Tastatur Meyer OHG from Artikel A, Lieferant L Disketten 3 1/2 DD Meyer OHG where A.Lieferantennummer=L.LiefNr; Maus seriell Meyer OHG Monitor VGA Meyer OHG Centronics-Kabel Meyer OHG mit der where-Klausel wird die Gleichsetzung Disketten 5 1/4 HD Computer-Versand erzielt: Tastatur deutsch Computer-Versand Die Zeilen werden angezeigt, wo die LiefnumDisketten 3 1/2 HD Computer-Versand mer der Tabelle Lieferant gleich der Lieferan- Motherboard ASUS A7 V3 Schmitz AG tennummer der Tabelle Artikel ist Disketten 5 1/4 DD Schmitz AG Farbband AX 35 Schmitz AG Farbband AX 55 Schmitz AG SELECT A.Bezeichnung, L.Lieferant Vorsicht: Die einschränkende Bedingung durch die where-Klausel reicht nicht aus, wo nach bestimmten Daten gesucht wird. Angenommen, Sie wollen die Artikelbezeichnung und den Lieferantennamen anzeigen, und zwar nur für die Artikel, die von Lieferant Meyer OHG geliefert werden. Bezeichnung Haube für Tastatur Disketten 3 1/2 DD Disketten 5 1/4 HD Motherboard ASUS A7 V3 Maus seriell Die Einschränkung durch die where-Klausel reicht Disketten 5 1/4 DD nicht aus. Es wird das Cross Join gebildet, und bei Tastatur deutsch Monitor VGA jedem Artikel wird Meyer OHG angezeigt Farbband AX 35 es sind alle Artikel, bei jedem steht Meyer OHG! Farbband AX 55 Disketten 3 1/2 HD Centronics-Kabel SELECT A.Bezeichnung, L.Lieferant from Artikel A, Lieferant L where L.Lieferant="Meyer OHG"; Lieferant Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG So ist es richtig: Equi Join, dann mit and die Einschränkung auf den einen Lieferanten: SELECT A.Bezeichnung, L.Lieferant from Artikel A, Lieferant L where A.Lieferantennummer=L.LiefNr and L.Lieferant="Meyer OHG"; Bezeichnung Lieferant Haube für Tastatur Meyer OHG Disketten 3 1/2 DD Meyer OHG Maus seriell Meyer OHG Monitor VGA Meyer OHG Centronics-Kabel Meyer OHG Genauso suchen Sie auch nach einem ganz bestimmten Artikel, für den Daten aus den beiden Tabellen benötigt werden: SELECT A.Bezeichnung, L.Lieferant from Artikel A ,Lieferant L where A.Lieferantennummer=L.LiefNr and A.Bezeichnung="Haube für Tastatur"; Bezeichnung Lieferant Haube für Tastatur Meyer OHG Die folgende Abfrage sucht nach den Artikelnummern von dem Lieferanten, der im Ort Sprockhövel ansässig ist: SELECT A.Artikelnummer,L.Lieferant from Artikel A, Lieferant L where A.Lieferantennummer=L.LiefNr and L.Ort="Sprockhövel" 2 Artikelnummer 129 206 282 391 639 Lieferant Meyer OHG Meyer OHG Meyer OHG Meyer OHG Meyer OHG SQL-Befehle in Abfragen: Join Die allgemeine Form des Equi Join lautet also: 2 beliebige Felder in zwei Tabellen in denen ein Feld (Feld2) gleiche Einträge hat SELECT Tabelle1.Feld1, Tabelle2.Feld3 FROM Tabelle1, Tabelle2 WHERE Tabelle1.Feld2 = Tabelle2.Feld2 Die Felder, die in der ersten Zeile mit Select ausgewählt werden, müssen nicht unbedingt aus beiden Tabellen stammen, dann aber ein Teil der Bedingung – sonst läge gar kein Join vor. Sehen Sie dazu folgendes Beispiel: Aufgabe: Wie lauten Artikelnummer und Bezeichnung von den Artikeln, deren Lieferantennummer 25 ist und von denen mehr als 100 Stück vorrätig sind? Artikelnummer Bezeichnung SELECT A.Artikelnummer,A.Bezeichnung 206 Disketten 3 1/2 DD from Artikel A, Lieferant L 208 Disketten 5 1/4 HD where A.Lieferantennummer=L.LiefNr 331 Disketten 5 1/4 DD and L.LiefNR=25 352 Tastatur deutsch and A.Menge>100 452 Farbband AX 35 463 Farbband AX 55 530 Disketten 3 1/2 HD Die Verbindung kann sich natürlich über mehr als zwei Tabellen erstrecken. Durch eine SQL-Abfrage sollen Artikelbezeichnung und Name des Kunden von den Verkaufsdaten angezeigt werden, wo der Kunde namens Hartfiel etwas gekauft hat. Dazu muss das Beziehungsmodell der Datenbank herangezogen werden: Sie sehen dabei, dass die Verbindung von Kunde zu Artikel über die beiden Tabellen Verkauf und Verkaufdetails läuft. Deshalb müssen in der Abfrage alle Verbindungen aufgeführt werden: SELECT A.Bezeichnung, K.Name, VD.Menge from Artikel A, Kunde K, Verkauf Vk, VerkaufDetails VD where Vk.Kundennummer = K.Kundennummer and Vk.VerkaufNr = VD.VerkaufNr and Vd.Artikelnummer=A.Artikelnummer and K.Name="Hartfiel" 3 Bezeichnung Name Menge Centronics-Kabel Hartfiel 50 SQL-Befehle in Abfragen: Join Versuchen Sie nun, die folgenden Beispiele zur Datenbank Firma zu lösen: 1. Wie lautet die Adresse des Lieferanten, der den Artikel mit der Nummer 129 liefert? Lieferant Straße PLZ Ort Meyer OHG Haßlinghauser Straße 89 43320 Sprockhövel 2. Wer hat nach dem 15.08.01 etwas bestellt? (Vorsicht: in der SQL-Version, die in Access zur Anwendung kommt, muss das Datum in der Form #8/15/2001# (Monat/Tag/Jahr) angegeben werden) Name Grieswelle Hartfiel Schäfer Schäfer Bestelldatum 12.11.01 30.09.01 25.09.01 13.10.01 3. An welchem Datum hat der Kunde mit der Nummer 10903 etwas bestellt? Bestelldatum 13.05.01 20.05.01 30.06.01 4. Welcher Kunde hat Artikel mit einem Einzelverkaufspreis über 100 Euro bestellt? Name Handke Hillmann 5. Der Mindestbestand und die Artikelbezeichnung von den Artikeln, die Meyer OHG liefert, soll aufgelistet werden. Mindestbestand 10 15 20 50 10 Bezeichnung Haube für Tastatur Disketten 3 1/2 DD Maus seriell Monitor VGA Centronics-Kabel 6. Welcher Lieferant liefert welche bruchempfindlichen Artikel? Lieferant Schmitz AG Meyer OHG Meyer OHG Bezeichnung Motherboard ASUS A7 V3 Monitor VGA Centronics-Kabel Centronics-Kabel sind normalerweise nicht bruchempfindlich, aber so sind sie in der Tabelle gespeichert! 7. Name und Anschrift des Kunden, der ein Farbband gekauft hat (Achtung: Es gibt zwei Sorten Farbbänder) Name Grieswelle Handke Hillmann Schäfer Straße Uferweg 9 Wörterweg 19 Kölner Straße 80 Bergstraße 7 PLZ 50983 80702 40217 60321 Ort Köln München Düsseldorf Frankfurt 8. Artikelbezeichnung, Name des Kunden, gekaufte Menge und Gesamtpreis (Verkaufspreis mal Menge sowie die Mehrwertsteuer von 16 % von den Verkaufsvorgängen, bei denen Nettopreis mal verkaufte Menge über 2000 Euro lag. Bezeichnung Name Menge Motherboard ASUS A7 V3 Motherboard ASUS A7 V3 Maus seriell Hillmann Handke Schäfer 10 3 30 4 Gesamtprei s 9800 2940 2250 MWSt 1568 470,4 360 SQL-Befehle in Abfragen: Join Bezeichnung Name Menge Centronics-Kabel Grieswelle 100 Gesamtprei s 2327 MWSt 372,32 Lösungen zu den Aufgaben S. 24: 1. SELECT L.Lieferant, L.Straße, L.PLZ, L.Ort from Lieferant L, Artikel A where A.Lieferantennummer=L.LiefNr and A.Artikelnummer=129; 2. SELECT distinct K.Name, VK.Bestelldatum FROM Kunde AS K, Verkauf AS VK, Verkaufdetails AS VD WHERE K.Kundennummer=VK.Kundennummer AND VK.VerkaufNr=VD.VerkaufNr AND VK.Bestelldatum>#8/15/2001#; 3. SELECT Vk.Bestelldatum from Kunde K, Verkauf VK where K.Kundennummer=VK.Kundennummer and K.Kundennummer=10903; 4. SELECT distinct K.Name FROM Artikel A, Kunde K, Verkauf Vk, VerkaufDetails VD WHERE Vk.Kundennummer=K.Kundennummer And Vk.VerkaufNr=VD.VerkaufNr And Vd.Artikelnummer=A.Artikelnummer and A.Einkaufspreis>100; 5. SELECT A.Mindestbestand, A.Bezeichnung FROM Lieferant L, Artikel A WHERE A.Lieferantennummer=L.LiefNr And L.Lieferant="Meyer OHG"; 6. SELECT L.Lieferant, A.Bezeichnung FROM Lieferant L, Artikel A, Lager LG WHERE A.Lieferantennummer=L.LiefNr and LG.Artikelnummer=A.Artikelnummer And LG.bruchempfindlich=-1; 7. Select distinct K.Name, K.Straße, K.PLZ, K.Ort from Kunde K, Artikel A, Verkauf VK, Verkaufdetails VD where K.Kundennummer= VK.Kundennummer and Vk.Verkaufnr=VD.Verkaufnr and Vd.Artikelnummer=A.Artikelnummer and A.Bezeichnung like "Farbband*"; 8. Select A.Bezeichnung, K.Name, vd.Menge, A.Verkaufspreis*VD.Menge as Gesamtpreis, A.Verkaufspreis*VD.Menge*0.16 as MWSt from Kunde K, Artikel A, Verkauf VK, Verkaufdetails VD where K.Kundennummer= VK.Kundennummer and Vk.Verkaufnr=VD.Verkaufnr 5 SQL-Befehle in Abfragen: Join and Vd.Artikelnummer=A.Artikelnummer and VD.Menge*A.Verkaufspreis>2000; Verbindung von Tabellen: Outer Join Die Select-Abfrage über verbundene Tabellen ist bisher so erfolgt, wie es der Tabellenverbindung mit relationaler Integrität entspricht. Die SQL-Syntax nach ANSI-Standard sieht darüber hinaus auch den Outer Join vor, womit sich Daten erfragen lassen, die teilweise sogar außerhalb dessen liegen, was in relationaler Integrität verbundene Tabellen zulassen. Aufgabe: Erstellen Sie in Access eine neue Datenbank namens Join. Erfassen Sie diese beiden kleinen Tabellen namens Kunde und Bestellung. Vergleichen Sie die Daten in folgenden beiden Tabellen. Es gibt ein Feld BestellNr, über welches eine Verbindung zwischen den Tabellen hergestellt werden kann. Aber es gibt nicht pro Kunde eine Bestellung (z. B. die Kunden Hilmayer und Jagomir mit den Bestellnummern 127 und 145 sind ohne Bestellung), und umgekehrt ist für die Bestellung 112, 114 und 121 kein Kunde vorhanden. Der erste Fall ist in einer relationalen Datenbank noch nicht zu beanstanden: Es muss möglich sein, Kunden aufzunehmen, die im Moment noch keine Bestellung aufgegeben haben. Aber der umgekehrte Fall ist nicht verantwortbar im Sinne der Eindeutigkeit und der Kongruenz zwischen den Daten: Es darf kein „verwaiste“ Bestellung geben, von der man nicht mehr weiß, welcher Kunde sie aufgegeben hat. Wenn relationale Integrität in der Beziehung zwischen den Tabellen vorliegt, dann ist es auch gar nicht möglich, diese Daten aufzunehmen. Falls Sie aber Daten in einer Datenbank antreffen, zwischen denen die Verhältnisse nicht so eindeutig liegen, wie es eigentlich sein sollte, dann muss es zumindest möglich sein, die Datensätze herauszusuchen, denen ein Pendant in der anderen Tabelle fehlt. In einer SQL-Abfrage ist die Verbindung zwischen den Tabellen über ein Equi Join (s. S. 19 dieses Skripts) folgende: 1. Name Bestellnr Schmitz 120 Manz 125 SELECT ku.Name, Be.Bestellnr from Kunde as ku, Bestellung as be where ku.bestellnr=be.bestellnr; So sind zunächst nur die Daten zu finden, bei denen es eine Übereinstimmung in beiden Tabellen über das gemeinsame Feld Bestellnr gibt. Um auch die Daten in der Kundentabelle herauszufinden, für die keine Bestellung vorliegt – oder umgekehrt, um die Bestellungen zu finden, für die kein Kunde bekannt ist – wird das Outer Join benötigt. 6 SQL-Befehle in Abfragen: Join Die Bedeutung des Outer Join kann man sich so vorstellen: Welche Daten liegen außerhalb (=outer) dessen, was in einer voll übereinstimmenden Beziehung zwischen den Tabellen vorkommt. Dabei unterscheidet man zwischen dem Left outer Join und Right outer join links bzw. rechts außerhalb liegende Verbindung Links und rechts kann man sich dabei durchaus räumlich vorstellen: In der Abbildung vorige Seite oben steht die Tabelle Kunde links. „Left outer Join“ heißt dann: Stelle eine Verbindung her, bei der die Daten der links stehenden Tabelle Kunde voll einbezogen werden (also auch Kunden ohne Bestellung). Natürlich hätten die Tabellen in der Abbildung auch vertauscht sein können, es kommt tatsächlich darauf an, welche Tabelle zuerst erwähnt in der Abfrage genannt wird. In der ANSI-Syntax bedeutet: • LEFT OUTER JOIN Schließt sämtliche Zeilen aus der ersten Tabelle und nur die zutreffenden Zeilen aus der zweiten Tabelle ein • RIGHT OUTER JOIN Schließt sämtliche Zeilen aus der zweiten Tabelle und nur die zutreffenden Zeilen aus der ersten Tabelle ein • FULL OUTER JOIN (funktioniert nicht in Access) Schließt sämtliche nicht zutreffenden Zeilen aus beiden Tabellen ein Im Abfrage-Entwurfsbildschirm von Access sehen Sie die möglichen Verknüpfungen so beschrieben: Equi Join Left outer Join Right outer Join Aufgabe: Erstellen Sie eine Abfrage in der SQL-Ansicht des Abfragefensters. Erstellen Sie die left outer join-Abfrage: Ergebnis: Name Bestellnr Schmitz 120 Müller Manz 125 Hilmayer Jagomir SELECT ku.Name, Be.Bestellnr from Kunde as ku left outer join Bestellung as be on ku.bestellnr=be.bestellnr; Im Gegensatz dazu liefert die right outer Join-Abfrage folgendes Ergebnis: Name Bestellnr 112 SELECT ku.Name, Be.Bestellnr from Kunde as ku 7 SQL-Befehle in Abfragen: Join right outer join Bestellung as be on ku.bestellnr=be.bestellnr; Schmitz Manz 114 120 121 125 Was mit "rechts" und was mit "links" angesprochen wird, hängt nur davon ab, was man in welcher Reihenfolge anspricht. In der folgenden Abfrage ist die Tabelle Bestellung links: SELECT Be.Bestellnr, ku.Name FROM Bestellung AS be left outer JOIN kunde as ku ON ku.bestellnr=be.bestellnr; Bestellnr Name 112 114 120 Schmitz 121 125 Manz Sehen Sie sich an und testen Sie, was geschieht, wenn man nur die Wörter "left" und "right" vertauscht: SELECT ku.Name, Be.Bestellnr FROM Kunde AS ku LEFT JOIN Bestellung AS be ON ku.bestellnr=be.bestellnr; Bestellnr Name 120 Schmitz Müller 125 Manz Hilmayer Jagomir Aufgabe: Öffnen Sie die Datenbank Biblio2. Gegenüber der vorher verwendeten Datenbank Biblio sind hier einige Änderungen durchgeführt: ⇒ Aus dem Haffmanns Verlag (Nr 9) und aus dem Verlag Milson & Boons gibt es keine Bücher ⇒ Die Bücher mit der Kattalognummer 108 und 109 haben keinen Datensatz in der Tabelle Katalog. Außerdem haben Sie keinen Eintrag als Verlag (Feld VerlagNr) in der Tabelle Bücher. ⇒ Das Buch Die Firma von John Grisham ist mit Verlag Nr 11 aufgenommen, für den es keine Entsprechung in der Verlagstabelle gibt (Verlag 11 existiert nicht). ⇒ In der Tabelle Buchgruppe gibt es eine KategorieNr 4 (Horror), dafür ist kein Buch eingetragen. 1) Führen Sie zunächst einen Cross Join (Verbindung jedes Datensatzes mit jedem Datensatz aus der anderen Tabelle) durch. Es sollen das Feld Verlag aus der Tabelle Verlag und das Feld Titel aus der Tabelle Bücher angesprochen werden. Das Ergebnis macht tatsächlich keinen Sinn, weil die Zuordnung von Buch zu Verlag nicht deutlich wird. 8 SQL-Befehle in Abfragen: Join 2. Führen Sie die Equi-Join-Abfrage durch (Tabellen Verlag und Titel) . Man soll dadurch sehen könnnen, welches Buch von welchem Verlag geliefert wird. Blättern Sie nach unten, um zu sehen, dass das Buch "Die Firma" von John Grisham nicht erscheint. Einschränkung auf einen Verlag: 3. Titel Ergänzen Sie jetzt die Abfrage so, dass nur die verlag Bücher aus dem Rowohlt Verlag (Nr 2) ausgewählt Rowohlt Leichen leben länger Rowohlt Mord auf der Reeperbahn werden. Left outer Join: 4. Machen Sie jetzt die Abfrage, bei der man alle Titel Bücher mit dem dazugehörigen Verlag sieht, SQL Server 7.0 Flash 5.0 auch die Bücher ohne Verlag: Verlag Erkenntnis und Interesse Suhrkamp ... ... Die Firma left outer Join – Verlag links 5. Vertauschen Sie rechts und links, indem Sie Verlag verlag nach links nehmen und auch die Verlage ohne Bücher .... Fischer im Ergebnis sehen: Titel .... Außenseiter Haffmanns Milson & Boons right outer join: Verlag rechts 6. Machen Sie die Abfrage mit demselben Ergebnis, aber Titel so, dass Sie die Titel wieder links sehen: .... Verlag ..... Außenseiter Fischer Haffmanns Milson & Boons Gruppe katalognummer .... ... Krimi 768 Krimi 720 Horror 7. Verbinden Sie in einer Abfrage die Tabellen Buchgruppe und Katalog, sodass man auch die Kategorie "Horror" sieht, für die keine Bücher vorhanden sind: 8. Verlag Abfrage in der Verbindung Verlag – Titel, aber nur für Titel Volkswirtschaftslehre Fischer die Verlage Fischer und Haffmanns: Außenseiter 9. Titel und Verlag von den Büchern, die entweder von Christie geschrieben wurden oder von denen der verlag Milson & Boons ist: 9 Titel Mord im Orientexpress Hercule Poirot's Weihnachten Poirot's letzter Fall Fischer Haffmanns Verlag Scherz Scherz Scherz Milson & Boons SQL-Befehle in Abfragen: Join Lösungen S. 25 - 26: 1. SELECT ve.verlag, bu.Titel from verlag ve, bücher bu; 2. SELECT ve.verlag, bu.Titel FROM verlag AS ve, bücher AS bu where bu.verlagnr=ve.verlagnr 3. SELECT ve.verlag, bu.Titel FROM verlag AS ve, bücher AS bu where bu.verlagnr=ve.verlagnr and ve.verlagnr=2; 4. SELECT bu.Titel, ve.Verlag FROM Bücher AS bu LEFT outer JOIN Verlag AS ve ON bu.VerlagNr=ve.VerlagNr; 5. SELECT ve.verlag, bu.Titel FROM Verlag AS ve LEFT outer JOIN Bücher AS bu ON Ve.VerlagNr=Bu.VerlagNr; 6. SELECT bu.Titel, ve.Verlag FROM Bücher AS bu RIGHT outer JOIN Verlag AS ve ON bu.VerlagNr=ve.VerlagNr; 7. SELECT bg.Gruppe, ka.katalognummer FROM Buchgruppe AS bg LEFT outer JOIN Katalog AS ka ON bg.kategorienr=ka.kategorienr; 8. SELECT bu.Titel, ve.Verlag FROM Bücher AS bu RIGHT JOIN Verlag AS ve ON bu.VerlagNr=ve.VerlagNr where ve.verlag="Fischer" or ve.verlag="Haffmanns"; 9. SELECT bu.Titel, ve.Verlag FROM Bücher AS bu RIGHT JOIN Verlag AS ve ON bu.VerlagNr=ve.VerlagNr where ve.Verlag="Milson & Boons" or bu.Autor="Christie"; 10 SQL-Befehle in Abfragen: Join Unterabfrage aufbauen1 Unterabfragen (auch subquery genannt) sind geschachtelte Abfragen mit select. Sie können in einer oder über mehrere Tabellen durchgeführt werden a) Unterabfragen über mehrere Tabellen "Vereinfacht ausgedrückt verbindet eine Unterabfrage die Ergebnismenge der einen Abfrage mit einer anderen. Die allgemeine Syntax lautet: SELECT * FROM Tabelle1 WHERE Tabelle1.Eine_Spalte = (SELECT Eine_Andere_Spalte FROM Tabelle2 WHERE Eine_Andere_Spalte = Ein_Wert) Da die zweite Abfrage in der ersten eingebaut ist, spricht man auch von einer verschachtelten Abfrage. " Testen Sie dies mit der Datenbank Firma2003.mdb In beiden Tabellen, Lieferant und Artikel, ist das Feld Liefnr vorhanden. Wenn man nun die Artikel suchen will, die vom Lieferanten Meyer OHG geleifert werden, dann geht das – statt wie bisher gelöst über den Equi Join auch über eine Unterabfrage: SELECT * from artikel where liefnr= (select liefnr from lieferant where lieferant="Meyer OHG"); b) Unterabfragen in einer Tabelle Wichtiger als die zuerst gezeigte Abfrageform sind Unterabfragen in einer Tabelle, weil man mit ihnen Ergebnisse erzielen kann, die man auf andere Art nicht erzielt hätte. Am Beispiel der Tabelle Abteilung, Datenbank: SQL-Beispiele, soll dies gezeigt werden: Zunächst eine Abfrage, die noch nichts direkt mit der subquery zu tun hat, die aber dazu dient, zur Problematik hinzuführen: Es soll der Mittelwert des Gehalts aus der Tabelle ermittelt werden: SELECT Avg(gehalt) AS Mittelwert_Gehalt FROM abteilung; 1 aus: SQL in 21 Tagen, Kap. 7 11 SQL-Befehle in Abfragen: Join Jetzt soll außerdem nach Abschlüssen (Ausbildung, Uni oder FH) gruppiert werden. Damit das Ergebnis besser lesbar ist, soll der Mittelwert gerundet werden. SELECT abschluss, round(Avg(gehalt),2) AS Mittelwert_Gehalt FROM abteilung group by abschluss; Nach der Gruppierung kann bekanntlich nicht mit where gearbeitet werden, wohl aber mit der having-Klausel, wenn eine Bedingung für die Ausgabe gebildet wird: SELECT abschluss, round(Avg(gehalt),2) AS Mittelwert_Gehalt FROM abteilung group by abschluss having avg(gehalt)<3000; Mit der Unterabfrage kann man nun herausbekommen, wie der Mittelwert des Gehalts ist, bezogen auf die Abteilung, in der sich das kleinste Gehalt befindet: SELECT round(Avg(gehalt),2) AS Mittelwert_Gehalt FROM abteilung where gehalt=(select min(gehalt) from abteilung); Dabei ist aber nicht sichtbar, welche Abteilung es ist. Lösen wir solch ein Problem wieder über eine Subquery: Frage: In welcher Abteilung findet sich das höchste Gehalt? SELECT abteilung FROM abteilung where gehalt=(select max(gehalt) from abteilung); Zusätzlich stellen wir die Frage: wie hoch ist das höchste Gehalt, und in welcher Abteilung finden wir es? SELECT abteilung, gehalt FROM abteilung where gehalt=(select max(gehalt) from abteilung); Aufgaben: 1) Wie heißt der Angestellte mit den meisten Krank_Tagen? name Gernegroß 2) In welcher Abteilung findet sich der Angestellte mit den meisten Krank_Tagen, wie viele sind es, und wie heißt er? name krank_tage abteilung Gernegroß 20 Marketing 3) Wie ist der Abschluss (Ausbildung, FH oder Uni) dessen, der die meisten Urlaubstage hat? abschluss Ausbildung 4) Wer bezieht das höchste Gehalt? name Klinger 12 SQL-Befehle in Abfragen: Join zu 1) SELECT name FROM abteilung where krank_tage=(select max(krank_tage) from abteilung); zu 2) SELECT abteilung,name, krank_tage FROM abteilung where krank_tage=(select max(krank_tage) from abteilung); zu 3) SELECT abschluss FROM abteilung where Urlaubstage=(select max(urlaubstage) from abteilung); zu 4) SELECT name FROM abteilung where gehalt=(select max(gehalt) from abteilung); weitere Übungen: wie viele Leute sind verheiratet? verheiratet 6 Wer hat das höchste Gehalt aus der Abteilung Personal??? 13 SQL-Befehle in Abfragen: Join SELECT ve.verlag, bu.Titel FROM Verlag as ve left JOIN Bücher as bu ON Ve.VerlagNr = Bu.VerlagNr; Im „normalen“ Join erscheint der Verlag nicht SELECT ve.verlag, bu.Titel FROM verlag AS ve, bücher AS bu where bu.verlagnr=ve.verlagnr verlag .... Diogenes Fischer Fischer Titel ..... Der tiefe Schlaf Volkswirtschaftslehre Außenseiter verlag .... Diogenes Fischer Fischer Haffmanns Titel ..... Der tiefe Schlaf Volkswirtschaftslehre Außenseiter 1.1 Left Outer Join SELECT ve.verlag, bu.Titel FROM Verlag AS ve left outer join Bücher AS bu ON Ve.VerlagNr=Bu.VerlagNr; 1.2 Right Outer JOIN verlag Titel Diogenes Der tiefe Schlaf Fischer Volkswirtschaftslehre Fischer Außenseiter Die Firma SELECT ve.verlag, bu.Titel FROM Verlag AS ve right outer JOIN Bücher AS bu ON Ve.VerlagNr=Bu.VerlagNr; Umgekehrte Reihenfolge: Titel verlag Der tiefe Schlaf Diogenes Volkswirtschaftslehre Fischer Außenseiter Fischer Haffmanns SELECT bu.Titel, ve.verlag FROM Bücher AS bu right outer JOIN Verlag AS ve ON Ve.VerlagNr=Bu.VerlagNr; Full outer Join geht nicht in Access: SELECT bu.Titel, ve.verlag FROM Bücher AS bu full outer JOIN Verlag AS ve ON Ve.VerlagNr=Bu.VerlagNr; 14 SQL-Befehle in Abfragen: Join Lösungen: 10. SELECT ve.verlag, bu.Titel from verlag ve, bücher bu; 11. SELECT ve.verlag, bu.Titel FROM verlag AS ve, bücher AS bu where bu.verlagnr=ve.verlagnr 12. SELECT ve.verlag, bu.Titel FROM verlag AS ve, bücher AS bu where bu.verlagnr=ve.verlagnr and ve.verlagnr=2; 13. SELECT bu.Titel, ve.Verlag FROM Bücher AS bu LEFT JOIN Verlag AS ve ON bu.VerlagNr=ve.VerlagNr; 14. SELECT ve.verlag, bu.Titel FROM Verlag AS ve LEFT JOIN Bücher AS bu ON Ve.VerlagNr=Bu.VerlagNr; 15. SELECT bu.Titel, ve.Verlag FROM Bücher AS bu RIGHT outer ON bu.VerlagNr=ve.VerlagNr; JOIN Verlag AS ve 16. SELECT bg.Gruppe, ka.katalognummer FROM Buchgruppe AS bg LEFT JOIN Katalog AS ka ON bg.kategorienr=ka.kategorienr; 15