1.7.2) DQL - Data Query Language

1.7.2.1) Grundkonstruktion einer SQL-Abfrage

Grundkonstruktion einer SQL-Abfrage ist von der Form

SELECT attributListe FROM relation

Beispiel
SELECT name,adresse FROM restaurant;

entspricht
$ π_{name,adresse}(restaurant) $

SELECT * FROM restaurant;
/*liefert die gesamte Tabelle (d.h. mit allen Attributen)



SQL-Abfrage mit Verknüpfung mehrerer Relationen:

SELECT attributListe FROM relationen WHERE bedingung

Eine solche SQL-Abfrage wird ausgewertet, indem zunächst das kartesische Produkt der in der FROM-Klausel angegebenen Relationen gebildet wird. Daraus werden dann jene Tupel ausgewählt, die die in der WHERE-Klausel angegebenen Bedingungen erfüllen. Zudem wird auf die in der SELECT-Klausel angegebenen Attribute dieser Tupel projiziert.

Beispiel

Wir wollen wissen welche Speisen in welchem Restaurant angeboten werden.

SELECT * FROM Speise, Restaurant WHERE Restaurant.rnr = Speise.rnr;

Die Bedingunng in der WHERE-Klausel kann sich aus mehreren, durch die logischen Operatoren AND, OR und NOT verbundenen Teilbedingungen zusammensetzen.

Beispiel
	SELECT rnr, name, haube, typ
	FROM restaurant
	WHERE haube > 1 AND NOT (typ='österreichisch' OR typ='international');

In der SELECT-Klausel können auch Ausdrücke, die aus Attributen berechnet werden, stehen. Durch das Schlüsselwort AS kann einem so berechneten Ausdruck ein Attributname zugewiesen werden.

Beispiel

Wir wollen alle Paare von Restaurants auswählen, die sich um mehr als zwei Hauben unterscheiden und die Differenz der Hauben ausgeben.

	SELECT r1.name, r2.name, (r2.haube-r1.haube) AS differenz
	FROM restaurant r1, restaurant r2
	WHERE r1.haube +2 < r2.haube;

In SQL werden Duplikate, d.h. Ergebnistupel mit identischen Werten, nicht automatisch eliminiert. Um Duplikate zu eliminieren, muss der Liste von ausgewählten Attribute das Schlüsselwort DISTINCT vorangestellt werden.
Durch die Angabe einer ORDER BY-Klausel mit den Schlüsselworten ASC oder DESC kann die Ausgabe aufsteigend bzw. absteigend nach bestimmten Attributen sortiert werden. Der Defaultwert ist ASC.

Beispiel

Wir wollen eine alphabetisch sortierte Liste aller Speisen von Restaurants mit mehr als einer Haube.

	SELECT DISTINCT s.name
	FROM Restaurant r, Speise r
	WHERE (r.rnr = s.rnr) AND (r.haube>1)
	ORDER BY s.name, s.preis;

Übungsbeispiele

Gegeben sind folgende Relationen

Person (id, name, plz)
Orte (plz, ort)
Mitarbeiter (id, gehalt, abtnr)
Kunde (id, rabatt)
Abteilung (abtnr, name)
PKW (marke, ps, id, fahrgestellnr)

Aufgaben

Entwickeln Sie SQL-Anweisungen für folgende Abfragen

  1. Geben Sie die Namen aller Personen aus Amstetten aus
  2. Geben Sie die Namen aller Mitarbeiter aus Amstetten aus
  3. Gesucht sind die Namen aller Mitarbeiter die auch Kunden sind
  4. Namen aller Mitarbeiter die PKWs mit mehr als 1000 PS fahren
  5. Gesucht sind die Namen jener Orte, in denen Mitarbeiter wohnen, die in einer Abteilung „Buchhaltung“ arbeiten
Lösungen
1)
SELECT name
FROM Person p, Orte o
WHERE o.ort="Amstetten" AND p.plz=o=plz;
 
 
2)
SELECT name
FROM Person p, Orte o, Mitarbeiter m
WHERE m.id=p.id AND o.ort="Amstetten" AND p.plz=o.plz; 
 
 
3)
SELECT name
FROM Person p, Orte o, Mitarbeiter m
WHERE m.id=p.id AND m.id=k.id;
 
4)
SELECT name
FROM Person p, Mitarbeiter m, PKW
WHERE p.id=m.id AND PKW.id=p.id AND PKW.ps>100;
 
5)
SELECT ort
FROM Orte o, Mitarbeiter m, Person p, Abteilung a
WHERE o.plz=p.plz AND p.id=m.id AND m.abtnr=a.abtnr AND p.plz=o.plz;

1.7.2.2) Die WHERE-Klausel

Neben den Boolschen Funktionen (AND,OR,NOT) sind folgende weitere Angaben zulässig:

IN-Operator

Anstatt eine Reihe von OR-Verknüpfungen durchzuführen, kann auch der IN-Operator verwendet werden.

Bsp:

SELECT * FROM ... WHERE typ IN ('österreichisch', 'international');

BETWEEN-Operator

Bsp.:

SELECT * FROM ... WHERE preis BETWEEN 100 AND 150;
 
//ist dasselbe wie
 
SELECT * FROM ... WHERE preis >= 100 AND preis<=150;

IS NULL-Operator

Bsp.: Es sollen alle Personen gesucht werden, die beim Attribut TelNr den NULL-Wert eingetragen haben.

SELECT * FROM ... WHERE TelNr IS NULL;

LIKE-Operator

Der Like-Operator ist ein Vergleichsoperator, der Datenwerte einer Spalte mit einem vorgegebenen Muster vergleicht.

Allgemeine Form:

AttributName [NOT] LIKE 'muster';

Dabei haben in 'muster' zwei Zeichen eine besondere Bedeutung:



Bsp.: Alle Speisen deren Name mit 'M' beginnt

SELECT Name FROM Speise WHERE Name LIKE 'M%';


Bsp.: Alle Restaurants, welche an 2. Stelle im Namen ein 'o' haben

SELECT Name FROM Restaurant WHERE Name LIKE '_o%';

1.7.2.3) Mengenoperationen

SQL stellt die Mengenoperationen UNION (Vereinigung), INTERSECT (Durchschnitt) und EXCEPT (Mengendifferenz) für typkompatible Relationen (d.h. Relationen mit der gleichen Anzahl von jeweils typkompatiblen Attributen) zur Verfügung.

Beispiel: Wir wollen eine Liste der Namen aller Restaurants und der Namen aller Speisen

(SELECT Name FROM Restaurant)
UNION
(SELECT Name FROM Speise)
 
oder
 
SELECT Name FROM Restaurant WHERE Name NOT IN 
(SELECT Name FROM Speise)

Mit typkompatiblen Relationen sind dabei nicht die Relationen Restaurant oder Speise gemeint, sondern die Ergebnisse der beiden SELECT Statements.

1.7.2.4) Aggregatfunktionen und Gruppierung

Aggregatfunktionen

Es gibt folgende Aggregatfunktionen in SQL:

Bsp: Gesucht ist der Preis des teuersten Burgers:

SELECT MAX(Preis)
FROM Speise
WHERE Name LIKE '%Burger%';

Bsp.: Wie viele Speisen werden im Brauhof angeboten?

SELECT COUNT(*)   //COUNT(*) zählt alle Tupel
FROM Restaurant r, Speise s,
WHERE r.rnr = s.rnr AND r.name="Brauhof";

Gruppierung

Die Select-Abfrage kann um eine Klause „GROUP BY attributListe“ und eine Klausel „HAVING bedingung“ ergänzt werden, um Gruppen von Tupeln zu bilden und auf diese Gruppen Aggregatfunktionen anzuwenden.
Dabei werden diese Tupel nach gemeinsamen Werten in den in der GROUP BY-Klausel angeführten Attributen gruppiert. Von diesen Gruppen werden jene eliminiert, die die in der HAVING-Klausel angegebene Bedingung nicht erfüllen.

Anschließend werden etwaige in der SELECT-Klausel angegebenen Aggregatfunktionen auf jede der verbliebenen Gruppen angewendet. Diese Aggregatfunktionen (außer COUNT) können auch auf arithmetische Ausdrücke über Attributen angewandt werden.

Beispiel

Relation Restaurant
rnrRNameAdrHaube
1McDonaldsAmstetten0
2McDonaldsYbbs0
3HollywoodAmstetten1
4Casa VeneziaAmstetten2
5grill.BarAmstetten2
6SchinakelGrein1

Frage: Wie viele Restaurants haben die gleiche Haubenanzahl?

SELECT Haube, COUNT(*) AS AnzahlRestaurants
FROM Restaurant
GROUP BY Haube;


Ergebnis:

HaubeAnzahlRestaurants
02
12
22

Frage: Wie viele Restaurants in Amstetten haben die gleiche Haubenanzahl?

SELECT Haube, COUNT(*) AS AnzahlRestaurants
FROM Restaurant
WHERE Adr='Amstetten'
GROUP BY Haube;


Ergebnis:

HaubeAnzahlRestaurants
01
11
22

Beispiel

Gesucht ist eine SQL-Abfrage, die alle Restaurants (rnr und name) und die Anzahl der jeweils gebotenen Speisen ausgibt:

Relation Restaurant
rnrRNameAdrHaube
1McDonaldsAmstetten0
2McDonaldsYbbs0
3HollywoodAmstetten1
4Casa VeneziaAmstetten2
5grill.BarAmstetten2
6SchinakelGrein1
Relation Speise
rnrSNamePreis
1Hamburger1
2Hamburger1
2Cheeseburger1,30
3Hawaii8,6
4Hawaii9
5Salat5
1Salat1,80
SELECT r.rnr, r.name, COUNT(*) AS Anzahl
FROM Restaurant r, Speise s
WHERE r.rnr=s.rnr
GROUP BY r.rnr, r.name;


1. Schritt: JOIN

1McDonaldsAmstetten0Hamburger1
1McDonaldsAmstetten0Salat1,80
2McDonaldsYbbs0Hamburger1
2McDonaldsYbbs0Cheeseburger1,30
3HollywoodAmstetten1Hawaii8,6
4Casa VeneziaAmstetten2Hawaii9
5grill.BarAmstetten2Salat5

2. Schritt: GROUP BY

1McDonaldsAmstetten0Hamburger1
1McDonaldsAmstetten0Salat1,80
2McDonaldsYbbs0Hamburger1
2McDonaldsYbbs0Cheeseburger1,30
3HollywoodAmstetten1Hawaii8,6
4Casa VeneziaAmstetten2Hawaii9
5grill.BarAmstetten2Salat5

3. Schritt: COUNT(*) AS Anzahl (pro Gruppe)

rnrRNameAnzahl
1McDonalds2
2McDonalds2
3Hollywood1
4Casa Venezia1
5grill.Bar1

Beispiel

Gesucht sind alle Restaurants (rnr, name), welche mehr als 5 verschiedene (Tipp: Schlüsselwort DISTINCT) Speisen anbieten!

Relation Restaurant
rnrRNameAdrHaube
1McDonaldsAmstetten0
2McDonaldsYbbs0
3HollywoodAmstetten1
4Casa VeneziaAmstetten2
5grill.BarAmstetten2
6SchinakelGrein1
Relation Speise
rnrSNamePreis
1Hamburger1
2Hamburger1
2Cheeseburger1,30
3Hawaii8,6
4Hawaii9
5Salat5
1Salat1,80
SELECT r.rnr, r.name
FROM Restaurant r, Speise s
WHERE r.rnr=s.rnr
GROUP BY r.rnr, r.name
HAVING COUNT(DISTINCT s.name) > 5;

1. Schritt: JOIN

1McDonaldsAmstetten0Hamburger1
1McDonaldsAmstetten0Salat1,80
2McDonaldsYbbs0Hamburger1
2McDonaldsYbbs0Cheeseburger1,30
3HollywoodAmstetten1Hawaii8,6
4Casa VeneziaAmstetten2Hawaii9
5grill.BarAmstetten2Salat5

2. Schritt: GROUP BY

1McDonaldsAmstetten0Hamburger1
1McDonaldsAmstetten0Salat1,80
2McDonaldsYbbs0Hamburger1
2McDonaldsYbbs0Cheeseburger1,30
3HollywoodAmstetten1Hawaii8,6
4Casa VeneziaAmstetten2Hawaii9
5grill.BarAmstetten2Salat5

3. Schritt: HAVING COUNT(DISTINCT s.name)>5

rnrRName

Beispiel

Gesucht ist eine SQL-Abfrage, die die rnr und die Anzahl der Haube jener Restaurants angibt, deren teuerste Speise mehr als 8€ kostet. Weiters werden jeweils die Anzahl der Speisen als auch deren Durchschnittspreis ausgegeben.

Relation Restaurant
rnrRNameAdrHaube
1McDonaldsAmstetten0
2McDonaldsYbbs0
3HollywoodAmstetten1
4Casa VeneziaAmstetten2
5grill.BarAmstetten2
6SchinakelGrein1
Relation Speise
rnrSNamePreis
1Hamburger1
2Hamburger1
2Cheeseburger1,30
3Hawaii8,6
4Hawaii9
5Salat5
1Salat1,80
4Hühnerstreifensalat8,20
SELECT r.rnr, r.haube, COUNT(DISTINCT s.name) AS Anzahl, AVG(s.preis) AS AVGPreis
FROM Restaurant r, Speise s
WHERE r.rnr=s.rnr
GROUP BY r.rnr, haube
HAVING MAX (s.preis)>8;

1. Schritt: JOIN

1McDonaldsAmstetten0Hamburger1
1McDonaldsAmstetten0Salat1,80
2McDonaldsYbbs0Hamburger1
2McDonaldsYbbs0Cheeseburger1,30
3HollywoodAmstetten1Hawaii8,6
4Casa VeneziaAmstetten2Hawaii9
4Casa VeneziaAmstetten2Hühnerstreifensalat7,20
5grill.BarAmstetten2Salat5

2. Schritt: GROUP BY

1McDonaldsAmstetten0Hamburger1
1McDonaldsAmstetten0Salat1,80
2McDonaldsYbbs0Hamburger1
2McDonaldsYbbs0Cheeseburger1,30
3HollywoodAmstetten1Hawaii8,6
4Casa VeneziaAmstetten2Hawaii9
4Casa VeneziaAmstetten2Hühnerstreifensalat7,20
5grill.BarAmstetten2Salat5

3. Schritt: HAVING MAX(s.preis)>8

3HollywoodAmstetten1Hawaii8,6
4Casa VeneziaAmstetten2Hawaii9
4Casa VeneziaAmstetten2Hühnerstreifensalat7,20

4. Schritt: SELECT r.rnr, r.name, COUNT(DISTINCT s.name) AS Anzahl, AVG(s.preis) AS AVGPreis

rnrRNameAnzahlPreis
3Hollywood18,6
4Casa Venezia28,1