DQL: Unterschied zwischen den Versionen

Aus FLBK-Wiki
Zur Navigation springen Zur Suche springen
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
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.
Die '''Data Query Language (DQL)''' ermöglicht es, Informationen aus verschiedenen Tabellen abzufragen. Das Ergebnis ist eine Relation, die meist als Tabelle angezeigt wird.


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]]
Basierend auf dem bereitgestellten Schema des Friseursalons ergeben sich folgende Tabelleninhalte:


== Datenbasis & Modellierung ==
{| class="wikitable" style="float: left; margin-right: 10px;"
Um komplexe Abfragen zu verstehen, ist die Kenntnis des zugrundeliegenden Schemas (ER-Modell) notwendig.
|+ Tabelle: Salon
! IdSalon !! Name
|-
| 1 || Friedrich List Frisuren
|-
| 2 || Hammer Haare
|-
| 3 || Kaiserschnitt
|}


== Grundstruktur einer Abfrage ==
{| class="wikitable" style="float: left; margin-right: 10px;"
|+ Tabelle: Mitarbeiter
! IdMitarbeiter !! Nachname !! Vorname !! FkSalon
|-
| 1 || Krause || Sabine || 1
|-
| 2 || Schrotter || Claudia || 1
|-
| 3 || Hermann || Markus || 1
|-
| 4 || Krause || Christoph || 2
|-
| 5 || Bitter || Manuel || 2
|}


Die Basis jeder Abfrage besteht aus der Auswahl der Spalten (`SELECT`) und der Festlegung der Datenquelle (`FROM`).
{| class="wikitable"
|+ Tabelle: Termin
! IdTermin !! Datum !! Rechnungsbetrag !! FkMitarbeiter !! FkKunde
|-
| 1 || 01.11.2012 || 20 || 1 || 1
|-
| 2 || 11.12.2012 || 29 || 2 || 2
|-
| 3 || 19.02.2013 || 77 || 2 || 3
|-
| 4 || 19.02.2013 || 20 || 5 || 4
|}
<div style="clear:both;"></div>


=== Auswahl (SELECT) und Alias (AS) ===
== Grundlegende Abfragen ==
Mit `SELECT` werden die gewünschten Spalten definiert. Mehrere Spalten werden durch Kommata getrennt.
* `*`: Wählt alle Spalten einer Tabelle aus.
* `AS`: Definiert einen Alias-Namen für eine Spalte oder Tabelle (erhöht die Lesbarkeit).


=== Einfache Abfrage (Projektion) ===
<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
-- Beispiel mit Spaltenauswahl und Alias
SELECT * FROM Mitarbeiter;
SELECT Nachname AS Mitarbeitername, IdMitarbeiter
FROM Mitarbeiter;
</syntaxhighlight>
</syntaxhighlight>
'''Ergebnis:'''
{| class="wikitable"
! IdMitarbeiter !! Nachname !! Vorname !! FkSalon
|-
| 1 || Krause || Sabine || 1
|-
| 2 || Schrotter || Claudia || 1
|-
| 3 || Hermann || Markus || 1
|-
| 4 || Krause || Christoph || 2
|-
| 5 || Bitter || Manuel || 2
|}


=== Datenherkunft (FROM) ===
=== Alias und Spaltenauswahl ===
Hinter `FROM` werden die betroffenen Tabellen gelistet. Bei mehreren Tabellen müssen Spaltennamen eindeutig durch Voranstellen des Tabellennamens (`Tabellenname.Spaltenname`) identifiziert werden.
<syntaxhighlight lang="sql">
SELECT IdMitarbeiter AS Mitarbeiternr, Nachname FROM Mitarbeiter;
</syntaxhighlight>
'''Ergebnis:'''
{| class="wikitable"
! Mitarbeiternr !! Nachname
|-
| 1 || Krause
|-
| 2 || Schrotter
|-
| 3 || Hermann
|-
| 4 || Krause
|-
| 5 || Bitter
|}


---
== Filtern von Daten (WHERE) ==
 
== Filtern und Sortieren ==
 
=== WHERE-Klausel (Filter) ===
Die `WHERE`-Klausel schränkt die Ergebnismenge ein. Nur Datensätze, die die Bedingung erfüllen (boolesche Logik), werden angezeigt.
 
* '''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`.


=== Einfacher Filter ===
<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
-- Filter mit komplexer Bedingung und NULL-Prüfung
SELECT Vorname, Nachname FROM Mitarbeiter WHERE Nachname = 'Krause';
SELECT * FROM Termin
WHERE (Rechnungsbetrag BETWEEN 50 AND 150)
  AND Datum IS NOT NULL;
</syntaxhighlight>
</syntaxhighlight>
'''Ergebnis:'''
{| class="wikitable"
! Vorname !! Nachname
|-
| Sabine || Krause
|-
| Christoph || Krause
|}


=== ORDER BY & LIMIT ===
=== Komplexer Filter ===
* '''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).
 
