Structured Query Language (SQL)

Structured Query Language (SQL)

Beim Arbeiten mit relationalen Datenbanken kommt nicht um SQL herum. Mit dieser Anfragesprache wurde ein Standart gesetzt um mit Datenbanken zukommunizieren. Dieser Standart hat sich über verschiedene Datenbank-Systeme verbreitet und immer weiterentwickelt. Wie man mit dieser Sprache umgeht und was die Besonderheiten sind, behandel ich in diesen Artikel.

Im ersten Teil beschäftigen wir uns mit DML (Data modification language), also dem Anfragen und ändern von Daten. Im zweiten Teil geht es dann um DDL (Data definition language), welche sich mit dem erstellen und verändern der Relationen befasst. Der zweite Teil wird jedoch ein eigener Artikel sein um bessere Übersicht zu behalten.

Aufbau der Sprache

Wie man es bei Programmiersprachen kennt muss auch eine Anfragesprache bestimmte Kriterien erfüllen. Dazu zählen dann Punkte wie

  • Anfragen sollten funktionieren ohne komplette Programme schreiben zu müssen
  • Deskriptivität: Anfragen werden in der Form „Was will ich haben?“ gestellt
  • Mengenorientiert/Abgeschlossenheit: Ergebnisse sind immer Mengen und können wiederverwendet werden
  • Jede Operation hat eine Komplexität von < O(n2)
  • Sicherheit: Anfragen können nicht in Endlosschleifen enden

Wichtig es handelt sich hier um eine Anfragesprache! Nicht um eine Programmiersprache. Das sind zwei verschiedene Konstrukte.

Anfragen und deren Struktur

Wollen wir nun etwas aus unserer Datenbank auslesen werden wir grundlegend immer dieselbe Struktur haben. Dabei handelt es sich um die SFW-Form, welche einfach nur vorgibt, dass unsere Anfrage grob so aussieht

SELECT ...      // Was will ich?
FROM ...        // Von wo will ich es?
WHERE ...       // Welche Bedingungen soll es erfüllen?

Diese Form kann natürlich noch erweitert werden.

SELECT ...      // Was will ich?
FROM ...        // Von wo will ich es?
WHERE ...       // Welche Bedingungen soll es erfüllen?
GROUP BY ...    // Gruppiere nach Attribute
HAVING ...      // Die Gruppe muss ... haben
ORDER BY ...    // Reihenfolge bei der Ausgabe

Für jetzt machen wir ein paar Beispiele anhand einer Datenbank.

- Gebe mir die Namen aller Schüler
SELECT name FROM schüler;

- Gebe mir die Namen der Schüler aus der Klasse 8B
SELECT name FROM schüler WHERE klasse = '8B';

- Gebe mir die Klasse und den Namen des Schülers mit der id = 2
SELECT name, klasse FROM schüler WHERE id = 2;

Kreuzprodukt und Joins

SQL kann auch etwas mathematischer betrachtet werden. Dazu können wir einerseits das Kreuzprodukt einbauen. Mit dem Kreuzprodukt bilden wir also jede Zeile aus der linken Tabelle mit jeder Zeile aus der rechten Tabelle ab. In SQL sieht das dann folgendermaßen aus

SELECT * 
FROM schüler, Raum;

//oder als join formuliert

SELECT *
FROM schüler cross join raum;

Das können wir außerdem jetzt als Grundlage für einen Join nutzen. Dabei fügen wir eine Bedingung ein. Als erstes wollen wir den natural join machen, welcher so funktioniert

SELECT * 
FROM schüler s, Raum r
WHERE s.klasse = r.klasse;

//Oder als join formuliert

SELECT *
FROM schüler join raum;

Dadurch erhalten wir eine Relation welche alle Attribute enthält, wo die Klasse aus schüler gleich der klasse aus Raum ist.

Right-Join

Left-Join

Umbenennung

Ergebnisse aus einer Anfrage können wir umbenennen und mit dieser neuen Bezeichnung ebenfalls wiederverwenden.

SELECT COUNT(id) as anzahl_schüler
FROM schüler;

Duplikate

SQL macht im Gegensatz zur relationalen Algebra keine Duplikateliminierung. Diese müssen wir durch das Keyword distinct selber festlegen. Wollen wir also nur wissen welche Klassen es gibt, müssen wir doppelt vorkommende Klassen rausnehmen.

SELECT DISTINCT klasse
FROM schüler;

Erweiterte Bedingungen

Wenn wir jetzt einen Bereich angeben wollen, der in unserer WHERE-Bedingung geprüft werden soll, könn das entweder so machen

SELECT name
FROM schüler
WHERE id > 1 AND id < 5;

//oder so

SELECT name
FROM schüler
WHERE id BETWEEN 1 AND 5;

Ebenfalls können wir auch Strings überprüfen ob ein bestimmter Text enthalten ist.

SELECT name
FROM schüler
WHERE name like 'Ma%';     //Ausgabe: Mark

Bei Strings im speziellen gibt es wesentlich mehr Operationen. Diese kann man ziemlich leicht bezogen auf euer Datenbanksystem im Internet finden. In meinem Fall beziehe ich mich auf Postgres.

