1
0
Fork 0
mirror of https://github.com/TheTaz25/denis.ergin.git synced 2025-07-06 13:18:49 +00:00

feat(slides): add slides for using databases

This commit is contained in:
Denis Ergin 2025-03-14 16:19:51 +01:00
parent 9845b3dad0
commit 750bb56827
7 changed files with 381 additions and 0 deletions

View file

@ -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';
---
<div class="slides">
<Title />
<Intro />
<Setup />
<Sql />
<Usage />
</div>

View file

@ -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>

View file

@ -0,0 +1,61 @@
<section>
<section>
<h2>SQLite &amp; 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>

View file

@ -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>

View file

@ -0,0 +1,3 @@
<section>
<h1>Kurzeinstieg in Datenbanken</h1>
</section>

View file

@ -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.
-->

View file

@ -0,0 +1,8 @@
---
import Reveal from "../../../layouts/Reveal.astro";
import Slides from "../../../components/slides/databases/index.astro";
---
<Reveal title="Datenbanken einbinden">
<Slides />
</Reveal>