diff --git a/src/components/slides/databases/index.astro b/src/components/slides/databases/index.astro new file mode 100644 index 0000000..b89f8b2 --- /dev/null +++ b/src/components/slides/databases/index.astro @@ -0,0 +1,15 @@ +--- +import Title from './title.astro'; +import Intro from './intro.astro'; +import Setup from './setup.astro'; +import Sql from './sql.astro'; +import Usage from './usage.astro'; +--- + +
+ + <Intro /> + <Setup /> + <Sql /> + <Usage /> +</div> \ No newline at end of file diff --git a/src/components/slides/databases/intro.astro b/src/components/slides/databases/intro.astro new file mode 100644 index 0000000..5f0b981 --- /dev/null +++ b/src/components/slides/databases/intro.astro @@ -0,0 +1,69 @@ +<section> + <section> + <h2>Einführung</h2> + </section> + + <section> + <p>Wenn wir (Nutzer)-Daten speichern wollen, legen wir in großen Projekten keine Dateien im Datei-System ab. Gründe hierfür sind:</p> + <ul> + <li>Ineffizienz</li> + <li>Sicherheit</li> + <li>"Instabilität"</li> + </ul> + </section> + + <section> + <p>Hierfür gibt es Datenbanken. Sie sorgen dafür das die Daten optimiert und <em>sicherer</em> gespeichert werden.</p> + <p>Je nach Anwendungsfall gibt es auch weiter optimierte Datenbanken, die in einer Niche besonders gut sind.</p> + </section> + + <section> + <h3>Relationale Datenbanken</h3> + </section> + + <section> + <p>In einer Relationelen Datenbank werden Daten strukturiert abgelegt. Hierfür muss die "Form" der zu speichernden Daten vordefiniert sein.</p> + <p>Daten in Relationelen Datenbanken werden in Tabellen gespeichert. Tabellen können miteinander Verknüpft werden (sie haben eine relation zueinander).</p> + </section> + + <section> + <h3>Nicht-Relationale Datenbanken</h3> + </section> + + <section> + <p>Auch genannt "NoSQL"-Datenbanken, verfolgt den genau Gegenteiligen Ansatz einer relationelen Datenbank. Daten werden in einer strukturierten Art und Weise (z.B. JSON) abgelegt.</p> + <p>Das Ziel der abgelegten Daten ist hier aber dabei nicht relationel aufgebaut, alle notwendigen Informationen sollten eher in einem "Dokument" gespeichert sein.</p> + </section> + + <section> + <h3>In-Memory Datenbanken</h3> + </section> + + <section> + <p>Diese Art von Datenbanken sind spezieller Natur. Daten werden primär im Arbeitsspeicher abgelegt.</p> + <p>Die abgelegten Daten sind normalerweise in einer einfachen Datenstruktur (z.B. Strings) gespeichert.</p> + </section> + + <section> + <h3>Weitere (speziellere) Datenbanken</h3> + </section> + + <section> + <ol> + <li>Time-Series-Datenbanken</li> + <li>Graphdatenbanken</li> + <li>Objektdatenbanken</li> + <li>Geodatenbanken</li> + </ol> + </section> + + <section> + <h3>SQLite</h3> + </section> + + <section> + <p>In unserem kurzen Kurs versuchen wir es einfach und standardisiert zu halten.</p> + <p>Hierzu verwenden wir das vereinfachte Datenbank-System "SQLite".</p> + <p>SQLite ist eine relatione Datenbank. Die Inhalte werden dabei innerhalb einer Datenbank-Datei lokal gespeichert, eine eigene Datenbank-Applikation ist hierbei nicht notwendig, alle Transaktionen werden durch eine eigene Bibliothek gemanaged.</p> + </section> +</section> \ No newline at end of file diff --git a/src/components/slides/databases/setup.astro b/src/components/slides/databases/setup.astro new file mode 100644 index 0000000..6b564fc --- /dev/null +++ b/src/components/slides/databases/setup.astro @@ -0,0 +1,61 @@ +<section> + <section> + <h2>SQLite & NodeJS</h2> + </section> + + <section> + <p><strong>Vorab anzumerken: Um die Nachfolgenden Code-Snippets auszuführen, ist NodeJS in der Mindestversion 22.5.0 notwendig.</strong> Seit dieser Version wurde die <em>libsql</em> in die JavaScript Engine miteingebaut.</p> + <p>Hiermit ist es möglich eine SQLite Datenbank zu bedienen, ohne auf externe Pakete zurückgreifen zu müssen.</p> + </section> + + <section> + <h3>Setup</h3> + </section> + + <section> + <p>Wir bleiben weiterhin mit fastify unterwegs. Hier verwenden wir das Plugin-System um die Datenbank im Web-Server zu nutzen.</p> + <p>Beginnen wir nun auch damit. Im existierenden Projekt legen wir eine db.ts im Plugin-Ordner an.</p> + </section> + + <section> + <p>Initialer Aufbau:</p> + <pre class="ts"><code data-trim data-line-numbers="1-3|5-7|9-13" is:raw> + import fp from 'fastify-plugin'; + import { DatabaseSync } from 'node:sqlite'; + import path from 'node:path'; + + export default fp(async (fastify, opts) => { + // ToDo + }) + + declare module 'fastify' { + export interface FastifyInstance { + db: DatabaseSync, + } + } + </code></pre> + </section> + + <section> + <p>Plugin-Implementierung</p> + <pre class="ts"><code data-trim data-line-numbers="2-3|6-10|12" is:raw> + export default fp(async (fastify, opts) => { + const p = path.join(process.cwd(), 'db', 'store.db'); + const db = new DatabaseSync(p); + + db.exec(` + CREATE TABLE IF NOT EXISTS test( + key INTEGER PRIMARY KEY, + value TEXT + ) STRICT + `); + + fastify.decorate('db', db); + }); + </code></pre> + </section> + + <section> + <p>Mit diesen Zeilen haben wir nun in allen Fastify-Umgebungen auf die Datenbank-Konstante zugreifen.</p> + </section> +</section> \ No newline at end of file diff --git a/src/components/slides/databases/sql.astro b/src/components/slides/databases/sql.astro new file mode 100644 index 0000000..18a089e --- /dev/null +++ b/src/components/slides/databases/sql.astro @@ -0,0 +1,148 @@ +<section> + <section> + <h2>Schnell-Kurs zu SQL</h2> + </section> + + <section> + <p>Um im weiteren mit der Datenbank zu arbeiten, müssen wir kurz auf ein paar Basics mit SQL (Structured Query Language) eingehen.</p> + <p>Da wir hier mit SQLite arbeiten, müssen wir uns nicht um User-Management und Rechte kümmern, das haben wir hier nicht.</p> + </section> + + <section> + <h3>Tabellen erstellen</h3> + </section> + + <section> + <p>Um mit Tabellen und deren Daten zu arbeiten, müssen wir zuerst eine oder mehrere Tabellen anlegen, in der wir die Daten speichern wollen.</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + CREATE TABLE IF NOT EXISTS tasks ( + id INTEGER PRIMARY KEY, + title TEXT NOT NULL, + completed INTEGER DEFAULT 0, + due_date TEXT + ) STRICT + </code></pre> + </section> + + <section> + <p>SQLite unterstützt nur 5 Daten-Typen:</p> + <ul> + <li>NULL</li> + <li>INTEGER</li> + <li>REAL</li> + <li>TEXT</li> + <li>BLOB</li> + </ul> + </section> + + <section> + <p> + CREATE TABLE IF NOT EXISTS tasks + <br /> + Erstelle die Tabelle <em>tasks</em>, falls diese noch nicht angelegt ist + </p> + <hr> + <p> + "id" - "INTEGER" "PRIMARY KEY" + <br /> + "name" - "Datentype" "Primärschlüssel" + </p> + </section> + + <section> + <p>In Datenbanken ist ein <em>PRIMARY KEY</em> notwendig um Einträge in der Tabelle eindeutig zu identifizieren.</p> + <p>Die Anweisung <strong>PRIMARY KEY</strong> zeigt an, dass diese Spalte eindeutig (UNIQUE) ist und das Datenbanksystem die Zahl automatisch hochzählen soll für jeden Eintrag.</p> + </section> + + <section> + <p>Die Anweisung <strong>NOT NULL</strong> zeigt der Datenbank an, dass dieses Feld (Spalte) nicht leer sein darf. Leere Werte werden in relationalen Datenbanken als <strong>NULL</strong> definiert.</p> + </section> + + <section> + <h3>Einträge speichern</h3> + </section> + + <section> + <p>Die Tabelle ist nun angelegt, wir können also jetzt Daten darin speichern:</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + INSERT INTO tasks (title) VALUES + ("Für Web-Engineering lernen"); + </code></pre> + <p>Mit diesem Eintrag speichern wie eine neue Aufgabe in die neue Tabelle. Defaults werden automatisch gesetzt und der erste Eintrag erhält die id <strong>1</strong>.</p> + </section> + + <section> + <h3>Einträge abfragen</h3> + </section> + + <section> + <p>Die wahre Stärke von relationalen Datenbanken besteht in der <em>effizienten</em> Abfrage von Daten. Fragen wir zum Anfang <strong>alle</strong> in der befindlichen Tabelle abgelegten Aufgaben ab:</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + SELECT * FROM tasks; + </code></pre> + </section> + + <section> + <p>Wenn wir nur einzelne <em>Spalten</em> abfragen wollen, können wir die Spalten-Namen anstatt der <strong>Wildcard *</strong> verwenden. Die Spalten-Liste muss Komma-Separiert sein.</p> + <pre class="sql"><code data-trim data-line-numbers> + SELECT title, completed FROM tasks; + </code></pre> + </section> + + <section> + <p>Wenn wir bestimmte Einträge filtern wollen können wir dies auch erreichen:</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + SELECT * FROM tasks WHERE completed = 0; + SELECT * FROM tasks WHERE completed <> 1; + </code></pre> + </section> + + <section> + <h3>Einträge aktualisieren</h3> + </section> + + <section> + <p>Wir können unsere Aufgaben nun abhaken:</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + UPDATE tasks SET completed = 1 WHERE id = 1; + </code></pre> + </section> + + <section> + <h3>Einträge löschen</h3> + </section> + + <section> + <p>Zu guter letzt ist es auch möglich, Einträge aus einer Datenbank zu löschen</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + DELETE FROM tasks WHERE completed = 1; + </code></pre> + </section> + + <section> + <h3>Relationen (JOINs)</h3> + </section> + + <section> + <p>Eine der Stärken / Features von relationelen Datenbanken ist die Möglichkeit, Tabellen miteinander zu verknüpfen. So lassen sich komplexe Datenstrukturen stark vereinfachen. Besonders wenn es 1:n oder m:n Relationen gibt.</p> + <p>Wir können also Einträge einer Tabelle als Referenz in einer zweiten Tabelle verwenden.</p> + </section> + + <section> + <p>Legen wir zuerst eine neue Tabelle an, die Nutzer abbilden soll:</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + CREATE TABLE IF NOT EXISTS user ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL + ) STRICT + </code></pre> + </section> + + <section> + <p>Im zweiten Schritt müssen wir die existierende Tabelle um eine Spalte erweitern, die die Referenz zum Nutzer (genauer gesagt dessen id) speichern kann.</p> + <pre class="sql"><code data-trim data-line-numbers is:raw> + ALTER TABLE tasks ADD COLUMN + user_id INTEGER REFERENCES user(id); + </code></pre> + </section> +</section> \ No newline at end of file diff --git a/src/components/slides/databases/title.astro b/src/components/slides/databases/title.astro new file mode 100644 index 0000000..0620453 --- /dev/null +++ b/src/components/slides/databases/title.astro @@ -0,0 +1,3 @@ +<section> + <h1>Kurzeinstieg in Datenbanken</h1> +</section> \ No newline at end of file diff --git a/src/components/slides/databases/usage.astro b/src/components/slides/databases/usage.astro new file mode 100644 index 0000000..cb77f67 --- /dev/null +++ b/src/components/slides/databases/usage.astro @@ -0,0 +1,77 @@ +<!-- Live Action! --> +<section> + <section> + <h2>Aufgabe!</h2> + </section> + + <section> + <p>Lasst uns einen kleinen Finanz-Tracker bauen:</p> + <ul> + <li>Einnahmen tracken</li> + <li>Ausnahmen tracken</li> + <li>Kategorisierung von Transaktionen (z.B. Lebensversicherung, Lebensmittel, etc)</li> + <li>Accounts (z.B. Bank, Kreditkarte, etc)</li> + <li>"Transaktionspartner" (an wen ging die Zahlung?)</li> + </ul> + </section> + + <section> + <p>Accounts "Managen"</p> + <pre class="sql"><code data-trim data-line-numbers> + CREATE TABLE accounts ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL UNIQUE, + type TEXT NOT NULL + ) STRICT + </code></pre> + </section> + + <section> + <p>Kategorien bereitstellen</p> + <pre class="sql"><code data-trim data-line-numbers> + CREATE TABLE categories ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL UNIQUE + ) STRICT + </code></pre> + </section> + + <section> + <p>Transaktionspartner</p> + <pre class="sql"><code data-trim data-line-numbers> + CREATE TABLE transactors ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL + ) STRICT + </code></pre> + </section> + + <section> + <p>Zu guter letzt, die Transaktionstabelle selbst:</p> + <pre class="sql"><code data-trim data-line-numbers> + CREATE TABLE transactions ( + id INTEGER PRIMARY KEY, + name TEXT NOT NULL, + date TEXT NOT NULL, + cat_id INTEGER REFERENCES categories(id), + acc_id INTEGER NOT NULL REFERENCES accounts(id), + tra_id INTEGER NOT NULL REFERENCES transactors(id), + value INTEGER + ) STRICT + </code></pre> + </section> +</section> +<!-- Here are some simple applications that can help you learn SQL while building practical projects: + +1. **To-Do List App** + - **Database Tables:** Tasks, Categories, Users + - **Features:** Add, update, and delete tasks; categorize tasks; assign deadlines; filter tasks by status. + +3. **Personal Finance Tracker** + - **Database Tables:** Transactions, Categories, Accounts, Users + - **Features:** Record income/expenses; categorize transactions; view financial summaries and reports. + +6. **Student Management System** + - **Database Tables:** Students, Courses, Grades, Instructors + - **Features:** Enroll students in courses; assign grades; generate reports of student performance. +--> diff --git a/src/pages/slides/flexi-pool/03-using-databases.astro b/src/pages/slides/flexi-pool/03-using-databases.astro new file mode 100644 index 0000000..3c28cdd --- /dev/null +++ b/src/pages/slides/flexi-pool/03-using-databases.astro @@ -0,0 +1,8 @@ +--- +import Reveal from "../../../layouts/Reveal.astro"; +import Slides from "../../../components/slides/databases/index.astro"; +--- + +<Reveal title="Datenbanken einbinden"> + <Slides /> +</Reveal> \ No newline at end of file