DQL: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
| (3 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 1: | Zeile 1: | ||
Die '''Data Query Language (DQL | == Einführung == | ||
Die '''Data Query Language''' (kurz '''DQL''') der [[SQL|Structured Query Language (SQL)]] ermöglicht es, mittels Abfragen Informationen aus unterschiedlichen Tabellen zusammenzutragen. Das Ergebnis einer Abfrage ist eine [[Relation]] und kann oft auch wie eine Tabelle angezeigt, bearbeitet und weiterverwendet werden. Abfragen basieren auf den Operationen der '''relationalen Algebra'''. | |||
== Datenbasis == | == Datenbasis == | ||
[[Datei:DQLDatenbasisERM.jpg|mini|ERM-Modell zur Datenbasis]] | [[Datei:DQLDatenbasisERM.jpg|mini|ERM-Modell zur Datenbasis]] | ||
[[Datei:DQLDatenbasisTabellen.jpg|mini]] | [[Datei:DQLDatenbasisTabellen.jpg|mini|Tabellenübersicht]] | ||
Um die Syntax von SQL-Abfragen nachvollziehen zu können, wird die Datenbasis eines Friseursalons verwendet (siehe Bilder). Die Abfragen beziehen sich auf Tabellen wie `Mitarbeiter`, `Salon`, `Kunde` und `Termin`. | |||
== | == Auswahl (SELECT) == | ||
Eine Abfrage beginnt mit der Auswahl anzuzeigender Spalten durch das Schlüsselwort '''SELECT'''. | |||
* Spalten werden durch Komma getrennt. | |||
* Mit einem Sternchen (`*`) werden alle Spalten ausgewählt. | |||
* Bei mehreren Tabellen wird die Punkt-Notation verwendet: `Tabellenname.Spaltenname`. | |||
=== | === Alias (AS) === | ||
Nach jeder Spalte kann mit dem Schlüsselwort '''AS''' ein neuer Name (Alias) für die Anzeige festgelegt werden. | |||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT | SELECT Nachname AS Mitarbeitername, IdMitarbeiter FROM Mitarbeiter; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
=== | == Datenherkunft (FROM) == | ||
Nach dem Schlüsselwort '''FROM''' werden alle Tabellen angegeben, die von der Abfrage betroffen sind. Es muss mindestens eine Tabelle angegeben werden. | |||
'''Einfache Abfrage mit Spaltenauswahl:''' | |||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT | SELECT nachname, vorname FROM Mitarbeiter; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Ergebnis:''' | '''Ergebnis:''' | ||
{| class="wikitable" | {| class="wikitable" | ||
! | ! nachname !! vorname | ||
|- | |- | ||
| | | Krause || Sabine | ||
|- | |- | ||
| | | Schrotter || Claudia | ||
|- | |- | ||
| | | Hermann || Markus | ||
|- | |- | ||
| | | Krause || Christoph | ||
|- | |- | ||
| | | Bitter || Manuel | ||
|} | |} | ||
== | == Filter (WHERE) == | ||
Ein Filter schränkt die Ergebnismenge auf Datensätze ein, für die eine Aussage im Sinne der '''booleschen Algebra''' wahr ist. Er wird durch '''WHERE''' eingeleitet. Neben den Operatoren `<>` und `=` kann auch '''BETWEEN''' eingesetzt werden, um Ober- und Untergrenze eines Filters gleichzeitig anzugeben. | |||
'''Beispiel komplexer Filter:''' | |||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT Vorname, Nachname FROM Mitarbeiter WHERE Nachname = 'Krause'; | SELECT Vorname, Nachname FROM Mitarbeiter | ||
WHERE (Nachname = 'Krause' OR Vorname = 'Manuel') AND IdMitarbeiter <> 1; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Ergebnis:''' | '''Ergebnis:''' | ||
{| class="wikitable" | {| class="wikitable" | ||
! Vorname !! Nachname | ! Vorname !! Nachname | ||
|- | |- | ||
| | | Christoph || Krause | ||
|- | |- | ||
| | | Manuel || Bitter | ||
|} | |} | ||
=== | === IS NULL === | ||
SQL nutzt '''NULL-Werte''' für fehlende Informationen. Die Prüfung erfolgt mit `IS NULL` oder `IS NOT NULL`. Dies ist besonders bei äußeren Verbünden (Outer Joins) wichtig. | |||
<syntaxhighlight lang="sql"> | |||
SELECT * FROM Termin WHERE Datum IS NOT NULL; | |||
</syntaxhighlight> | |||
== Sortierung und Begrenzung == | |||
=== ORDER BY === | |||
Mit '''ORDER BY''' wird die Sortierreihenfolge festgelegt. | |||
* '''ASC:''' aufsteigend (Standard) | |||
* '''DESC:''' absteigend | |||
<syntaxhighlight lang="sql"> | |||
SELECT Nachname, Vorname FROM Mitarbeiter ORDER BY Nachname ASC; | |||
</syntaxhighlight> | |||
=== Top-N-Zeilen (LIMIT) === | |||
Bei MySQL und PostgreSQL wird die Ergebnismenge durch '''LIMIT''' beschränkt, um z. B. nur die aktuellsten Einträge zu erhalten. | |||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT | SELECT * FROM Warenkorbposition ORDER BY Datum DESC LIMIT 10; | ||
</syntaxhighlight> | </syntaxhighlight> | ||
== Tabellen verknüpfen (JOINs) == | == Tabellen verknüpfen (JOINs) == | ||
Werden Informationen unterschiedlicher Tabellen zusammengefügt, müssen diese über Schlüsselfelder verbunden werden. | |||
=== Innerer natürlicher Verbund (INNER JOIN) === | |||
Zeigt nur Datensätze an, für die in beiden Tabellen eine Entsprechung existiert. | |||
=== | |||
<html> | <html> | ||
<svg width="200" height="120" viewBox="0 0 200 120"> | <svg width="200" height="120" viewBox="0 0 200 120"> | ||
| Zeile 87: | Zeile 96: | ||
</clipPath> | </clipPath> | ||
<circle cx="130" cy="60" r="50" fill="#3498db" clip-path="url(#inner)" /> | <circle cx="130" cy="60" r="50" fill="#3498db" clip-path="url(#inner)" /> | ||
<text x="45" y="65" font-size="12">A</text> | <text x="45" y="65" font-size="12">Tab. A</text> | ||
<text x=" | <text x="135" y="65" font-size="12">Tab. B</text> | ||
</svg> | </svg> | ||
</html> | </html> | ||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT Salon.Name, Mitarbeiter.Nachname | SELECT Salon.IdSalon, Salon.Name AS Salonname, Mitarbeiter.Nachname | ||
FROM Salon INNER JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon; | FROM Salon | ||
INNER JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Ergebnis:''' (Salon 3 erscheint nicht, da kein Mitarbeiter zugeordnet ist) | '''Ergebnis:''' (Salon 3 "Kaiserschnitt" erscheint nicht, da ihm kein Mitarbeiter zugeordnet ist) | ||
{| class="wikitable" | {| class="wikitable" | ||
! | ! IdSalon !! Salonname !! Nachname | ||
|- | |- | ||
| Friedrich List Frisuren || Krause | | 1 || Friedrich List Frisuren || Krause | ||
|- | |- | ||
| Friedrich List Frisuren || Schrotter | | 1 || Friedrich List Frisuren || Schrotter | ||
|- | |- | ||
| Friedrich List Frisuren || Hermann | | 1 || Friedrich List Frisuren || Hermann | ||
|- | |- | ||
| Hammer Haare || Krause | | 2 || Hammer Haare || Krause | ||
|- | |- | ||
| Hammer Haare || Bitter | | 2 || Hammer Haare || Bitter | ||
|} | |} | ||
=== | === Linker äußerer Verbund (LEFT JOIN) === | ||
Alle Datensätze der linken Tabelle (Tab. A) werden angezeigt. Die der rechten Tabelle nur bei Übereinstimmung, sonst `NULL`. | |||
<html> | <html> | ||
<svg width="200" height="120" viewBox="0 0 200 120"> | <svg width="200" height="120" viewBox="0 0 200 120"> | ||
<circle cx="130" cy="60" r="50" stroke="black" stroke-width="2" fill="white" /> | <circle cx="130" cy="60" r="50" stroke="black" stroke-width="2" fill="white" /> | ||
<circle cx="70" cy="60" r="50" stroke="black" stroke-width="2" fill="#3498db" /> | <circle cx="70" cy="60" r="50" stroke="black" stroke-width="2" fill="#3498db" /> | ||
<text x="45" y="65" font-size="12">A</text> | <text x="45" y="65" font-size="12">Tab. A</text> | ||
<text x=" | <text x="135" y="65" font-size="12">Tab. B</text> | ||
</svg> | </svg> | ||
</html> | </html> | ||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT Salon.Name, Mitarbeiter.Nachname | SELECT Salon.Name AS Salonname, Mitarbeiter.Nachname | ||
FROM Salon LEFT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon; | FROM Salon | ||
LEFT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Ergebnis:''' | '''Ergebnis:''' | ||
{| class="wikitable" | {| class="wikitable" | ||
! | ! Salonname !! Nachname | ||
|- | |- | ||
| Friedrich List Frisuren || Krause | | Friedrich List Frisuren || Krause | ||
| Zeile 142: | Zeile 154: | ||
|} | |} | ||
=== | === Rechter äußerer Verbund (RIGHT JOIN) === | ||
Alle Einträge der rechten Tabelle (Tab. B) werden selektiert, auch wenn keine Verbindung zur linken besteht. | |||
<html> | <html> | ||
<svg width="200" height="120" viewBox="0 0 200 120"> | <svg width="200" height="120" viewBox="0 0 200 120"> | ||
<circle cx="70" cy="60" r="50" stroke="black" stroke-width="2" fill="white" /> | <circle cx="70" cy="60" r="50" stroke="black" stroke-width="2" fill="white" /> | ||
<circle cx="130" cy="60" r="50" stroke="black" stroke-width="2" fill="#3498db" /> | <circle cx="130" cy="60" r="50" stroke="black" stroke-width="2" fill="#3498db" /> | ||
<text x="45" y="65" font-size="12">A</text> | <text x="45" y="65" font-size="12">Tab. A</text> | ||
<text x=" | <text x="135" y="65" font-size="12">Tab. B</text> | ||
</svg> | </svg> | ||
</html> | </html> | ||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT Salon.Name | -- Hier: Alle Salons (Rechts) anzeigen, auch wenn keine Mitarbeiter (Links) zugeordnet sind | ||
SELECT Mitarbeiter.Nachname, Salon.Name AS Salonname | |||
FROM Mitarbeiter | |||
RIGHT JOIN Salon ON Mitarbeiter.FKSalon = Salon.IdSalon; | |||
</syntaxhighlight> | </syntaxhighlight> | ||
'''Ergebnis:''' | |||
{| class="wikitable" | |||
! Nachname !! Salonname | |||
|- | |||
| Krause || Friedrich List Frisuren | |||
|- | |||
| Schrotter || Friedrich List Frisuren | |||
|- | |||
| Hermann || Friedrich List Frisuren | |||
|- | |||
| Krause || Hammer Haare | |||
|- | |||
| Bitter || Hammer Haare | |||
|- | |||
| ''NULL'' || Kaiserschnitt | |||
|} | |||
== Gruppierung und | == Gruppierung und Aggregat-Funktionen == | ||
Mit '''GROUP BY''' werden Datensätze aggregiert (z. B. `COUNT`, `SUM`, `AVG`). Möchte man die Datensätze in einer gruppierten Abfrage filtern, muss '''HAVING''' anstatt `WHERE` verwendet werden. | |||
<syntaxhighlight lang="sql"> | <syntaxhighlight lang="sql"> | ||
SELECT SUM(Rechnungsbetrag) AS Umsatz, Mitarbeiter.Nachname | SELECT SUM(Termin.Rechnungsbetrag) AS Umsatz, Mitarbeiter.Nachname AS Mitarbeiter | ||
FROM | FROM TERMIN | ||
INNER JOIN Mitarbeiter ON Termin.FKMitarbeiter = Mitarbeiter.IdMitarbeiter | INNER JOIN Mitarbeiter ON Termin.FKMitarbeiter = Mitarbeiter.IdMitarbeiter | ||
GROUP BY Mitarbeiter.IdMitarbeiter | GROUP BY Mitarbeiter.IdMitarbeiter | ||
| Zeile 172: | Zeile 204: | ||
| 106 || Schrotter | | 106 || Schrotter | ||
|} | |} | ||
''( | |||
== Unterabfragen (Verschachtelt) == | |||
Unterabfragen werden in Klammern gesetzt und liefern Werte für die Hauptabfrage. | |||
<syntaxhighlight lang="sql"> | |||
-- Termine mit unterdurchschnittlichem Umsatz | |||
SELECT TerminID, Rechnungsbetrag FROM Termin | |||
WHERE Rechnungsbetrag < (SELECT AVG(Rechnungsbetrag) FROM Termin); | |||
</syntaxhighlight> | |||
== UNION == | |||
Mit '''UNION''' werden zwei Relationen vereint. Die Spalten müssen vom gleichen Typ sein. | |||
<syntaxhighlight lang="sql"> | |||
SELECT Mitarbeiter.nachname FROM Mitarbeiter | |||
UNION | |||
SELECT Kunde.nachname FROM Kunde; | |||
</syntaxhighlight> | |||
== Reihenfolge der Abarbeitung == | |||
Das DBMS arbeitet eine DQL-Abfrage logisch in dieser Reihenfolge ab: | |||
# '''FROM''' (inkl. JOINs) | |||
# '''WHERE''' | |||
# '''GROUP BY''' | |||
# '''HAVING''' | |||
# '''SELECT''' | |||
# '''ORDER BY''' | |||
# '''LIMIT''' | |||
[[Kategorie:Datenbanken]] | [[Kategorie:Datenbanken]] | ||
[[Kategorie:FI_I_SDM]] | [[Kategorie:FI_I_SDM]] | ||
[[Kategorie:FI_I_TP2]] | [[Kategorie:FI_I_TP2]] | ||