Die Seite wurde neu angelegt: „Die '''Data Query Language (DQL)''' ist der Teilbereich von SQL, der zur Abfrage und Zusammenstellung von Informationen aus Datenbanktabellen dient. Das Ergebnis einer DQL-Abfrage ist eine Relation, die in der Regel als temporäre Tabelle dargestellt wird. DQL-Abfragen basieren auf den Operationen der '''relationalen Algebra''' (Selektion, Projektion, Join etc.). == Datenbasis & Modellierung == Um komplexe Abfragen zu verstehen, ist die Kenntnis…“
 
Keine Bearbeitungszusammenfassung
 
(5 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
Die '''Data Query Language (DQL)''' ist der Teilbereich von [[SQL]], der zur Abfrage und Zusammenstellung von Informationen aus Datenbanktabellen dient. Das Ergebnis einer DQL-Abfrage ist eine [[Relation]], die in der Regel als temporäre Tabelle dargestellt wird.
== 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'''.


DQL-Abfragen basieren auf den Operationen der '''relationalen Algebra''' (Selektion, Projektion, Join etc.).
== Datenbasis ==
[[Datei:DQLDatenbasisERM.jpg|mini|ERM-Modell zur Datenbasis]]
[[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`.


== Datenbasis & Modellierung ==
== Auswahl (SELECT) ==
Um komplexe Abfragen zu verstehen, ist die Kenntnis des zugrundeliegenden Schemas (ER-Modell) notwendig.
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`.


== Grundstruktur einer Abfrage ==
=== Alias (AS) ===
 
Nach jeder Spalte kann mit dem Schlüsselwort '''AS''' ein neuer Name (Alias) für die Anzeige festgelegt werden.
Die Basis jeder Abfrage besteht aus der Auswahl der Spalten (`SELECT`) und der Festlegung der Datenquelle (`FROM`).
<syntaxhighlight lang="sql">
SELECT Nachname AS Mitarbeitername, IdMitarbeiter FROM Mitarbeiter;
</syntaxhighlight>


=== Auswahl (SELECT) und Alias (AS) ===
== Datenherkunft (FROM) ==
Mit `SELECT` werden die gewünschten Spalten definiert. Mehrere Spalten werden durch Kommata getrennt.
Nach dem Schlüsselwort '''FROM''' werden alle Tabellen angegeben, die von der Abfrage betroffen sind. Es muss mindestens eine Tabelle angegeben werden.
* `*`: Wählt alle Spalten einer Tabelle aus.
* `AS`: Definiert einen Alias-Namen für eine Spalte oder Tabelle (erhöht die Lesbarkeit).


'''Einfache Abfrage mit Spaltenauswahl:'''
<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
-- Beispiel mit Spaltenauswahl und Alias
SELECT nachname, vorname FROM Mitarbeiter;
SELECT Nachname AS Mitarbeitername, IdMitarbeiter
FROM Mitarbeiter;
</syntaxhighlight>
</syntaxhighlight>


=== Datenherkunft (FROM) ===
'''Ergebnis:'''
Hinter `FROM` werden die betroffenen Tabellen gelistet. Bei mehreren Tabellen müssen Spaltennamen eindeutig durch Voranstellen des Tabellennamens (`Tabellenname.Spaltenname`) identifiziert werden.
{| 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.


== Filtern und Sortieren ==
'''Beispiel komplexer Filter:'''
<syntaxhighlight lang="sql">
SELECT Vorname, Nachname FROM Mitarbeiter
WHERE (Nachname = 'Krause' OR Vorname = 'Manuel') AND IdMitarbeiter <> 1;
</syntaxhighlight>


=== WHERE-Klausel (Filter) ===
'''Ergebnis:'''
Die `WHERE`-Klausel schränkt die Ergebnismenge ein. Nur Datensätze, die die Bedingung erfüllen (boolesche Logik), werden angezeigt.
{| class="wikitable"
 
! Vorname !! Nachname
* '''Operatoren:''' `=`, `<>`, `<`, `>`, `BETWEEN`, `AND`, `OR`, `NOT`.
|-
* '''NULL-Werte:''' Da `NULL` kein Wert, sondern ein Zustand ist, erfolgt die Prüfung mit `IS NULL` oder `IS NOT NULL`.
| 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">
<syntaxhighlight lang="sql">
-- Filter mit komplexer Bedingung und NULL-Prüfung
SELECT * FROM Termin WHERE Datum IS NOT NULL;
SELECT * FROM Termin  
WHERE (Rechnungsbetrag BETWEEN 50 AND 150)
  AND Datum IS NOT NULL;
</syntaxhighlight>
</syntaxhighlight>


=== ORDER BY & LIMIT ===
== Sortierung und Begrenzung ==
* '''ORDER BY:''' Sortiert die Ausgabe nach einer oder mehreren Spalten (`ASC` für aufsteigend, `DESC` für absteigend).
 
* '''LIMIT:''' (In MySQL/PostgreSQL) Begrenzt die Anzahl der ausgegebenen Zeilen (Top-N-Abfrage).
=== ORDER BY ===
Mit '''ORDER BY''' wird die Sortierreihenfolge festgelegt.
* '''ASC:''' aufsteigend (Standard)
* '''DESC:''' absteigend


<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
SELECT * FROM Warenkorb
SELECT Nachname, Vorname FROM Mitarbeiter ORDER BY Nachname ASC;
ORDER BY datum DESC
LIMIT 10;
</syntaxhighlight>
</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">
SELECT * FROM Warenkorbposition ORDER BY Datum DESC LIMIT 10;
</syntaxhighlight>


== Tabellen verknüpfen (JOINs) ==
== Tabellen verknüpfen (JOINs) ==
Werden Informationen unterschiedlicher Tabellen zusammengefügt, müssen diese über Schlüsselfelder verbunden werden.


JOINs ermöglichen es, Daten aus unterschiedlichen Tabellen über Fremdschlüsselbeziehungen zusammenzuführen.
=== Innerer natürlicher Verbund (INNER JOIN) ===
 
Zeigt nur Datensätze an, für die in beiden Tabellen eine Entsprechung existiert.
 
<html>
<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="130" cy="60" r="50" stroke="black" stroke-width="2" fill="white" />
  <clipPath id="inner">
    <circle cx="70" cy="60" r="50" />
  </clipPath>
  <circle cx="130" cy="60" r="50" fill="#3498db" clip-path="url(#inner)" />
  <text x="45" y="65" font-size="12">Tab. A</text>
  <text x="135" y="65" font-size="12">Tab. B</text>
</svg>
</html>


=== INNER JOIN ===
Gibt nur die Datensätze zurück, bei denen in beiden Tabellen eine Übereinstimmung der Verknüpfungsbedingung vorliegt.
<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
SELECT Salon.Name, Mitarbeiter.Nachname  
SELECT Salon.IdSalon, Salon.Name AS Salonname, Mitarbeiter.Nachname  
FROM Salon  
FROM Salon  
INNER JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;
INNER JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;
</syntaxhighlight>
</syntaxhighlight>
'''Ergebnis:''' (Salon 3 "Kaiserschnitt" erscheint nicht, da ihm kein Mitarbeiter zugeordnet ist)
{| class="wikitable"
! 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
|}


=== LEFT / RIGHT OUTER JOIN ===
=== Linker äußerer Verbund (LEFT JOIN) ===
* '''LEFT JOIN:''' Alle Datensätze der linken Tabelle werden angezeigt. Gibt es keine Entsprechung in der rechten Tabelle, werden die Spalten mit `NULL` aufgefüllt.
Alle Datensätze der linken Tabelle (Tab. A) werden angezeigt. Die der rechten Tabelle nur bei Übereinstimmung, sonst `NULL`.
* '''RIGHT JOIN:''' Funktioniert analog, jedoch werden alle Datensätze der rechten Tabelle garantiert angezeigt.
<html>
<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="70" cy="60" r="50" stroke="black" stroke-width="2" fill="#3498db" />
  <text x="45" y="65" font-size="12">Tab. A</text>
  <text x="135" y="65" font-size="12">Tab. B</text>
</svg>
</html>


---
<syntaxhighlight lang="sql">
SELECT Salon.Name AS Salonname, Mitarbeiter.Nachname
FROM Salon
LEFT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;
</syntaxhighlight>
'''Ergebnis:'''
{| class="wikitable"
! Salonname !! Nachname
|-
| Friedrich List Frisuren || Krause
|-
| Friedrich List Frisuren || Schrotter
|-
| Friedrich List Frisuren || Hermann
|-
| Hammer Haare || Krause
|-
| Hammer Haare || Bitter
|-
| Kaiserschnitt || ''NULL''
|}


== Gruppierung und Aggregate ==
=== Rechter äußerer Verbund (RIGHT JOIN) ===
Alle Einträge der rechten Tabelle (Tab. B) werden selektiert, auch wenn keine Verbindung zur linken besteht.
<html>
<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="130" cy="60" r="50" stroke="black" stroke-width="2" fill="#3498db" />
  <text x="45" y="65" font-size="12">Tab. A</text>
  <text x="135" y="65" font-size="12">Tab. B</text>
</svg>
</html>


Mit `GROUP BY` werden Datensätze mit gleichen Werten in bestimmten Spalten zusammengefasst. Dies wird meist mit Aggregatfunktionen genutzt:
<syntaxhighlight lang="sql">
* `COUNT()`: Anzahl der Datensätze
-- Hier: Alle Salons (Rechts) anzeigen, auch wenn keine Mitarbeiter (Links) zugeordnet sind
* `SUM()`: Summe
SELECT Mitarbeiter.Nachname, Salon.Name AS Salonname
* `AVG()`: Mittelwert
FROM Mitarbeiter
* `MIN()` / `MAX()`: Extremwerte
RIGHT JOIN Salon ON Mitarbeiter.FKSalon = Salon.IdSalon;
</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
|}


> '''Wichtig:''' Um auf aggregierte Werte zu filtern, muss das Schlüsselwort '''HAVING''' anstelle von `WHERE` verwendet werden.
== 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 Mitarbeiter.Nachname, SUM(Termin.Rechnungsbetrag) AS Umsatz
SELECT SUM(Termin.Rechnungsbetrag) AS Umsatz, Mitarbeiter.Nachname AS Mitarbeiter
FROM Mitarbeiter
FROM TERMIN
INNER JOIN Termin ON Mitarbeiter.MitarbeiterID = Termin.FKMitarbeiter
INNER JOIN Mitarbeiter ON Termin.FKMitarbeiter = Mitarbeiter.IdMitarbeiter
GROUP BY Mitarbeiter.MitarbeiterID
GROUP BY Mitarbeiter.IdMitarbeiter
HAVING Umsatz > 100;
HAVING Umsatz > 100;
</syntaxhighlight>
</syntaxhighlight>
'''Ergebnis:'''
{| class="wikitable"
! Umsatz !! Mitarbeiter
|-
| 106 || Schrotter
|}


---
== Unterabfragen (Verschachtelt) ==
 
Unterabfragen werden in Klammern gesetzt und liefern Werte für die Hauptabfrage.
== Fortgeschrittene Techniken ==
 
=== Unterabfragen (Subqueries) ===
Eine Abfrage kann innerhalb einer anderen Abfrage stehen. Sie muss in Klammern gesetzt werden.
<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
-- Termine finden, deren Betrag unter dem Durchschnitt liegt
-- Termine mit unterdurchschnittlichem Umsatz
SELECT TerminID, Rechnungsbetrag  
SELECT TerminID, Rechnungsbetrag FROM Termin  
FROM Termin  
WHERE Rechnungsbetrag < (SELECT AVG(Rechnungsbetrag) FROM Termin);
WHERE Rechnungsbetrag < (SELECT AVG(Rechnungsbetrag) FROM Termin);
</syntaxhighlight>
</syntaxhighlight>


=== UNION ===
== UNION ==
Vereint die Ergebnismengen zweier `SELECT`-Abfragen. Voraussetzungen: Gleiche Anzahl an Spalten und kompatible Datentypen.
Mit '''UNION''' werden zwei Relationen vereint. Die Spalten müssen vom gleichen Typ sein.
<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
SELECT nachname FROM Mitarbeiter
SELECT Mitarbeiter.nachname FROM Mitarbeiter  
UNION
UNION  
SELECT nachname FROM Kunde;
SELECT Kunde.nachname FROM Kunde;
</syntaxhighlight>
</syntaxhighlight>


---
== Reihenfolge der Abarbeitung ==
 
Das DBMS arbeitet eine DQL-Abfrage logisch in dieser Reihenfolge ab:
== Logische Verarbeitungsreihenfolge ==
# '''FROM''' (inkl. JOINs)
Für die Fehleranalyse ist es wichtig zu wissen, in welcher Reihenfolge das DBMS die Befehle intern abarbeitet:
# '''WHERE'''
 
# '''GROUP BY'''
{# class="wikitable"
# '''HAVING'''
! Reihenfolge !! Klausel !! Beschreibung
# '''SELECT'''
|-
# '''ORDER BY'''
| 1 || '''FROM''' || Tabellen und JOINs werden geladen.
# '''LIMIT'''
|-
| 2 || '''WHERE''' || Zeilenweise Filterung der Rohdaten.
|-
| 3 || '''GROUP BY''' || Zusammenfassen von Zeilen zu Gruppen.
|-
| 4 || '''HAVING''' || Filterung der gebildeten Gruppen.
|-
| 5 || '''SELECT''' || Auswahl der Spalten und Berechnung von Aggregaten.
|-
| 6 || '''ORDER BY''' || Sortierung der fertigen Ergebnismenge.
|-
| 7 || '''LIMIT''' || Begrenzung der Ausgabeanzahl.
|}


[[Kategorie:Datenbanken]]
[[Kategorie:Datenbanken]]
[[Kategorie:FI_I_SDM]]
[[Kategorie:FI_I_SDM]]
[[Kategorie:FI_I_TP2]]
[[Kategorie:FI_I_TP2]]
Abgerufen von „https://wiki.flbk-hamm.de/DQL