diff --git a/SQL.md b/SQL.md index 95e6ac2..fbf6733 100644 --- a/SQL.md +++ b/SQL.md @@ -194,8 +194,6 @@ Um anzugeben, wie diese Daten sortiert werden sollen, können wir die `DESC`- od `ORDER BY avg_speed ASC` - - ## 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) @@ -545,24 +543,24 @@ Verfügbare Tabellen und Spalten: - `**products**`**:** `**id**`**,** `**price**`, `quantity` - Products -| id | price | quantity | -| :--- | :---- | :------- | -| 1 | 154 | 18 | -| 2 | 98 | 3 | -| 3 | 54 | 15 | -| 4 | 142 | 14 | -| 5 | 70 | 2 | -| 6 | 189 | 7 | -| 7 | 44 | 3 | -| 8 | 62 | 16 | -| 9 | 101 | 8 | -| 10 | 192 | 9 | -| 11 | 4 | 21 | -| 12 | 208 | 3 | -| 13 | 144 | 5 | -| 14 | 68 | 98 | -| 15 | 5 | 14 -Erstellen Sie eine Abfrage, die: +| id | price | quantity | +|:-------------------------------- |:----- |:-------- | +| 1 | 154 | 18 | +| 2 | 98 | 3 | +| 3 | 54 | 15 | +| 4 | 142 | 14 | +| 5 | 70 | 2 | +| 6 | 189 | 7 | +| 7 | 44 | 3 | +| 8 | 62 | 16 | +| 9 | 101 | 8 | +| 10 | 192 | 9 | +| 11 | 4 | 21 | +| 12 | 208 | 3 | +| 13 | 144 | 5 | +| 14 | 68 | 98 | +| 15 | 5 | 14 | +| Erstellen Sie eine Abfrage, die: | | | 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` @@ -1036,7 +1034,6 @@ Benenne die Spalte als `worst_criminals`. | 19 | Kshitija Ladislav | cSA0hA | Caerleon | 2 | | 20 | Ha-Eun Tatiana | YNYhHV | Kara's Vale | 4 | - ```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 ``` @@ -1140,7 +1137,6 @@ a*a*a -- Potenz von 3 ``` - ```sql 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 | | 13 | 2022-10-31T22:00:00.000Z | | 14 | 2023-03-19T22:00:00.000Z | + ```sql select id as game from games where date < "2022-12-21" or date > "2023-03-20" order by date desc ``` @@ -1203,23 +1200,26 @@ SELECT JULIANDAY('2023-02-20 12:00:00') 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. + #### Challenge + verfügbare Tabellen und Spalten: + - `events`**:** `id`**,** `start`**,** `end` -| id | start | end | -| ---- | ----- | ------------------------ | -| 1 | 13 | 2009-01-12T22:00:00.000Z | -| 2 | 14 | 2009-10-11T22:00:00.000Z | -| 3 | 15 | 2009-09-14T21:00:00.000Z | -| 4 | 16 | 2009-02-19T22:00:00.000Z | -| 5 | 17 | 2009-08-07T21:00:00.000Z | -| 6 | 18 | 2010-12-23T22:00:00.000Z | -| 7 | 19 | 2009-07-13T21:00:00.000Z | -| 8 | 20 | 2009-07-25T21:00:00.000Z | -| 9 | 21 | 2008-04-02T21:00:00.000Z | -| 10 | 22 | 2010-01-01T22:00:00.000Z | -Rufe die IDs aller Ereignisse ab, die weniger als drei Tage dauern +| id | start | end | +| ------------------------------------------------------------------ | ----- | ------------------------ | +| 1 | 13 | 2009-01-12T22:00:00.000Z | +| 2 | 14 | 2009-10-11T22:00:00.000Z | +| 3 | 15 | 2009-09-14T21:00:00.000Z | +| 4 | 16 | 2009-02-19T22:00:00.000Z | +| 5 | 17 | 2009-08-07T21:00:00.000Z | +| 6 | 18 | 2010-12-23T22:00:00.000Z | +| 7 | 19 | 2009-07-13T21:00:00.000Z | +| 8 | 20 | 2009-07-25T21:00:00.000Z | +| 9 | 21 | 2008-04-02T21:00:00.000Z | +| 10 | 22 | 2010-01-01T22:00:00.000Z | +| Rufe die IDs aller Ereignisse ab, die weniger als drei Tage dauern | | | ```sql 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 Verfügbare Tabellen und Spalten: + - `events`**:** `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. Hinweis: Um die Differenz zwischen Datumsangaben zu berechnen, verwende: `JULIANDAY(end) - JULIANDAY(start)` und verwende `ROUND()`, um auf ganze Zahlen zu runden. + #### Lösung + ```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 ``` @@ -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: - `MAX` - Gibt den Maximalwert eines Feldes zurück + - `MIN` - Gibt den Minimalwert eines Feldes zurück + - `AVG` - Gibt den Durchschnittswert eines Feldes zurück - `COUNT` – Gibt die Gesamtzahl der Datensätze 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: @@ -1357,7 +1363,9 @@ Oder um mehrere Aggregatfunktionen gleichzeitig zu erhalten: ```sql SELECT MAX(salary), MIN(salary), AVG(salary) FROM employees ``` + ### Challenge + > Verfügbare Tabellen und Spalten: > > - `sales`**:** `product_id`**,** `price_per_unit`**,**  `quantity` @@ -1376,22 +1384,23 @@ Dein Ergebnis sollte genau diese Spaltennamen haben: - `max_unit_price`  - `total_revenue` -|product_id|price_per_unit|quantity| -|:---|:---|:---| -|4|19|1| -|5|16|3| -|6|13|2| -|7|21|1| -|8|16|3| -|9|23|5| -|10|27|1| -|11|18|2| -|12|21|3| -|13|22|2| +| product_id | price_per_unit | quantity | +|:---------- |:-------------- |:-------- | +| 4 | 19 | 1 | +| 5 | 16 | 3 | +| 6 | 13 | 2 | +| 7 | 21 | 1 | +| 8 | 16 | 3 | +| 9 | 23 | 5 | +| 10 | 27 | 1 | +| 11 | 18 | 2 | +| 12 | 21 | 3 | +| 13 | 22 | 2 | ```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 ``` + ## 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. @@ -1400,41 +1409,54 @@ Wenn du Berechnungen durchführen möchtest, die einzelne Zeilen mit aggregierte Dies liefert nicht das gewünschte Ergebnis pro Zeile: ```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: ```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. Häufige Anwendungsfälle für verschachtelte Aggregationen: + 1. Jeden Wert mit dem Durchschnitt vergleichen 2. Prozentsatz der Gesamtsumme berechnen 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: + > - `items`**:** `id`**,** `price` -| id | price | -| --- | ----- | -| 4 | 19 | -| 5 | 16 | -| 6 | 13 | -| 7 | 21 | -| 8 | 16 | -| 9 | 23 | -| 10 | 27 | -| 11 | 18 | -| 12 | 21 | -| 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`. +| id | price | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- | +| 4 | 19 | +| 5 | 16 | +| 6 | 13 | +| 7 | 21 | +| 8 | 16 | +| 9 | 23 | +| 10 | 27 | +| 11 | 18 | +| 12 | 21 | +| 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`. | | 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** -|id|area|age| -|---|---|---| -|1|A|35| -|2|A|37| -|3|B|29| -|4|B|39| +| id | area | age | +| --- | ---- | --- | +| 1 | A | 35 | +| 2 | A | 37 | +| 3 | B | 29 | +| 4 | B | 39 | Wenn wir  @@ -1475,10 +1497,10 @@ SELECT area, AVG(age) as avg_age FROM workers GROUP BY area Das Ergebnis: -|Bereich|Durchschnittsalter| -|---|---| -|A|36| -|B|34| +| Bereich | Durchschnittsalter | +| ------- | ------------------ | +| A | 36 | +| B | 34 | 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 Was würde diese Abfrage zurückgeben? + ```sql SELECT COUNT(id) FROM workers GROUP BY area ``` + 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. ### Challenge + | name | type | pH | | ------------ | --------- | ---- | | 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 | | Blueberries | berry | 3.7 | | 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 `HAVING`. Es filtert Daten nach der Aggregatbedingung. + +```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 |