diff --git a/Code/Teil 1/.idea/.gitignore b/Code/part-1/.idea/.gitignore similarity index 100% rename from Code/Teil 1/.idea/.gitignore rename to Code/part-1/.idea/.gitignore diff --git a/Code/Teil 1/.idea/dataSources.xml b/Code/part-1/.idea/dataSources.xml similarity index 100% rename from Code/Teil 1/.idea/dataSources.xml rename to Code/part-1/.idea/dataSources.xml diff --git a/Code/Teil 1/docker-compose.yaml b/Code/part-1/docker-compose.yaml similarity index 100% rename from Code/Teil 1/docker-compose.yaml rename to Code/part-1/docker-compose.yaml diff --git a/Tasks/part-1/SQL-Recherche.md b/Tasks/part-1/SQL-Recherche.md new file mode 100644 index 0000000..ecf68b2 --- /dev/null +++ b/Tasks/part-1/SQL-Recherche.md @@ -0,0 +1,81 @@ +## a) UNION, INTERSECT, EXCEPT + +![[Pasted image 20250308160323.png]] + +```sql +SELECT cust_id FROM customer +UNION +SELECT cust_id FROM account; + +SELECT cust_id FROM customer +UNION ALL +SELECT cust_id FROM account; + +SELECT cust_id FROM customer +INTERSECT +SELECT cust_id FROM account; + +SELECT cust_id FROM customer +EXCEPT +SELECT cust_id FROM account; +``` + +## b)  Partial Index + +Ein _Partial Index_ ist ein Index, der nur für einen Teil der Datensätze einer Tabelle erstellt wird, die einer bestimmten Bedingung entsprechen. + +z.B. für alle aktiven accounts. + +## c) View +Eine _View_ ist eine virtuelle Tabelle, die im Grunde die SQL Abfrage zusammenfasst. + +Man kann sie sich wie eine Python-Funktion vorstellen, die das Ergebnis einer Abfrage zurückgibt. + +```sql +CREATE VIEW customer_accounts AS +SELECT c.cust_id, p.fname, p.lname, a.account_id, a.avail_balance +FROM customer c +JOIN person p ON c.cust_id = p.person_id +JOIN account a ON c.cust_id = a.cust_id; +``` + +## d) Postgres Auto-Increment +### Deprecated (SERIAL) +```sql +CREATE TABLE example ( +  id SERIAL PRIMARY KEY, +  ... +); +``` + + +### Aktuell (GENERATED) +```sql +CREATE TABLE products ( +product_id INT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, product_name TEXT NOT NULL +); +``` + +## e) Trigger + +Ein _Trigger_ ist eine Datenbankfunktion, die automatisch vor oder nach bestimmten Ereignissen (z.B. INSERT, UPDATE oder DELETE) auf einer Tabelle ausgeführt wird. +WICHTIG: Kann bei schlechter Dokumentation sehr schnell, zu unerwünschten Seiteneffekten führen. + + +In der Bank-Datenbank könnte ein Trigger verwendet werden, um das Feld last_activity_date einer Kontotabelle zu aktualisieren, wenn eine neue Transaktion erfolgt: +```sql +CREATE FUNCTION update_last_activity() RETURNS trigger AS $$ +BEGIN + UPDATE account + SET last_activity_date = NEW.txn_date + WHERE account_id = NEW.account_id; + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +CREATE TRIGGER trg_update_last_activity +AFTER INSERT ON transaction +FOR EACH ROW +EXECUTE FUNCTION update_last_activity(); +``` + diff --git a/Tasks/part-1/SQL-Recherche.pdf b/Tasks/part-1/SQL-Recherche.pdf new file mode 100644 index 0000000..1e391e2 Binary files /dev/null and b/Tasks/part-1/SQL-Recherche.pdf differ diff --git a/Tasks/part-1/SQL_Queries.sql b/Tasks/part-1/SQL_Queries.sql new file mode 100644 index 0000000..bb2a777 --- /dev/null +++ b/Tasks/part-1/SQL_Queries.sql @@ -0,0 +1,133 @@ +-- Erstellen Sie SQL-Abfragen für die folgenden Aufgaben (Queries geben einen Punkt, sofern nicht anders angegeben): + +-- 1) Selektieren Sie die Employee ID, Vornamen und Nachname aller Angestellten - sortieren Sie absteigend nach Nachname und dann nach Vorname. +SELECT emp_id, fname, lname +FROM employee +ORDER BY lname DESC, fname DESC; + +-- 2) Holen Sie Kontonummer, Kundennummer und Kontostand für alle aktiven Konten mit mehr als 2500 Dollar (nutzen Sie als Kontostand avail_balance). +SELECT + account_id, + cust_id, + avail_balance +FROM account +WHERE + status = 'ACTIVE' + AND avail_balance > 2500; + +-- 3) Holen Sie aus der Tabelle account alle IDs der Angestellten, die ein Konto eröffnet haben - geben Sie dabei jede ID nur einmal aus (Tipp: DISTINCT). +SELECT a.open_emp_id AS emp_id FROM account a GROUP BY a.open_emp_id; + +-- 4) Zählen Sie die Zeilen in der account-Tabelle. +SELECT COUNT(a.account_id) AS Anzahl_Zeilen FROM account a; + +-- 5) Geben Sie eine Tabelle aus, in der, in der ersten Spalte der Name des Kunden und in einer zweiten Spalte die Anzahl Konten dieses Kunden steht - Hinweis: hier reicht es aus, die Namen der Individualkunden zu verwenden (individual), Geschäftskunden dürfen ignoriert werden. +CREATE OR REPLACE VIEW AUFGABE_5 AS -- Der View ist hier nur für Aufgabe 6 + +SELECT CONCAT(i.lname, ' ', i.fname) AS Kunden_Name, COUNT(a.account_id) AS Anzahl_Konten +FROM account a + JOIN individual i ON i.cust_id = a.cust_id +GROUP BY + i.cust_id; + +-- 6) Wie 5), aber zeigen Sie nur Kunden an, die 2 oder mehr Konten haben. + +-- Kleiner Trick ^-^, Aufgabe 5 als View verwenden: +SELECT * FROM AUFGABE_5 WHERE Anzahl_Konten >= 2; + +-- Alternative Lösung: +SELECT CONCAT(i.lname, ' ', i.fname) AS Kunden_Name, COUNT(a.account_id) AS Anzahl_Konten +FROM account a + JOIN individual i ON i.cust_id = a.cust_id +GROUP BY + i.cust_id +HAVING + COUNT(a.account_id) >= 2; + +-- 7) Geben Sie eine Query an, die alle Accounts findet, die im Jahr 2002 eröffnet wurden, ohne die Symbole > oder < zu verwenden. +SELECT * +FROM account a +WHERE + a.open_date BETWEEN TIMESTAMP '2002-01-01' AND TIMESTAMP '2003-01-01'; + +-- 8) Geben Sie eine Query an, die alle Kunden ("individual") findet, deren Nachname an der zweiten Stelle ein 'a' danach an beliebiger Stelle ein 'e' enthält. +SELECT * FROM individual i WHERE REGEXP_LIKE(i.lname, '^.a.*e'); + +-- 9) Schreiben Sie eine Query, die alle Account-IDs für jeden Nicht-Geschäftskunden holt, +-- dazu die fed_id des Kunden und den Namen des Produkts, auf dem der Account basiert. +SELECT a.account_id, c.fed_id, p.name +FROM + customer c + JOIN account a ON c.cust_id = a.cust_id + JOIN product p ON a.product_cd = p.product_cd +WHERE + c.cust_type_cd != 'B'; + +-- 10) Schreiben Sie eine Query, die alle Angestellten findet, +-- deren Supervisor in einer anderen Abteilung (department) arbeitet. +-- Selektieren Sie ID, Vor- und Nachname. +SELECT e.emp_id AS ID, e.fname AS Vorname, e.lname AS Nachname +FROM employee e + JOIN employee e2 ON e.superior_emp_id = e2.emp_id +WHERE + e.dept_id != e2.dept_id; + +-- 11) (2 Punkte) Selektieren Sie alle Vornamen und Nachnamen in einer Tabelle +-- (sowohl die der Individual-Kunden als auch die der Angestellten). +-- Tipp: Machen Sie sich mit der UNION-Anweisung vertraut. +SELECT fname, lname +FROM individual +UNION +SELECT fname, lname +FROM employee; + +-- 12) (2 Punkte) Selektieren Sie folgende Tabelle: Vorgesetzter (Name), komma-getrennte Liste der Mitarbeiter, +-- die zu einem Vorgesetzten gehören. +SELECT + sup.lname AS Vorgesetzter, + STRING_AGG ( + CONCAT(emp.fname, ' ', emp.lname), + ', ' + ) AS Mitarbeiter +FROM employee emp + JOIN employee sup ON emp.superior_emp_id = sup.emp_id +GROUP BY + sup.emp_id; + +-- 13) (2 Punkte) Selektieren Sie alle Account-IDs und die dazugehörige Customer-ID. +-- Wenn es ein Geschäftskunde ist, dann soll noch der Firmenname in der dritten Spalte stehen, +-- sonst soll in der dritten Spalte der Vor- und Nachname des Privatkunden stehen (Tipp: COALESCE). +SELECT c.cust_id, + STRING_AGG(a.account_id::text, ', ') AS Accounts, + COALESCE(b.name, CONCAT(i.fname, ' ', i.lname)) AS Kundenname +FROM account a +JOIN customer c ON a.cust_id = c.cust_id +LEFT JOIN business b ON c.cust_id = b.cust_id +LEFT JOIN individual i ON c.cust_id = i.cust_id +GROUP BY c.cust_id, b.name, CONCAT(i.fname, ' ', i.lname); + +-- 14) (2 Punkte) Selektieren Sie den Namen des Kunden mit dem höchsten Gesamtvermögen (nur eine Gesamt-Query - Subqueries dürfen genutzt werden) +SELECT SUM(a.avail_balance) AS "Gesamtvermögen", COALESCE( + b.name, CONCAT(i.fname, ' ', i.lname) + ) AS Kundenname +FROM + customer c + JOIN account a ON c.cust_id = a.cust_id + LEFT JOIN individual i ON c.cust_id = i.cust_id + LEFT JOIN business b ON c.cust_id = b.cust_id +GROUP BY + c.cust_id, + b.name, + i.fname, + i.lname +ORDER BY SUM(a.avail_balance) DESC +LIMIT 1; + +-- 15) (2 Punkte) Selektieren Sie alle Namen der Bank-Produkte (Tabelle product, Verbindung product_cd) +-- mit den Accounts (account_id), die auf diesem Produkt basieren. +-- Dabei sollen alle Produkte auftauchen, auch die ohne Account. +SELECT p.name AS Produktname, + STRING_AGG(a.account_id::text, ', ') AS Accounts +FROM product p +LEFT JOIN account a ON p.product_cd = a.product_cd +GROUP BY p.product_cd; diff --git a/Tasks/part-1/er_diagram_oliver_schuetz.drawio b/Tasks/part-1/er_diagram_oliver_schuetz.drawio new file mode 100644 index 0000000..194ce24 --- /dev/null +++ b/Tasks/part-1/er_diagram_oliver_schuetz.drawio @@ -0,0 +1,345 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +