DQL: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
|||
| (2 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 | 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]] | ||
Aktuelle Version vom 26. Februar 2026, 14:27 Uhr
Einführung
Die Data Query Language (kurz DQL) der 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


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.
SELECT Nachname AS Mitarbeitername, IdMitarbeiter FROM Mitarbeiter;
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:
SELECT nachname, vorname FROM Mitarbeiter;
Ergebnis:
| 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:
SELECT Vorname, Nachname FROM Mitarbeiter
WHERE (Nachname = 'Krause' OR Vorname = 'Manuel') AND IdMitarbeiter <> 1;
Ergebnis:
| 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.
SELECT * FROM Termin WHERE Datum IS NOT NULL;
Sortierung und Begrenzung
ORDER BY
Mit ORDER BY wird die Sortierreihenfolge festgelegt.
- ASC: aufsteigend (Standard)
- DESC: absteigend
SELECT Nachname, Vorname FROM Mitarbeiter ORDER BY Nachname ASC;
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.
SELECT * FROM Warenkorbposition ORDER BY Datum DESC LIMIT 10;
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.
SELECT Salon.IdSalon, Salon.Name AS Salonname, Mitarbeiter.Nachname
FROM Salon
INNER JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;
Ergebnis: (Salon 3 "Kaiserschnitt" erscheint nicht, da ihm kein Mitarbeiter zugeordnet ist)
| IdSalon | Salonname | Nachname |
|---|---|---|
| 1 | Friedrich List Frisuren | Krause |
| 1 | Friedrich List Frisuren | Schrotter |
| 1 | Friedrich List Frisuren | Hermann |
| 2 | Hammer Haare | Krause |
| 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`.
SELECT Salon.Name AS Salonname, Mitarbeiter.Nachname
FROM Salon
LEFT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;
Ergebnis:
| Salonname | Nachname |
|---|---|
| Friedrich List Frisuren | Krause |
| Friedrich List Frisuren | Schrotter |
| Friedrich List Frisuren | Hermann |
| Hammer Haare | Krause |
| Hammer Haare | Bitter |
| Kaiserschnitt | NULL |
Rechter äußerer Verbund (RIGHT JOIN)
Alle Einträge der rechten Tabelle (Tab. B) werden selektiert, auch wenn keine Verbindung zur linken besteht.
-- 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;
Ergebnis:
| Nachname | Salonname |
|---|---|
| Krause | Friedrich List Frisuren |
| Schrotter | Friedrich List Frisuren |
| Hermann | Friedrich List Frisuren |
| Krause | Hammer Haare |
| Bitter | Hammer Haare |
| NULL | Kaiserschnitt |
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.
SELECT SUM(Termin.Rechnungsbetrag) AS Umsatz, Mitarbeiter.Nachname AS Mitarbeiter
FROM TERMIN
INNER JOIN Mitarbeiter ON Termin.FKMitarbeiter = Mitarbeiter.IdMitarbeiter
GROUP BY Mitarbeiter.IdMitarbeiter
HAVING Umsatz > 100;
Ergebnis:
| Umsatz | Mitarbeiter |
|---|---|
| 106 | Schrotter |
Unterabfragen (Verschachtelt)
Unterabfragen werden in Klammern gesetzt und liefern Werte für die Hauptabfrage.
-- Termine mit unterdurchschnittlichem Umsatz
SELECT TerminID, Rechnungsbetrag FROM Termin
WHERE Rechnungsbetrag < (SELECT AVG(Rechnungsbetrag) FROM Termin);
UNION
Mit UNION werden zwei Relationen vereint. Die Spalten müssen vom gleichen Typ sein.
SELECT Mitarbeiter.nachname FROM Mitarbeiter
UNION
SELECT Kunde.nachname FROM Kunde;
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