<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
SELECT * FROM Warenkorb
SELECT Vorname, Nachname FROM Mitarbeiter
ORDER BY datum DESC
WHERE (Nachname = 'Krause' OR Vorname = 'Manuel') AND IdMitarbeiter <> 1;
LIMIT 10;
</syntaxhighlight>
</syntaxhighlight>
 
'''Ergebnis:'''
---
{| class="wikitable"
! Vorname !! Nachname
|-
| Christoph || Krause
| Manuel || Bitter
|}


== Tabellen verknüpfen (JOINs) ==
== Tabellen verknüpfen (JOINs) ==


JOINs ermöglichen es, Daten aus unterschiedlichen Tabellen über Fremdschlüsselbeziehungen zusammenzuführen.
Hier werden die Tabellen `Salon` (Tabelle A) und `Mitarbeiter` (Tabelle B) verknüpft.


=== Inner Join (Schnittmenge) ===
<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">A</text>
  <text x="145" y="65" font-size="12">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.Name, 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 erscheint nicht, da kein Mitarbeiter zugeordnet ist)
{| class="wikitable"
! Name !! Nachname
|-
| Friedrich List Frisuren || Krause
|-
| Friedrich List Frisuren || Schrotter
|-
| Friedrich List Frisuren || Hermann
|-
| Hammer Haare || Krause
|-
| Hammer Haare || Bitter
|}


