SQL nun wird es schwieriger

This commit is contained in:
Sven Riwoldt
2026-09-22 13:39:21 +02:00
parent af3537b17b
commit c418fe6153
+146 -37
View File
@@ -194,8 +194,6 @@ Um anzugeben, wie diese Daten sortiert werden sollen, können wir die `DESC`- od
`ORDER BY avg_speed ASC` `ORDER BY avg_speed ASC`
## Datumsangaben behandeln ## Datumsangaben behandeln
Daten in SQL haben ein bestimmtes Format und wir können sie ähnlich wie Zahlen abfragen. Um ein Datum in einer Abfrage zu schreiben, verwendet man das Format: YYYY-MM-DD (2012-09-24) Daten in SQL haben ein bestimmtes Format und wir können sie ähnlich wie Zahlen abfragen. Um ein Datum in einer Abfrage zu schreiben, verwendet man das Format: YYYY-MM-DD (2012-09-24)
@@ -546,7 +544,7 @@ Verfügbare Tabellen und Spalten:
- Products - Products
| id | price | quantity | | id | price | quantity |
| :--- | :---- | :------- | |:-------------------------------- |:----- |:-------- |
| 1 | 154 | 18 | | 1 | 154 | 18 |
| 2 | 98 | 3 | | 2 | 98 | 3 |
| 3 | 54 | 15 | | 3 | 54 | 15 |
@@ -561,8 +559,8 @@ Verfügbare Tabellen und Spalten:
| 12 | 208 | 3 | | 12 | 208 | 3 |
| 13 | 144 | 5 | | 13 | 144 | 5 |
| 14 | 68 | 98 | | 14 | 68 | 98 |
| 15 | 5 | 14 | 15 | 5 | 14 |
Erstellen Sie eine Abfrage, die: | Erstellen Sie eine Abfrage, die: | | |
1. Die Produkt-ID anzeigt 1. Die Produkt-ID anzeigt
2. Jedes Produkt einem von drei Qualitätskontrollteams (0, 1 oder 2) **basierend auf der Produkt-ID unter Verwendung des Modulo-Operators** zuweist; nennen Sie diese Spalte `quality_control` 2. Jedes Produkt einem von drei Qualitätskontrollteams (0, 1 oder 2) **basierend auf der Produkt-ID unter Verwendung des Modulo-Operators** zuweist; nennen Sie diese Spalte `quality_control`
@@ -1036,7 +1034,6 @@ Benenne die Spalte als `worst_criminals`.
| 19 | Kshitija Ladislav | cSA0hA | Caerleon | 2 | | 19 | Kshitija Ladislav | cSA0hA | Caerleon | 2 |
| 20 | Ha-Eun Tatiana | YNYhHV | Kara's Vale | 4 | | 20 | Ha-Eun Tatiana | YNYhHV | Kara's Vale | 4 |
```sql ```sql
select name as worst_criminals from police_report where (report like '%g%' or report like '%b%' or report is null ) and map in ('Caerleon', 'Dewsbury', 'Kirkwall', 'Findochty') order by severe_score desc limit 5 select name as worst_criminals from police_report where (report like '%g%' or report like '%b%' or report is null ) and map in ('Caerleon', 'Dewsbury', 'Kirkwall', 'Findochty') order by severe_score desc limit 5
``` ```
@@ -1140,7 +1137,6 @@ a*a*a
-- Potenz von 3 -- Potenz von 3
``` ```
```sql ```sql
select id , (3*id*id*id*id + 5*id*id*id + 0.9*id*id + 2.2 * id +1 )as quartic from items select id , (3*id*id*id*id + 5*id*id*id + 0.9*id*id + 2.2 * id +1 )as quartic from items
``` ```
@@ -1182,6 +1178,7 @@ Sortiere sie nach dem Datum in absteigender Reihenfolge und benenne die Spalte i
| 12 | 2022-12-19T22:00:00.000Z | | 12 | 2022-12-19T22:00:00.000Z |
| 13 | 2022-10-31T22:00:00.000Z | | 13 | 2022-10-31T22:00:00.000Z |
| 14 | 2023-03-19T22:00:00.000Z | | 14 | 2023-03-19T22:00:00.000Z |
```sql ```sql
select id as game from games where date < "2022-12-21" or date > "2023-03-20" order by date desc select id as game from games where date < "2022-12-21" or date > "2023-03-20" order by date desc
``` ```
@@ -1203,12 +1200,15 @@ SELECT JULIANDAY('2023-02-20 12:00:00')
Dies gibt `2459996.0` Tage zurück Dies gibt `2459996.0` Tage zurück
Julianische Tage beginnen mittags, daher steht `.0` für Mittag, wie im Unterrichtsbeispiel gezeigt, in dem `'2023-02-20 12:00:00'` `2459996.0` zurückgibt. Daher steht `.5` für Mitternacht (auf halbem Weg durch den `JULIANDAY`), nicht für Mittag. Julianische Tage beginnen mittags, daher steht `.0` für Mittag, wie im Unterrichtsbeispiel gezeigt, in dem `'2023-02-20 12:00:00'` `2459996.0` zurückgibt. Daher steht `.5` für Mitternacht (auf halbem Weg durch den `JULIANDAY`), nicht für Mittag.
#### Challenge #### Challenge
verfügbare Tabellen und Spalten: verfügbare Tabellen und Spalten:
- `events`**:** `id`**,** `start`**,** `end` - `events`**:** `id`**,** `start`**,** `end`
| id | start | end | | id | start | end |
| ---- | ----- | ------------------------ | | ------------------------------------------------------------------ | ----- | ------------------------ |
| 1 | 13 | 2009-01-12T22:00:00.000Z | | 1 | 13 | 2009-01-12T22:00:00.000Z |
| 2 | 14 | 2009-10-11T22:00:00.000Z | | 2 | 14 | 2009-10-11T22:00:00.000Z |
| 3 | 15 | 2009-09-14T21:00:00.000Z | | 3 | 15 | 2009-09-14T21:00:00.000Z |
@@ -1219,7 +1219,7 @@ verfügbare Tabellen und Spalten:
| 8 | 20 | 2009-07-25T21:00:00.000Z | | 8 | 20 | 2009-07-25T21:00:00.000Z |
| 9 | 21 | 2008-04-02T21:00:00.000Z | | 9 | 21 | 2008-04-02T21:00:00.000Z |
| 10 | 22 | 2010-01-01T22:00:00.000Z | | 10 | 22 | 2010-01-01T22:00:00.000Z |
Rufe die IDs aller Ereignisse ab, die weniger als drei Tage dauern | Rufe die IDs aller Ereignisse ab, die weniger als drei Tage dauern | | |
```sql ```sql
select id from events where (JULIANDAY(end) - JULIANDAY(start)) < 3 select id from events where (JULIANDAY(end) - JULIANDAY(start)) < 3
@@ -1290,6 +1290,7 @@ SELECT * FROM table1 WHERE STRFTIME('%Y', date_column) = STRFTIME('%Y', 
### Datumsangaben behandeln – Teil 3 ### Datumsangaben behandeln – Teil 3
Verfügbare Tabellen und Spalten: Verfügbare Tabellen und Spalten:
- `events`**:** `id`**,** `start`**,** `end` - `events`**:** `id`**,** `start`**,** `end`
| Id | start | end | | Id | start | end |
@@ -1322,7 +1323,9 @@ Filtere nur die Zeilen, in denen das Jahr der Spalte `start` `2009` ist (`STR
Sortiere die Ergebnisse nach der Dauer in Tagen in absteigender Reihenfolge. Sortiere die Ergebnisse nach der Dauer in Tagen in absteigender Reihenfolge.
Hinweis: Um die Differenz zwischen Datumsangaben zu berechnen, verwende: `JULIANDAY(end) - JULIANDAY(start)` und verwende `ROUND()`, um auf ganze Zahlen zu runden. Hinweis: Um die Differenz zwischen Datumsangaben zu berechnen, verwende: `JULIANDAY(end) - JULIANDAY(start)` und verwende `ROUND()`, um auf ganze Zahlen zu runden.
#### Lösung #### Lösung
```sql ```sql
select id , STRFTIME('%d-%m-%Y', start) as formatted_start, STRFTIME('%d-%m-%Y', end) as formatted_end, ROUND(JULIANDAY(end) - JULIANDAY(start)) AS duration_days from events where STRFTIME('%Y',start) == '2009' order by duration_days desc select id , STRFTIME('%d-%m-%Y', start) as formatted_start, STRFTIME('%d-%m-%Y', end) as formatted_end, ROUND(JULIANDAY(end) - JULIANDAY(start)) AS duration_days from events where STRFTIME('%Y',start) == '2009' order by duration_days desc
``` ```
@@ -1334,10 +1337,13 @@ SQL verfügt über viele integrierte Funktionen, aber in dieser Lektion behandel
Eine Aggregatfunktion erhält ein Feld als Eingabe und berechnet etwas über dieses Feld. Die häufigsten Aggregatfunktionen sind: Eine Aggregatfunktion erhält ein Feld als Eingabe und berechnet etwas über dieses Feld. Die häufigsten Aggregatfunktionen sind:
- `MAX` - Gibt den Maximalwert eines Feldes zurück - `MAX` - Gibt den Maximalwert eines Feldes zurück
- `MIN` - Gibt den Minimalwert eines Feldes zurück - `MIN` - Gibt den Minimalwert eines Feldes zurück
- `AVG` - Gibt den Durchschnittswert eines Feldes zurück - `AVG` - Gibt den Durchschnittswert eines Feldes zurück
- `COUNT` – Gibt die Gesamtzahl der Datensätze zurück - `COUNT` – Gibt die Gesamtzahl der Datensätze zurück
- `SUM` – Gibt die Summe aller Nicht-Null-Werte in einem Feld zurück - `SUM` – Gibt die Summe aller Nicht-Null-Werte in einem Feld zurück
Du kannst diese Funktionen in deiner SELECT-Anweisung wie folgt verwenden: Du kannst diese Funktionen in deiner SELECT-Anweisung wie folgt verwenden:
@@ -1357,7 +1363,9 @@ Oder um mehrere Aggregatfunktionen gleichzeitig zu erhalten:
```sql ```sql
SELECT MAX(salary), MIN(salary), AVG(salary) FROM employees SELECT MAX(salary), MIN(salary), AVG(salary) FROM employees
``` ```
### Challenge ### Challenge
> Verfügbare Tabellen und Spalten: > Verfügbare Tabellen und Spalten:
> >
> - `sales`**:** `product_id`**,** `price_per_unit`**,**  `quantity` > - `sales`**:** `product_id`**,** `price_per_unit`**,**  `quantity`
@@ -1376,22 +1384,23 @@ Dein Ergebnis sollte genau diese Spaltennamen haben:
- `max_unit_price`  - `max_unit_price` 
- `total_revenue` - `total_revenue`
|product_id|price_per_unit|quantity| | product_id | price_per_unit | quantity |
|:---|:---|:---| |:---------- |:-------------- |:-------- |
|4|19|1| | 4 | 19 | 1 |
|5|16|3| | 5 | 16 | 3 |
|6|13|2| | 6 | 13 | 2 |
|7|21|1| | 7 | 21 | 1 |
|8|16|3| | 8 | 16 | 3 |
|9|23|5| | 9 | 23 | 5 |
|10|27|1| | 10 | 27 | 1 |
|11|18|2| | 11 | 18 | 2 |
|12|21|3| | 12 | 21 | 3 |
|13|22|2| | 13 | 22 | 2 |
```sql ```sql
select count(product_id) as total_transactions, avg(quantity) as avg_quantity, max(price_per_unit) as max_unit_price, sum(price_per_unit * quantity) as total_revenue from sales select count(product_id) as total_transactions, avg(quantity) as avg_quantity, max(price_per_unit) as max_unit_price, sum(price_per_unit * quantity) as total_revenue from sales
``` ```
## Integrierte Aggregatfunktionen Teil 2 ## Integrierte Aggregatfunktionen Teil 2
Manchmal müssen wir Aggregatfunktionen auf komplexere Weise verwenden, etwa indem wir jede Zeile mit einem Aggregatwert vergleichen. Hier kommen verschachtelte Abfragen ins Spiel. Manchmal müssen wir Aggregatfunktionen auf komplexere Weise verwenden, etwa indem wir jede Zeile mit einem Aggregatwert vergleichen. Hier kommen verschachtelte Abfragen ins Spiel.
@@ -1400,30 +1409,43 @@ Wenn du Berechnungen durchführen möchtest, die einzelne Zeilen mit aggregierte
Dies liefert nicht das gewünschte Ergebnis pro Zeile: Dies liefert nicht das gewünschte Ergebnis pro Zeile:
```sql ```sql
SELECT value + MIN(value)FROM table1 SELECT value + MIN(value) FROM table1
``` ```
Der Grund ist, dass Aggregatfunktionen auf der gesamten Spalte arbeiten, während der Verweis „value“ versucht, zeilenweise zu arbeiten. Um dies zu lösen, verwenden wir eine verschachtelte Abfrage: Der Grund ist, dass Aggregatfunktionen auf der gesamten Spalte arbeiten, während der Verweis „value“ versucht, zeilenweise zu arbeiten. Um dies zu lösen, verwenden wir eine verschachtelte Abfrage:
```sql ```sql
SELECT value + (SELECT MIN(value) FROM table1)FROM table1 SELECT value + (SELECT MIN(value) FROM table1) FROM table1
``` ```
Das funktioniert, weil die verschachtelte Abfrage `(SELECT MIN(value) FROM table1)` zuerst ausgeführt wird und einen einzelnen Wert zurückgibt, der dann in der Hauptabfrage für jede Zeile verwendet werden kann. Das funktioniert, weil die verschachtelte Abfrage `(SELECT MIN(value) FROM table1)` zuerst ausgeführt wird und einen einzelnen Wert zurückgibt, der dann in der Hauptabfrage für jede Zeile verwendet werden kann.
Häufige Anwendungsfälle für verschachtelte Aggregationen: Häufige Anwendungsfälle für verschachtelte Aggregationen:
1. Jeden Wert mit dem Durchschnitt vergleichen 1. Jeden Wert mit dem Durchschnitt vergleichen
2. Prozentsatz der Gesamtsumme berechnen 2. Prozentsatz der Gesamtsumme berechnen
3. Unterschiede zu Maximal- oder Minimalwerten finden 3. Unterschiede zu Maximal- oder Minimalwerten finden
### Challenge
#################################################
`SELECT name, `
       `amount + AVG(amount)` <-- Fehler
`FROM orders`
In SQLite führt dies nicht zu einem Syntaxfehler, aber die Kombination einer spaltenbezogenen Zeile mit einem unqualifizierten Aggregat reduziert das Ergebnis auf eine einzelne Aggregatzeile statt auf ein Ergebnis pro Zeile. Verwende eine Unterabfrage: `amount + (SELECT AVG(amount) FROM orders)`.
#################################################
Verfügbare Tabellen und Spalten: Verfügbare Tabellen und Spalten:
> - `items`**:** `id`**,** `price` > - `items`**:** `id`**,** `price`
| id | price | | id | price |
| --- | ----- | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- |
| 4 | 19 | | 4 | 19 |
| 5 | 16 | | 5 | 16 |
| 6 | 13 | | 6 | 13 |
@@ -1434,7 +1456,7 @@ Verfügbare Tabellen und Spalten:
| 11 | 18 | | 11 | 18 |
| 12 | 21 | | 12 | 21 |
| 13 | 22 | | 13 | 22 |
Berechne, um wie viel der Preis jedes Elements den Durchschnittspreis aller Elemente **übersteigt**. Zeige die ID des Elements, seinen Preis und die Differenz zum Durchschnitt an. Benenne die Differenzspalte als `diff_from_avg`. | Berechne, um wie viel der Preis jedes Elements den Durchschnittspreis aller Elemente **übersteigt**. Zeige die ID des Elements, seinen Preis und die Differenz zum Durchschnitt an. Benenne die Differenzspalte als `diff_from_avg`. | |
Sortiere die Ergebnisse nach der Differenz in absteigender Reihenfolge. Sortiere die Ergebnisse nach der Differenz in absteigender Reihenfolge.
@@ -1450,12 +1472,12 @@ Wir haben bisher Daten für das gesamte Feld berechnet und werden nun die Mögli
**workers** **workers**
|id|area|age| | id | area | age |
|---|---|---| | --- | ---- | --- |
|1|A|35| | 1 | A | 35 |
|2|A|37| | 2 | A | 37 |
|3|B|29| | 3 | B | 29 |
|4|B|39| | 4 | B | 39 |
Wenn wir  Wenn wir 
@@ -1475,10 +1497,10 @@ SELECT area, AVG(age) as avg_age FROM workers GROUP BY area
Das Ergebnis: Das Ergebnis:
|Bereich|Durchschnittsalter| | Bereich | Durchschnittsalter |
|---|---| | ------- | ------------------ |
|A|36| | A | 36 |
|B|34| | B | 34 |
Jetzt wissen wir, dass das Durchschnittsalter in Bereich `A 36` und das Durchschnittsalter in Bereich `B 34` ist. Jetzt wissen wir, dass das Durchschnittsalter in Bereich `A 36` und das Durchschnittsalter in Bereich `B 34` ist.
@@ -1490,13 +1512,16 @@ Was macht `GROUP BY`?
Berechnet Aggregatwerte für jede Gruppe separat Berechnet Aggregatwerte für jede Gruppe separat
Was würde diese Abfrage zurückgeben? Was würde diese Abfrage zurückgeben?
```sql ```sql
SELECT COUNT(id) FROM workers GROUP BY area SELECT COUNT(id) FROM workers GROUP BY area
``` ```
Die Anzahl der Arbeiter in jedem Bereich, aber ohne anzuzeigen, welcher Bereich Die Anzahl der Arbeiter in jedem Bereich, aber ohne anzuzeigen, welcher Bereich
Die Abfrage gruppiert nach Bereich und zählt, aber da der Bereich nicht in SELECT enthalten ist, siehst du nur die Zählungen, ohne zu wissen, welchen Bereich sie repräsentieren. Die Abfrage gruppiert nach Bereich und zählt, aber da der Bereich nicht in SELECT enthalten ist, siehst du nur die Zählungen, ohne zu wissen, welchen Bereich sie repräsentieren.
### Challenge ### Challenge
| name | type | pH | | name | type | pH |
| ------------ | --------- | ---- | | ------------ | --------- | ---- |
| Celery | vegetable | 5.8 | | Celery | vegetable | 5.8 |
@@ -1515,5 +1540,89 @@ Die Abfrage gruppiert nach Bereich und zählt, aber da der Bereich nicht in SELE
| Strawberries | berry | 3.3 | | Strawberries | berry | 3.3 |
| Blueberries | berry | 3.7 | | Blueberries | berry | 3.7 |
| Grapes | berry | 3.9 | | Grapes | berry | 3.9 |
select type, round(avg(pH),2) as ph_average from foods group by type
```sql
select type, round(avg(pH),2) as ph_average from foods group by type
```
## Gruppierung Teil 2
Das Schlüsselwort `WHERE` führt eine Bedingung für jeden Datensatz einzeln aus. Zum Beispiel:
```sql
SELECT * FROM table1 WHERE col1 > col2
```
`col1 > col2` wird für jeden Datensatz ausgeführt und prüft, ob die Bedingung erfüllt ist.
Aber was ist, wenn wir aggregierte Ergebnisse filtern möchten? Zum Beispiel:
```sql
SELECT category, AVG(price) FROM table1 WHERE AVG(price) > 40 GROUP BY category
```
**Das wird nicht funktionieren**, weil `WHERE` keine Aggregationen überprüfen kann. Dafür haben wir das Schlüsselwort<mark> `HAVING`. Es filtert Daten nach der Aggregatbedingung.</mark>
```sql
SELECT category, AVG(price) FROM table1 GROUP BY category HAVING AVG(price) > 40
```
Dadurch werden alle Kategorien herausgefiltert, deren Durchschnittspreis größer als 40 ist.
Wenn wir die `HAVING`- und `WHERE`-Klausel kombinieren möchten, schreiben wir:
```sql
SELECT category, AVG(price) FROM table1 WHERE price > 25 GROUP BY category HAVING AVG(price) > 40
```
Zuerst wird Datensatz für Datensatz vorgegangen und alle Datensätze gefiltert, bei denen der Preis größer als 25 ist, und erst danach wird die `GROUP BY`-Klausel ausgeführt und jede Kategorie gefiltert, deren Durchschnittspreis größer als 40 ist.
####################################################
Warum schlägt diese Abfrage fehl?
```sql
SELECT category, AVG(price) FROM productsWHERE AVG(price) > 50GROUP BY category
```
`WHERE` kann keine Aggregatfunktionen filtern
####################################################
### Challenge
Verfügbare Tabellen und Spalten:
> - `earthquakes`**:** `location`**,** `amplitude`**,** `period`
Die Richterskala ist eine logarithmische Skala, die zur Messung der Magnitude von Erdbeben verwendet wird.
Wir müssen für jeden Ort die durchschnittliche Magnitude aller schweren Erdbeben zurückgeben.
Ein schweres Erdbeben ist definiert als:
- Die Amplitude ist größer oder gleich 1.
- Die Periode der Wellen ist größer oder gleich 1 Minute.
Für diese Herausforderung verwenden wir eine andere Formel: `M = (A/T)^2 / T`, die äquivalent zu `M = ((A/T)*(A/T)) / T` ist. Hier ist `M` die Magnitude, `A` die Spalte `amplitude` und `T` die Spalte `period`.
Gib den Ort und die durchschnittliche Magnitude jedes Ortes zurück und berücksichtige dabei nur die schweren Erdbeben (benenne die Spalte `avg_magnitude`). Nimm in dein Ergebnis nur die Orte auf, bei denen `avg_magnitude` größer als 1 ist.
Runde die Ergebnisse auf 2 Dezimalstellen.
| location | amplitude | period |
| --- | --- | --- |
| Stonebri | 0.01 | 1 |
| Readat | 0.003 | 24 |
| Chelten | 5 | 0.2 |
| Stonebri | 74 | 49 |
| Stonebri | 11 | 62 |
| Readat | 0.008 | 0.34 |
| Chelten | 73 | 13 |
| Hamwyawi | 68 | 72 |
| Chelten | 3 | 1.2 |
| Hamwyawi | 64 | 45 |
| Hamwyawi | 0.0005 | 1.2 |
| Stonebri | 13 | 1.6 |