Operationen mit Mengen

Da SQL wie bereits erwähnt mengenorientiert arbeitet, können wir ebenfalls auch Operationen aus diesen Bereich anwenden. Somit ist einerseits union als Keyword verwendbar und ermöglicht uns die Vereinigung anzuwenden. Ebenfalls können wir mit dem keyword intersect auch Schnittmengen bilden, wobei sich in den meisten Fällen hier ein Join eher lohnt, da wir bei komplexeren Anfragen auch weitere Bedingungen einbinden müssen.

//Vereinigung
SELECT *
FROM Schüler union raum;

//Schnittmenge
SELECT *
FROM Schüler intersect raum;

//Ohne-Formulierung
SELECT *
FROM Schüler EXCEPT (SELECT * FROM raum);

Agregatfunktion

In SQL gibt es auch bereits vordefinierte Operationen. Diese können wir wie Methoden/Funktionen in einer Programmiersprache verwenden und dabei auch Parameter übergeben. Die wichtigsten Funktionen zeige ich hier.

  • MAX()
  • MIN()
  • AVG()
  • COUNT()

Speziell für String-Operationen gibt es sehr viele Agregatfunktionen die man je nach verwendeten System auch in der entsprechenden Dokumentation findet.

ALL, ANY, SOME

Mit diesen Operatoren können wir unserern WHERE-Block etwas erweitern. Normalerweise können wir immer nur einzelne Werte miteinander vergleichen also zbs. schüler.klasse = raum.klasse. Jetzt bekommen wir aber die Möglichkeit mehrere Zeilen zu vergleichen. Das Konzept hier ist ähnlich zu einer For-Schleife.

ALL wird verwendet, wenn die Bedingung, die wir setzen für alle Werte in einer Relation erfüllt sein muss. Im Gegensatz dazu wird ANY oder SOME verwendet, wenn es ausreicht, dass die Bedingung auch nur für wenige Werte war ist.

EXISTS, IN

Neben der Möglichkeit spezifische Werte von mehreren Zeilen in unseren WHERE-Block zubehandeln, können wir ebenfalls diese Zeilen für eine boolsche Abfrage verwenden. Wir können also fragen, ob ein Wert in einer Menge enthalten ist oder ob eine bestimmte Ansammlung an Tupeln in der Menge enthalten sind.

Gebe mir alle Schüler, wenn es einen Schüler mit den Namen Mark gibt

SELECT s1.name
FROM schüler s1
WHERE EXISTS(
      SELECT 1              //1 als symbolischer bool-Wert
      FROM schüler s2
      WHERE s2.name = 'Mark'
      );

Neben der Abfrage ob ein Wert existiert, können wir auch eine Liste an Vergleichswerten übergeben, die abgearbeitet wird.

Gebe mir alle Schüler die entweder in Klasse 8B oder 9A sind

SELECT name
FROM schüler s1
WHERE klasse IN ('8B','9A');

Diese Anfrage gibt uns nun alle Werte zurück, die in der Liste enthalten sind. Im Gegensatz zu EXISTS werden hier immer Werte zurückgegeben sofern sie in der Liste sind. Bei EXISTS wird nur eine Menge ausgegeben, sofern die Bedingung für alle Tupel in der Subquery zutrifft.

Umformulierung von Anfragen

Besonders im akademischen Raum werden gerne Aufgaben gestellt, bei denen bestimmte Anfragen zbs. ohne Agregatfunktionen oder subqueries angegeben werden sollen. Hier zeige ich auch kurz ein paar Beispiele wie man Anfragen umformen kann um den gerecht zu werden.

Suche nach größtem Attributswert

Für solche Anfragen gibt es in SQL wichtige Keywords AL, ANY, SOME. Damit können wir Anfragen die normalerweise mit der Agregatfunktion MAX(*) ausgeführt werden umschreiben. Ein Beispiel könnte so aussehen

Gebe mir den SChüler mit der größten ID

SELECT MAX(id) FROM schüler;       //Lösung mit Agregatfunktion

SELECT s1.id 
FROM schüler s1
WHERE s1.id >= ALL (
         SELECT s2.id 
         FROM schüler s2
         );

Suche nach kleinsten Attributwert

Das ganze können wir natürlich auch andersrum machen indem wir >= durch <= austauschen und somit nach dem kleinsten Wert suchen.

Gebe mir den Schüler mit der kleinsten ID

SELECT MIN(id) FROM schüler;       //Lösung mit Agregatfunktion

SELECT s1.id 
FROM schüler s1
WHERE s1.id <= ALL (
         SELECT s2.id 
         FROM schüler s2
         );

Quellen

https://sibiwiki.de/wiki/index.php?title=SQL-Aufgaben-L%C3%B6sungen (14.9.23 14:59)

https://www.sqlshack.com/understanding-the-sql-except-statement-with-examples/ (14.9.23 16:28)

https://wiki.selfhtml.org/wiki/Datenbank/SQL-Grundlagen (14.9.23 16:38)

https://www.w3schools.com/sql/sql_any_all.asp (15.9.23 12:32)