=== LEFT / RIGHT OUTER JOIN ===
=== Left Join (Inklusive linker Tabelle) ===
* '''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.
<html>
* '''RIGHT JOIN:''' Funktioniert analog, jedoch werden alle Datensätze der rechten Tabelle garantiert angezeigt.
<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">A</text>
  <text x="145" y="65" font-size="12">B</text>
</svg>
</html>


---
<syntaxhighlight lang="sql">
 
SELECT Salon.Name, Mitarbeiter.Nachname
== Gruppierung und Aggregate ==
FROM Salon LEFT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;
</syntaxhighlight>
'''Ergebnis:''' (Salon 3 wird mit NULL aufgeführt)
{| class="wikitable"
! Name !! Nachname
|-
| Friedrich List Frisuren || Krause
|-
| Friedrich List Frisuren || Schrotter
|-
| Friedrich List Frisuren || Hermann
|-
| Hammer Haare || Krause
|-
| Hammer Haare || Bitter
|-
| Kaiserschnitt || ''NULL''
|}


Mit `GROUP BY` werden Datensätze mit gleichen Werten in bestimmten Spalten zusammengefasst. Dies wird meist mit Aggregatfunktionen genutzt:
=== Right Join (Inklusive rechter Tabelle) ===
* `COUNT()`: Anzahl der Datensätze
<html>
* `SUM()`: Summe
<svg width="200" height="120" viewBox="0 0 200 120">
* `AVG()`: Mittelwert
  <circle cx="70" cy="60" r="50" stroke="black" stroke-width="2" fill="white" />
* `MIN()` / `MAX()`: Extremwerte
  <circle cx="130" cy="60" r="50" stroke="black" stroke-width="2" fill="#3498db" />
 
  <text x="45" y="65" font-size="12">A</text>
> '''Wichtig:''' Um auf aggregierte Werte zu filtern, muss das Schlüsselwort '''HAVING''' anstelle von `WHERE` verwendet werden.
  <text x="145" y="65" font-size="12">B</text>
</svg>
</html>


<syntaxhighlight lang="sql">
<syntaxhighlight lang="sql">
SELECT Mitarbeiter.Nachname, SUM(Termin.Rechnungsbetrag) AS Umsatz
SELECT Salon.Name, Mitarbeiter.Nachname  
FROM Mitarbeiter  
FROM Salon RIGHT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;
INNER JOIN Termin ON Mitarbeiter.MitarbeiterID = Termin.FKMitarbeiter
GROUP BY Mitarbeiter.MitarbeiterID
HAVING Umsatz > 100;
</syntaxhighlight>
</syntaxhighlight>


---
== Gruppierung und Aggregate ==
 
== 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
SELECT SUM(Rechnungsbetrag) AS Umsatz, Mitarbeiter.Nachname
SELECT TerminID, Rechnungsbetrag
FROM Termin  
FROM Termin  
WHERE Rechnungsbetrag < (SELECT AVG(Rechnungsbetrag) FROM Termin);
INNER JOIN Mitarbeiter ON Termin.FKMitarbeiter = Mitarbeiter.IdMitarbeiter
GROUP BY Mitarbeiter.IdMitarbeiter
HAVING Umsatz > 100;
</syntaxhighlight>
</syntaxhighlight>
 
'''Ergebnis:'''
=== UNION ===
{| class="wikitable"
Vereint die Ergebnismengen zweier `SELECT`-Abfragen. Voraussetzungen: Gleiche Anzahl an Spalten und kompatible Datentypen.
! Umsatz !! Mitarbeiter
<syntaxhighlight lang="sql">
SELECT nachname FROM Mitarbeiter
UNION
SELECT nachname FROM Kunde;
</syntaxhighlight>
 
---
 
== Logische Verarbeitungsreihenfolge ==
Für die Fehleranalyse ist es wichtig zu wissen, in welcher Reihenfolge das DBMS die Befehle intern abarbeitet:
 
{# class="wikitable"
! Reihenfolge !! Klausel !! Beschreibung
|-
| 1 || '''FROM''' || Tabellen und JOINs werden geladen.
|-
| 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.
| 106 || Schrotter
|}
|}
''(Berechnung: Claudia Schrotter [ID 2] hatte Termine über 29 und 77 Euro.)''


[[Kategorie:Datenbanken]]
[[Kategorie:Datenbanken]]
[[Kategorie:FI_I_SDM]]
[[Kategorie:FI_I_SDM]]
[[Kategorie:FI_I_TP2]]
[[Kategorie:FI_I_TP2]]

Version vom 26. Februar 2026, 14:18 Uhr

Die Data Query Language (DQL) ermöglicht es, Informationen aus verschiedenen Tabellen abzufragen. Das Ergebnis ist eine Relation, die meist als Tabelle angezeigt wird.

Datenbasis

ERM-Modell zur Datenbasis

Basierend auf dem bereitgestellten Schema des Friseursalons ergeben sich folgende Tabelleninhalte:

Tabelle: Salon
IdSalon Name
1 Friedrich List Frisuren
2 Hammer Haare
3 Kaiserschnitt
Tabelle: Mitarbeiter
IdMitarbeiter Nachname Vorname FkSalon
1 Krause Sabine 1
2 Schrotter Claudia 1
3 Hermann Markus 1
4 Krause Christoph 2
5 Bitter Manuel 2
Tabelle: Termin
IdTermin Datum Rechnungsbetrag FkMitarbeiter FkKunde
1 01.11.2012 20 1 1
2 11.12.2012 29 2 2
3 19.02.2013 77 2 3
4 19.02.2013 20 5 4

Grundlegende Abfragen

Einfache Abfrage (Projektion)

SELECT * FROM Mitarbeiter;

Ergebnis:

IdMitarbeiter Nachname Vorname FkSalon
1 Krause Sabine 1
2 Schrotter Claudia 1
3 Hermann Markus 1
4 Krause Christoph 2
5 Bitter Manuel 2

Alias und Spaltenauswahl

SELECT IdMitarbeiter AS Mitarbeiternr, Nachname FROM Mitarbeiter;

Ergebnis:

Mitarbeiternr Nachname
1 Krause
2 Schrotter
3 Hermann
4 Krause
5 Bitter

Filtern von Daten (WHERE)

Einfacher Filter

SELECT Vorname, Nachname FROM Mitarbeiter WHERE Nachname = 'Krause';

Ergebnis:

Vorname Nachname
Sabine Krause
Christoph Krause

Komplexer Filter

SELECT Vorname, Nachname FROM Mitarbeiter 
WHERE (Nachname = 'Krause' OR Vorname = 'Manuel') AND IdMitarbeiter <> 1;

Ergebnis:

Vorname Nachname
Christoph Krause Manuel Bitter

Tabellen verknüpfen (JOINs)

Hier werden die Tabellen `Salon` (Tabelle A) und `Mitarbeiter` (Tabelle B) verknüpft.

Inner Join (Schnittmenge)

A B

SELECT Salon.Name, Mitarbeiter.Nachname 
FROM Salon INNER JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;

Ergebnis: (Salon 3 erscheint nicht, da kein Mitarbeiter zugeordnet ist)

Name Nachname
Friedrich List Frisuren Krause
Friedrich List Frisuren Schrotter
Friedrich List Frisuren Hermann
Hammer Haare Krause
Hammer Haare Bitter

Left Join (Inklusive linker Tabelle)

A B

SELECT Salon.Name, Mitarbeiter.Nachname 
FROM Salon LEFT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;

Ergebnis: (Salon 3 wird mit NULL aufgeführt)

Name Nachname
Friedrich List Frisuren Krause
Friedrich List Frisuren Schrotter
Friedrich List Frisuren Hermann
Hammer Haare Krause
Hammer Haare Bitter
Kaiserschnitt NULL

Right Join (Inklusive rechter Tabelle)

A B

SELECT Salon.Name, Mitarbeiter.Nachname 
FROM Salon RIGHT JOIN Mitarbeiter ON Salon.IdSalon = Mitarbeiter.FKSalon;

Gruppierung und Aggregate

SELECT SUM(Rechnungsbetrag) AS Umsatz, Mitarbeiter.Nachname 
FROM Termin 
INNER JOIN Mitarbeiter ON Termin.FKMitarbeiter = Mitarbeiter.IdMitarbeiter 
GROUP BY Mitarbeiter.IdMitarbeiter 
HAVING Umsatz > 100;

Ergebnis:

Umsatz Mitarbeiter
106 Schrotter

(Berechnung: Claudia Schrotter [ID 2] hatte Termine über 29 und 77 Euro.)