---
# System prepended metadata

title: Datenbanken
tags: [2.Semester]

---

# Datenbanken
## TRAINER
- [Datenbank Trainer](https://eild-nrw.github.io/overview/)
    - SQL-Trainer
    - NF-Trainer (Normalform)
    - Kreuzworträtsel (Datenbankbegriffe)
    - ER-Trainer 
    - ER-REL-Trainer
    - LOS-Trainer (ER => Logisches Schema)
    - Multiple-Choice-Test (1300 Fragen)
    - B-BAUM-Animation
    - B-Baum (Einfach)
    - RelaX (Realationale Algebra)

## Was vorbereiten 
ABSOLUTE BASICS
- Entitätstypen 
- Beziehungstypen 
- 1:1, 1:N, N:M
- Abrial Notation!
---
- Muss/ Kann beziehung 
- Natürliche! schlüssel 
- generalisierung 
- Aggregation 
- komposition
- Schwache Entitäten WICHTIG ! erklären können 
- Versionierung 
- Grundidee codsche regeln
> [!NOTE] Tipps
> 	Übung 2+3 
> 	Selbsttests in LEA 
> 	ER Trainer 
> 	Modelierungsübung

### Block 2 
Logische Schema 
- Unterschiede zum semantischen Schema 
- Keine zusammengesetzten Atrribute
- Schlüssel erforderlich !
- Fremdschlüssel
Transformation von 1:1, 1:N, N:M, Generalisierung 
Normalformen 
- Insbesondern 1NF
- Aber auch 2NF, 3NF, Boyce-Codd
- umfang siehe Probeklausur

### Block 3/4
SQL /DML
Select
- as 
- distinct
- order by 
Join 
- Inner/ (Full) outer 
- left /right 
- Natural 
Bedingungen 
- Is NULL
- LIKE 
- AND/OR/NOT

Theorie: Relationale Algebra 
- Selektion 
- Projektion 
- Umbenennung

Aggregation / Verdichtung 
- Min/MAX/AVG ...
- Group By /Having 
MengenOperationen 
- Union / Minus

Unterabfragen 
- IN / Exists /ALL 

INSERT / UPDATE / Delete 

Übung 6+7 
Selbsttest in LEA 
SQL Trainer 

### Block 5 
Zugriffspfade / Indexe 
Hash- Verfahren 
Baumverfahren 
- B-Bäume 
- B+Bäume 

Selbsttest in LEA 
b baum trainer 
literatur $\to$ Kemper eikel 
-Ausschluss 
	Historie netzwerkdb
	4 coddsche regel 
	ansi ebenen

KONZEPTE EER MODELIERUNG 
![image](https://hackmd.io/_uploads/B1CiMxBOA.png)

## Diskursbereich $\to$ Miniwelt
### Vorgehensweise: Klassische Datenbankentwicklung
1. Gegebene Miniwelt 
2. Semantisches Schema 
    1. Komplexe Objekte 
    2. struktierte Attribute
    3. mengewertige Attribute
3. Logisches Schema 
4. Normalisierung & Sichten 
5. Physisches Schema 
6. Speicherstrukturen 


### Satzanalyse
| Grammatik | Komponente | Beispiel |
| -------- | -------- | -------- |
| Eigenname     | Objekt Variable | Richard Dué |
|  Substantiv|Klasse|Spielzeug|
|Verb(tun)|Methode|kaufen|
|Verb(sein)|Klassifikation|ist ein|
|Verb(haben)|Komposition|hat ein|
|Zustandsverb|Invarianz|besssen werden|
|Modalverb|- Daten Semantik   - Precondition      - Post Condition|muss sein|
|Adjektiv|Attribut|ungeeignet|
|Transitives Verb|Methode|eingeben|
|Intransitives Verb|Ausnahmeereignis|abhängig von|

![image](https://hackmd.io/_uploads/S1LUUT7_A.png)


## Semenatisches Schema
### Enitity-Relationship-Modell (ERM)
#### Grundlage und Komponenten:
- **Entität** (Entity): Individuell identifizierbares Objekt der Realität (z. B. Angestellter Müller, Projekt 3232).
- **Beziehung** (Relationship): Verknüpfung zwischen zwei oder mehreren Entitäten (z. B. Angestellter Müller leitet Projekt 3232).
- **Attribut**: Eigenschaften von Entitäten oder Beziehungen (z.B. Eintrittsdatum des Angestellten Müller).
Entität (Entity): individuell identifizierbares Objekt der Wirklichkeit; z.B. der Angestellte Müller, das Projekt 3232.

#### Typisierung und Modellierung:
- **Entitätstyp**: Abstrakte Repräsentation von realen Objekten (z.B. Angestellter, Projekt).
![2024_07_16-17_55_48](https://hackmd.io/_uploads/H1Xf_MN_C.png)
- **Beziehungstyp**: Beschreibt Zusammenhänge zwischen Entitätstypen (z.B. Angestellter leitet Projekt).
- **Attribut**: Beschreibt Entitätstypen oder Beziehungstypen näher (z.B. Nachname, Eintrittsdatum).
![2024_07_16-17_52_59](https://hackmd.io/_uploads/B1sJOGNu0.png)

#### Besondere Sachverhalte:
- **Starker Entitätstyp**: Kann durch eigene Attribute identifiziert werden (z.B. Auftragsnummer).
- **Schwacher Entitätstyp**: Benötigt Attribute anderer Entitäten zur Identifikation (z.B. Raum benötigt Gebäude und Raumnummer).
- **Kardinalität**: Gibt an, wie viele Entitäten an einer Beziehung beteiligt sein können (z.B. 1, n).
- **Reflexive Beziehung**: Beziehung innerhalb desselben Entitätstyps (z. B. Teil wird verwendet in Teil).
- **Beziehungsattribute**: Attribute, die einer Beziehung zugeordnet werden (z. B. Projektbeteiligungsgrad).
- **Abgeleitete Attribute**: Werte, die aus anderen Attributen berechnet werden können (z.B. Alter aus Geburtsdatum).

#### Datentypen
- **Zeichenketten**: char(n), varchar(n)
- **Datum- und Zeitwerte**: date
- **Zahlen**: numeric(n,d)
- **Wahrheitswerte:** boolean
- **Komplexe Werte:** compound

#### Primäärschlüssel und Alternativ Schlüssel
![2024_07_16-17_54_51](https://hackmd.io/_uploads/SyJJ_zV_R.png)

##### Natürliche Schlüssel:
- **Definition**: Natürliche Schlüssel sind Attributkombinationen, die bereits in den realen Daten vorhanden sind und zur eindeutigen Identifikation einer Entität verwendet werden können, ohne dass zusätzliche künstliche Identifikatoren (wie sequenzielle Zahlen) eingeführt werden müssen.
- **Beispiel**: Die Kombination aus Vorname, Nachname und Geburtsdatum kann in manchen Systemen als natürlicher Schlüssel für die Identifikation von Personen dienen.
- **Vorteile**: Sie sind intuitiv verständlich und spiegeln reale Eigenschaften der Entitäten wider.
- **Nachteile**: Natürliche Schlüssel können sich ändern (z. B. Namensänderungen) und sind oft nicht universell eindeutig.

#### Beziehungen
##### 1:1-Beziehung
>Jede Entität aus der ersten kann mit höchstens einer aus der zweiten in Beziehung stehen.
![2024_07_16-17_50_10](https://hackmd.io/_uploads/rJGpUzNdC.png)

##### 1:n-Beziehung
>Jede Entität aus der ersten kann mit beliebig vielen Entitäten aus der zweiten in Beziehung stehen. Jede Entität aus der zweiten kann mit höchstens einer Entität aus der ersten in Beziehung stehen.
![2024_07_16-17_51_10](https://hackmd.io/_uploads/BJ6gDfNuA.png)

##### n:m-Beziehung
>Jede Entität aus der ersten Entitätsmenge kann mit beliebig vielen Entitäten aus der zweiten Entitätsmenge in Beziehung stehen, und umgekehrt.
![2024_07_16-17_51_43](https://hackmd.io/_uploads/SJgQDzEdC.png)

> [!NOTE] Abrial Notation
>![image](https://hackmd.io/_uploads/H1lt0ZxBdA.png)

> [!NOTE] Chen Notation
> ![image](https://hackmd.io/_uploads/rkJfflH_0.png)

### Extended Enitity-Relationship-Modell (EERM)
#### Rekursive Beziehungstypen
Bei einer Reukrusiven Beziehung handelt es sich um eine Beziehung die eine Entität mit sich selbst hat. Bei rekursiven Beziehungstypen sollten die Kardinalitäten mit fachlichen Rollenbezeichnern versehen werden. 
![2024_07_17-15_50_04](https://hackmd.io/_uploads/r10GnHSOR.png)

#### Generalisierung-Spezialisierung-Hierachien
Das Konzept der IST-Beziehung bzw. der Gerneralisierungs-/Spezialisierung dient zum Modellieren von Vererbungsbziehungen. Dadurch wird einerseits die semantische Ausdrucksstärke des Diagramms erhöt, da fachlich relevante Taxonomien ("Begriffspyramiden") abgebildet werden können dadurch redundante Attributdefinitionen vermieden und fachliche Beziehungstypen zusammengefasst werden.

![2024_07_17-15_55_33](https://hackmd.io/_uploads/H1cvaSBdR.png)
![2024_07_17-15_55_37](https://hackmd.io/_uploads/rknDpSB_0.png)

##### Eigenschaften der Generalisierung/Spezialisierung
- **"partiell" vs. "total"**: Sind nicht spezalisierte Entitäten zulässig?
- **"disjunkt" vs. "nicht-disjunkt":** Kann eine Entität mehrere Spezialisierungen annehmen?

#### Assoziationen, Aggregationen und Kompositionen
Die Teil-Ganzes-Beziehung wird in drei Kategorien unterteilt:
- **Assoziation:** Keine Teil-/Ganzes-Semantik
- **Aggregation:** Besteht zwischen starken eigenständigen Entitätstypen, bei denen eine Seite ein "übergeordnetes Ganzes" darstellt. Das "Ganze" bezeichnet man dabei als Aggreagt, die "Teile"-Entitäten werden als Komponenten bezeichnet. 
- **Kompositionen:** Spezifalfall der Aggregation, bei dem die Komponenten keine vollständige eigene Identität haben, also schwache Entitäten sind

![2024_07_17-16_01_08](https://hackmd.io/_uploads/SyZ3RBruR.png)

#### Schwache Entitätstypen
Bei einem schwachen Entiätstypen 
- haben die Entiäten keine vollständige eigenen Identität
- ergibt sich ein Teil der Identität über die verbundenen Entität
- können Entitäten nicht ohne die übergeordnete Entität exsistieren

![2024_07_17-15_37_40](https://hackmd.io/_uploads/HJmEFSBuR.png)
DB-Main kennt die doppelt-umrandeten Symbole nicht daher Auszeichnung mit Notiz:
![2024_07_17-15_38_22](https://hackmd.io/_uploads/rkkwYHH_C.png)

Schwache Entitästypen sind **Kompositionen**:
- sollten entsprechend marktiert werden mit ("cmp")
- stellen Teil-Ganzes-Beziehungen dar

##### Versionierung
Eine "N:M"-Beziehungstyp erlaubt, dass eine Entität mit beliebig vielen Entitäten der anderen Seite in Beziehung stehen kann. Im Beispiel kann ein Stundent beliebig vile Bücher ausleihen. Umgekehrt kann ein Buch von beliebig vielen Studenten ausgliehen werden.

![2024_07_17-16_08_03](https://hackmd.io/_uploads/BJxIxIBd0.png)

Was in dieser Modellierung noch nicht erfasst werden kann: Das Szenario, dass ein Student wiederholt dasselbe Buch ausleiht. Wie in der Vorlesung diskutiert, ergibt sich die Identität einer Beziehung aus den beteiligten Entitäten. Daraus folgt, dass eine bestimmte Kombination von Entitäten im rahmen eines Beziehungstyp nur einmal erfasst werden kann. Der Fall in der nächsten Abbildung ist also mit dem obigen Beziehungstypen nicht darstellbar.
![2024_07_17-16_15_09](https://hackmd.io/_uploads/rJpWz8BOC.png)

Die Lösung besteht darin, die Beziehungen um Versionierungs-Entitäten zu erweitern, die das Datum speichern. Danach hat jede "leiht"-Beziehung insgesamt drei beteiligte Entitäten und die beiden Beziehungen haben unterschiedliche Identitäten.

Die zugehörige Modellierung ist in der nächsten Abbildung dargestellt. Eine Versionierungsentität ist selbst schwach und braucht keine eigene vollständige Identität: Die Identität eines Ausleihvorgangs besteht aus Buch, Student und Datum.

![2024_07_17-16_17_42](https://hackmd.io/_uploads/H1E5MIBOR.png)
![2024_07_17-16_17_52](https://hackmd.io/_uploads/Bka9GIrOR.png)

Man bezeichnet Beziehungstypen, die solche Mehrfachbeziehungen zwischen denselben Entitäten zulassen als Versionierung bzw. Historisierung. Das erklärt sich daraus, dass sie meist dazu dienen, sich verändernde Beziehungen im Verlauf der Zeit erfassen zu können.

#### Zusammengesetzes Attribut
- **Definition**: Ein zusammengesetztes Attribut ist ein Attribut, das aus mehreren Teilattributen besteht. Diese Teilattribute bieten eine detailliertere Beschreibung und können separat verarbeitet werden.
- **Beispiel**: Eine Adresse kann als ein zusammengesetztes Attribut betrachtet werden, das aus den Teilattributen Straße, Hausnummer, Postleitzahl und Ort besteht.
- **Semantik**: Zusammengesetzte Attribute heben die Atomarität der Daten auf, indem sie mehrdimensionale Informationen in einer strukturierten Weise darstellen. Dies ermöglicht eine präzisere Modellierung von realen Objekten und deren Eigenschaften.

## Normalformen
Quelle: [Normalformen Wikipedia](https://de.wikipedia.org/wiki/Normalisierung_(Datenbank)#Normalformen)

Die Normalformen bauen aufeinander auf. Man kann nicht die Zweite anwenden ohne die erste anzuwenden.
### Erste Normalform (1NF)
1. **Atomare Wertebereiche:**
    - Jedes Attribut einer Relation muss einen atomaren (nicht weiter unterteilbaren) Wertebereich haben.
    - Zusammengesetzte, mengenwertige oder geschachtelte Wertebereiche sind nicht erlaubt.
    - **Beispiel**: Eine Adresse darf nicht als einzelnes Attribut verwendet werden, sondern sollte in PLZ, Ort, Straße, Hausnummer etc. aufgeteilt werden.
2. **Frei von Wiederholungsgruppen:**
    - Attribute mit gleichen oder gleichartigen Informationen müssen in eine separate Relation ausgelagert werden.
    - **Beispiel** einer Wiederholungsgruppe: Eine Spalte {Telefon} mit mehreren Telefonnummern oder eine Spaltengruppe {Telefon1, Telefon2, Telefon3}.

#### Praktischer Nutzen:
- Abfragen der Datenbank werden erleichtert oder überhaupt erst ermöglicht.
- **Beispiel**: In einem Feld, das einen Namensstring aus Titel, Vorname und Nachname enthält, ist es schwierig bis unmöglich, nach Nachnamen zu sortieren. Atomare Wertebereiche lösen dieses Problem.

#### Beispiel
##### Negativbeispiel
![2024_07_17-11_12_15](https://hackmd.io/_uploads/BJ4Zj-SOC.png)
- Das Feld **Album** enthält die Attributwertebereiche Interpret und Albumtitel
- Das Feld **Titelliste** enthält eine Menge von Titeln.

Dadruch hat man ohne Aufspaltung folgende Probleme bei Abfragen:
- Zur Sortierung nach Albumtitel muss das Feld **Album** in Interpret und Albumtitel aufgeteilt werden.
- Die Titel können (mit einfachen Mitteln) nur alle gleichzeitig als **Titelliste** oder gar nicht dargestellt werden.

##### Lösung
![2024_07_17-11_15_19](https://hackmd.io/_uploads/BJIhj-HdA.png)
Die Attributwertebereiche werden in atomare Attributwertebereiche aufgespalten:
- Das Feld **Album** wird in die Felder *Albumtitel* und *Interpret* gespalten.
- Das Feld **Titelliste** wird in die Felder *Track* und *Titel* gespalten sowie auf mehrere Datensätze aufgeteilt.

Da jetzt jeder Attributwertebereich atomar ist sowie die Tabelle einen eindeutigen Primärschlüssel (Verbundschlüssel aus den Spalten *CD_ID* und *Track*) besitzt, befindet sich die Relation in 1NF.

### Zweite Normalform (2NF)
1. **Abhängigkeit von Schlüsselkandiaten**
    - Kein Nichtprimärattribut (Attribut, das nicht Teil eines Schlüsselkandidaten ist) darf funktional von einer echten Teilmenge eines Schlüsselkandidaten abhängen.
    - Anders gesagt: Jedes Nichtprimärattribut muss von allen gesamten Schlüssenkandidaten vollständig abhängig sein, nicht nur von einem Teil eines Schlüsselkandidaten.
2. **Automatische Erfüllung**
    - Relationenen in der 1NF, deren Schlüsselkandidaten nur aus einem einzelnen Attribut bestehen, erfüllen automatisch die 2NF.
3. **Funktionale Abhängigkeit**
    - In einer Relation R(A, B) ist das Attribut B funktional abhängig von A, wenn zu jedem Wert von A genau ein Wert von B gehört.
    - In einer Relation R(S1, S2, B) ist das Attribut B voll funktional abhängig von den zusammengesetzten Attributen (S1, S2), nicht jedoch von einzelnen Attributen S1 oder S2.
4. **Präzisierte Definition:**
    - Eine Relation ist in der zweiten Normalform, wenn sie:
        - In der ersten Normalform (1NF) ist
        - Jedes Attribut der Relation entweder Teil eines Schlüsselkandidaten ist oder
        - von einem Schlüsselkandidaten abhängt und
        - nicht von einer echten Teilmenge eines Schlüsselkandidaten abhängt.
5. **Volle funktionale Abhöngigkeit**
    - Ein Attribut ist voll funktional abhängig von jeden Schlüsselkandidaten.
    - 2NF eleminiert alle partiellen funktionalen Abhängigkeiten, d.h. kein Nichtschlüsselattribut ist funktional abhängig von Teilen des Schlüsselkandidaten.
6. **Zerlegung in Relationen:**
    - Falls ein Schlüsselkandidaten zwei Attribute besitzt, können bei der Zerlegung in die 2NF höchstens drei Relationen entstehen.
    - Falls ein Schlüsselkandidat drei Attribute besitzt, können bei der Zerlegung in die 2NF höchstens sieben Relationen entstehen.
    - Dies entspricht  der Anzahl der Elemente der Potenzmenge (2^n) als Obergrenze, minus der leeren Menge.

#### Praktischer Nutzen
1. **Monothematische Relationen:** Die 2NF erzwingt, dass jede Relation nur einen Sachverhalt modelliert.
2. **Reduzierte Redundanz und Inkonsistenzgefahr:** Durch die 2NF wird Redundanz vermindert, was die Gefahr von Inkonsistenzen reduziert.
3. **Logisch/Sachlich Zusammengehörige Informationen:** Informationen, die logisch und sachlich zusammengehören, befinden isch in einer Relation.
4. **Verbessertes Verständis der Datenstrukturen:** Die Datenstrukturen sind leichter zu verstehen, da die Relationen klar definierte Themenbereiche abdecken.
5. **Seltenen Anwendung:** Beim Planen ienes Datenmoddels wird die 2NF oft übersprungen und ist daher im Vergleich zu 1. und 3. Normalform seltener anzutreffen.

#### Beispiel
##### Negativbeispiel: 2NF verletzt
![2024_07_17-11_46_41](https://hackmd.io/_uploads/S1RZQMSu0.png)
- Der Primärschlüssel der Relation ist aus den Feldern *CD_ID* und *Track* zusammengestzt. (Grundästzlich darf ein Primärschlüssel aus mehreren Attributen bestehen, jedoch entsteht daraus im genannten Beispiel ein Konflikt.)
- Die Felder *Albumtitel, Interpret* und *Erscheinungsjahr* sind vom Feld *CD_ID* abhänig, aber nicht vom Feld *Track*. Diesr (Punkt 2) verletzt die 2. Normalform, da die drei nicht-primären Attribute nicht nur von einem Teil des Schlüssels (hier *CD_ID*) abhängen dürfen. Wäre der Schlüssel nicht zusammengestzt, so könnte dies nicht passieren.

##### Probleme, die daraus entstehen.
Die Informationen aus diesen drei Feldern sind, wie am Beispiel der CD *Not That Kind* zu erkennen, mehrfach vorhanden d.h. redundant. Dadurch besteht die Gefahr, dass die **Integrität der Daten** verletzt. So könnte man den Albumtitel für das Lied *Not that Kind* in *I Dont´t Mind* ändern, ohne jedohch die entsprechende Einträge für die Titel *I´m Outta Love* und *Cowboys & Kisses* zu ändern.

![2024_07_17-11_52_10](https://hackmd.io/_uploads/BJD84MrdA.png)
In diesem Fall wäre ein Zusand erreicht, den man als **Dateninkonsitenz** bezeichnet. Über die komplette Tabelle btrachtet, "passen" die Daten nicht mehr zusammen.

##### Lösung
Die Daten in der Tabelle werden in zwei Tabellen aufgeteilt: *CD* und *Lied*. Die Tabelle und Cd enhtält nur noch Felder, die voll funktional von *CD_ID* abhängen, hat also *CD_ID* als Primärschlüssel. Auch der Albumtitel allein sei eindeutig, also ein Schlüsselkandidat. Da keine weiteren (zusammengesetzten) Schlüsselkandidaten existieren, liegt die Tabelle damit autimatisch in der 2. Normalform vor. Die Tabelle "Lied" enthält schließlich nur noch Felder, die voll funktional von *CD_ID* und *Track* abhängen, liegt also auch in der 2. Normalform vor. Mit Hilfe dieser verlustfreien Zerlegung sind auch die genannten Redundanzen der Daten beseitigt. 

![2024_07_17-12_31_00](https://hackmd.io/_uploads/HkZOaMH_0.png)

Das Attribut *CD_ID* aus der Tabelle *Lied* bezeichnet man als **Fremdschlüssel**, der auf den Primärschlüssel der Tabelle *CD* verweist. Zugleich stellen die Attribute *CD_ID* und *Track* den zusammengesetzten Primärschlüssel der Tabelle Lied dar.

### Dritte Normalform (3NF)
1. **Keine funktinalen Abhängigkeiten zwischen Nichtschlüsselattributen:**
    - Es dürfen keine funktionalen Abhängigkeiten der Nichtschlüsselattribute untereinander bestehen, auch bekannt als transitive Abhängigkeiten.
2. **Volle funktionale Abhängigkeit:**
    - Alle Nichtschlüsselattribute müssel voll funktional abhängig vom Schlüsselattribut sein.
3. **Transitive Abhängigkeit**
    - Ein Attribut $A_2$ ist vom Schlüsselkandidaten $P_1$ transitiv abhängig, wenn es eine Attributmenge $A_1$ gibt, sodass $(P_1 \to A_1)$ und $(A_1 \to A_2)$.
    - Einfach gesagt: Ein Nichtschlüsselattribut darf nicht von einer Menge aus Nicthschlüsselattributen abhängig sein, sondern nur direkt von einem Primärschlüssel (oder Schlüsselkandidaten).
4. **Alternative Formulierung:**
    - Eine relation ist in der 3NF, wenn:
        - Sie sich in der 2NF befindet und
        - Kein Nichtschlüsselattibut Determinatne ist.
    - Oder: Kein Nichtschlüsselattribut ist von einem anderen Nichtschlüsselattribut funktional abhängig.

#### Praktischer Nutzen
1. **Erkennbare transitive Abhängigkeiten:**
    - Transitive Abhängigkeiten sind sofort ersichtliche, ohne die Zusammenhänge der Daten zu kennen, durch die Struktur der Relationen.
2. **Behebung thematischer Durchmischungen:**
    - Verbliebene thematische Durchmischungen in der Relation werden behoben.
    - Nach der 3NF sind die Relaitonen des Schemas zuverlässig monothematisch. 

#### Beispiel
##### Negativbeispiel: 3NF verletzt
![2024_07_17-12_46_31](https://hackmd.io/_uploads/rkXfW7B_C.png)

Offentsichtlich lässt sich der *Interpret* einer CD aus der *CD_ID* bestimmen, das *Gründungsjahr* der Band/Interpreten hängt wiederum vom *Interpreten* und damit **transitiv** von der CD_ID ab. Das Problem ist hierbei wieder Datenredundanz. Wird zum Beispiel eine neue CD mit einem exisiterenden *Interpeten* eingeführt, wo wird das *Gründungsjahr* redundanz gespeichert. 

##### Lösung
![2024_07_17-12_50_20](https://hackmd.io/_uploads/S1deGQBd0.png)

Diese Lösung gilt nur, wenn man davon ausgeht, dass der Interpret weltweit eindeutig ist. Ansonsten müsste man eine synthetische ID in der Tabelle Künstler hinzufügen, die dann den Fremdschlüssel in der Tabelle CD stellt, wie folgt: 

![2024_07_17-12_51_27](https://hackmd.io/_uploads/HJsNMQHuA.png)

Die Relation wird aufgetielt, wobei die beiden voneinander abhängigen Daten in eine eigene Tabelle ausgelagert werden. Der Schlüssel der neuen Tabelle muss als Fremdschlüssel in der alten Tabelle erhalten bleiben. An der Tabelle "Lied" wurden keine Änderungen bei der Übertragung in die 3. Normalform vorgenommen. Sie sit hier nur  der Vollsätndigkeit halber gelistet.

### Boyce-Codd-Normalform (BCNF)
1. **Schlüsselkandiaten als determinanten:**
    - Jede Determinante (Attributmenge, von der andere Attribute funktional abhängen) muss ein Schlüsselkandiat sein oder die Abhängigkeit muss trivial sein.
2. **Verhinderung abhängiger Schlüsselkandidaten:**
    - BCNF verhindert, dass Teile zweier aus mehreren Feldern zusammengesetzten Schlüsselkandidaten voneinander abhängig sind.
3. **Verlustfreie Überführung**
    - Die Überführung in die BCNF ist immer verlustfrei möglich.
4. **Abhängigkeitserhalt:**
    - Die Überführung in die BCNF ist nicht immer abhängigkeitserhaltend.
5. **Verschärfung der 3NF:**
    - Urspürunglich als Vereinfachung der 3NF gedacht, führt BCNF zu einer verschäften Normalform:
        - Eine Relation ist autmatisch frei von transitiven Abhängigkeiten, wenn alle Determinanten Schlüsselkandidaten sind.

#### Beispiel
##### Negativbeispiel: BCNF verletzt
In diesem Beispiel gibt es eine einfache Datenbanken, in der die Vereinszugehörigkeit von Sportlern gespeichert wird. Es sollen die folgenden Bedingungen gelten:
- jeder Verein bietet nur eine Sportart an.
- ein Sportler kann in verschiedenen Vereinen spielen, aber nur, wenn idese Vereine unterschiedliche Sportarten anbieten. Damit wird sichergestellt, dass der Sportler nie gegen einen Verein spielt, in dem er selbst Mitglied ist.

![2024_07_17-13_00_56](https://hackmd.io/_uploads/r1NuVmS_0.png)

Aus den oben genannten Bedinungen folt, dass das Attribut Sportart funktional abhängig vom Attribut Vereint ist (Verein $\to$ Sportart), d.h. Verein ist eine Determinante. Jedoch ist Verein kein Schlüsselkandidat. Mögliche Schlüsselkandidaten sind {Name, Verein} und {Name, Sportart}. Eine Konvertierung in BCNF ist möglich, indem (Name, Verein) als Primärschlüssel verwendet und die Relation aufgetielt wird:

##### Lösung
![2024_07_17-13_03_12](https://hackmd.io/_uploads/B1AxBXS_A.png)


![image](https://hackmd.io/_uploads/HJdrBgBOR.png)

## Logisches Schema
### Abbildung eines ER auf relationales Schema
><font color="#1936C9">**1:1 Beziehung**</font>
>- Die Relation der einfachen Kardinalität erhält einen Fremdschlüssel auf den Primärschlüssel mit der bedingten Kardinalität wenn die Entitätstypen unterschiedliche Min Max Kardinalitäten haben.
>- Verfügen beide Entitätstypen über exakt identische Kardinalitäten (Min und Max) so soll der Fremdschlüssel die Hauptzugriffsrichtung unterstützen. 

![Untitled Diagram](https://hackmd.io/_uploads/S1dHj2IOC.jpg)


><font color="#1936C9">**N:M Beziehung**</font>
>- der Primärschlüssel der Beziehungsrelation erhält mehrere Fremdschlüssel (jeweils einfache Kardinalität) auf die jeweiligen Primärschlüssel der Relationen mit mehrfacher Kardinalität
>![image](https://hackmd.io/_uploads/ryeezzHuA.png)

![Untitled Diagram(4)](https://hackmd.io/_uploads/BkAflp8O0.jpg)
![Untitled Diagram(5)](https://hackmd.io/_uploads/rkvUGaIu0.jpg)

><font color="#1936C9">**1:N Beziehung**</font>
>- die Relation mit der einfachen Kardinalität erhält einen Fremdschlüssel auf den Primärschlüssel der Relation mit der mehrfachen Kardinalität
> ![image](https://hackmd.io/_uploads/Sk8_GfHdC.png)

![Untitled Diagram(1)](https://hackmd.io/_uploads/BydyTnUuR.jpg)

>**Muss/Kann Beziehung**
>![image](https://hackmd.io/_uploads/BJlqGGSu0.png)

><font color="#1936C9">**Generalisierung / Spezialisierung**</font>
>- die Relation unterhalten 1:1-Beziehungen, wobei die spezielleren Relationen einen Muss- Fremdschlüssel auf den Primärschlüssel der allgemeineren Relation erhalten
>![image](https://hackmd.io/_uploads/S1r2GMB_C.png)
>![image](https://hackmd.io/_uploads/HktsSWBuR.png)

## Speicherstrukturen
### Bäume
#### B-Bäume
[Animation B-Baum](https://www.cs.usfca.edu/~galles/visualization/BTree.html)

>[!Note]Definition
>- Jeder innere Knoten eines B-Baum enthält Suchschlüssel und zugehörige Datenwerte, sowie Verweise auf nachfolgende Knoten.
>- Ein B-Baum heißt von der Ordnung n, wenn gilt:
>- Alle Blätter besitzen gleiches Niveau. 
>- Jeder Knoten mit Ausnahme der Wurzel besitzt mindestens $\boxed{\frac n 2}$ Nachfolger und höchstens n Nachfolger. 
>- Die Wurzel besitzt mindestens 2 und höchstens n Nachfolger. 
>- Jeder Knoten mit k Nachfolgern enthält k − 1 Schlüssel. 
>- (Suchbaumeigenschaft) wie zuvor.
#### $B^+\text{ Bäume}$
[Animation B+Baum](https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html)

>[!Note]Unterschied zu B-Bäumen
> - $B^*\text{ Baum}$: innere Knoten zu $\frac 2 3$ = 66% gefüllt beim B-Baum mind. $\frac 1 2$. 
> 
> - $B^+\text{ Baum}$: Datenelemente nur in Blattknoten. Innere Knoten enthalten Suchschlüssel und Verweise auf Nachfolger. Im NTFS Dateisystem werden die Blätter des $B^+\text{ Baums}$ mit linearer Liste verbunden.

![image](https://hackmd.io/_uploads/H1inGQBu0.png)
![image](https://hackmd.io/_uploads/SyDpM7S_C.png)
## Operationen auf Bäumen 
### Einfügen
1. Einfügen in ein leeres Feld der Wurzel
2. Die ersten n Werte (d.h. Suchschlüssel mit Daten) werden sortiert als Separatoren in die Wurzel eingetragen
3. Der nächste Wert, der (n + 1)-te, passt nicht mehr in die Wurzel und erzeugt einen Überlauf (overflow). 
4. Die Wurzel wird geteilt mit der Split-Operation:
    -  Jeder der beiden Kinder bekommt $\boxed{\frac n 2}$ Werte.
    -   Die Wurzel bekommt den Median der (n + 1) Werte als Separator eingetragen. 
5. Neue Werte (= Schlüssel, Daten) werden in den Blättern sortiert gespeichert.
6. Läuft ein Blatt über, d.h. der (n + 1)-te Eintrag müsste gemacht werden, wird ein Splitt durchgeführt:
    - Das Blatt wird geteilt ⇒ 2 neue Blätter mit je $\boxed{\frac n 2}$ Einträgen.
    - Diese werden mit dem Elternknoten anstelle des ursprünglichen Blattes verbunden. 
    - Der Median der (n + 1) Werte wird als Separator in den Elternknoten eingetragen. 
7. Ist auch dieser Elternknoten voll, wird das Splitten fortgesetzt, im schlimmsten Fall bis zur Wurzel.
### Löschen
1. Sei x das zu löschende Element. Sei k die minimal nötige Knotenbelegung. 
2. Suche x . (Graphtraversierung, vgl. „Programmieren 2“, „Algorithmen, Datenstrukturen, Graphentheorie“) 
3. unterscheide 2 Fälle: 
    - x ist in einem Blatt: 
        - Verbleiben mindestens k Werte nach dem Löschen im Blatt ⇒ okay 
        - Verbleiben im Blatt k − 1 Werte (also zuwenig) und ein direktes Nachbarblatt besitzt mehr als k Werte ⇒ Rotation (also Füllungsausgleich).
        -  Sonst Blätter werden verschmolzen ⇒ Merge 
    -  x ist in einem inneren Knoten: 
        -  Ersetze x durch den nächstgrößeren oder nächstkleineren Wert (bezogen auf den Suchschlüssel) aus dem linken bzw. rechten Nachfolgeknoten. 
        -  Lösche den gerade gewählten Wert aus dem entsprechenden Knoten. ⇒ (Rekursion!)

### Beispiele
![image](https://hackmd.io/_uploads/SJoyNErOA.png)
![image](https://hackmd.io/_uploads/H14xN4BOR.png)
![image](https://hackmd.io/_uploads/Bk3xVVru0.png)
![image](https://hackmd.io/_uploads/HJKbNNrdA.png)
## Zugriffsverfahren
### Zugriffsverfahren für Primärschlüssel
![image](https://hackmd.io/_uploads/Hy6t54Bu0.png)
#### Organisation 
- die Datensätze werden nach dem Primärschlüssel aufsteigend abgespeichert
![image](https://hackmd.io/_uploads/SkMJsNSu0.png)

#### Sätze finden
- bei Anwendung des Verfahrens der binären Suche mit n Schlüsselwerten ist der Aufwand im Mittel
    - Suchaufwand: $(n)=\log_2 n$
    - ![image](https://hackmd.io/_uploads/ByXIo4B_A.png)

#### Sätze einfügen #
- recht aufwändig
- bei n Schlüsselwerten müssen durchschnittlich n/2 Sätze bewegt "aufgerückt" werden
![image](https://hackmd.io/_uploads/By7coVBdR.png)
![image](https://hackmd.io/_uploads/BJC86NBOR.png)
### Zugriffsverfahren für Bäume 
>[!Note] Definition 
> - die Knoten eines B-Baumes sind Speicherblöcke fester Länge 
> - jeder Block kann 2*k B-Baumdatensätze gleicher Länge aufnehmen (k = beliebige Zahl) 
> - jeder B-Baum Datensatz besteht aus drei Teilen: 
>   - einen Zeiger auf einen weiteren Knoten 
>   - einen Schlüssel 
>   - einen Nichtschlüsselbereich (z.B.: Zeiger auf Sekundärspeicherblock)
![image](https://hackmd.io/_uploads/Skld9THSu0.png)

![image](https://hackmd.io/_uploads/rJqwb8HOC.png)
![image](https://hackmd.io/_uploads/B1jtWUSuC.png)
![image](https://hackmd.io/_uploads/S1QqZIB_C.png)
![image](https://hackmd.io/_uploads/ByfjbUHuR.png)
![image](https://hackmd.io/_uploads/Hk1nW8rO0.png)
![image](https://hackmd.io/_uploads/HJfT-UrOA.png)

#### Verzeigerung von B-Bäumen 
**Vorgehensweise** 
- P0 zeigt auf einen Teilbaum (Block), dessen Schlüssel alle kleiner sind als S1 
- P1 zeigt auf einen Teilbaum (Block), dessen Schlüssel alle zwischen S1 und Sn liegen 
- Pn zeigt auf einen Teilbaum (Block), dessen Schlüssel alle größer als Sn-1 sind 
- in den Blattknoten sind die Zeiger nicht definiert 
- nicht alle Zeiger müssen benutzt werden 
![image](https://hackmd.io/_uploads/HJ7wRSH_C.png)

**Unterschied zur Index-Sequentiellen Organisation** 
- keine Unterscheidung zwischen Index- und Datenblöcken 
- B-Baum ist ausgeglichen („balanciert“) 
![image](https://hackmd.io/_uploads/Hk5vCHHOC.png)

### Zugriffsverfahren für Indexe
>[!Note]Definition INDEX
>- Ein Index ist eine Ansammlung von Datensätzen eines neuen Typs, die ausschließlich für die internen Zwecke der Datenverwaltung verwendet werden.
>- Der Index wird in einem oder mehreren Blöcken verwaltet. 

#### Struktur des Index 
- jeder Satz des Index ist vom Typ s,b
    - s $\to$ Primärschlüssel 
    - b $\to$ Blockidentifikator
- jeder Indexblock enthält eine Vielzahl von (s,b)-Indexeinträgen 
    - Blockgröße z.B 8KB
    - s: z.B 2 Bytes, b: z.B 8 Bytes
    - Block enthält ca. 800 Index-Einträge 
#### Eigenschaften von Indexen
##### Dichte
- Indexe sind in der Regel nicht dicht, d.h. sie enthalten nicht alle Schlüsselwerte des Primärschlüssels 
- Mögliche Indexeinträge sind: • ($s_{max},b$) oder ($s_{min},b$) 
- mit $s_{max}$ = größter Schlüsselwert in Block b oder 
- mit $s_{min}$ = kleinster Schlüsselwert in Block b
- ![image](https://hackmd.io/_uploads/HJm-GBBuC.png)

##### Mehrstufigkeit
- Indexe können kaskadiert werden 
    - … d.h. bei großen Indexen, die über mehrere Blöcke gehen, wird ein Index für den Index aufgebaut
    - diese Technik ist beliebig wiederholbar
![image](https://hackmd.io/_uploads/SkA-zHr_A.png)

#### Vorgehen der Suche mit Indexen 
1. Suche im Index einen Eintrag für den gilt s <=$_{min}$ s$_{max}$
    - <=$_{min}$ es existiert kein weiteres 
    - s$_{max}$ das größer s ist und noch näher zu s liegt oder aber gleich s ist. 
2. Lies den Block, dessen Anfangsadresse durch b gegeben ist
3. Suche (sequentiell oder binär) in diesem Block nach dem Datensatz mit dem Schlüsselwert s. 

    ![image](https://hackmd.io/_uploads/ByF1mSr_A.png)
    ![image](https://hackmd.io/_uploads/SyUdXHHd0.png)
#### Probleme beim Einfügen von Datensätzen 
##### Speicherreserve
- Bei vollständig gefüllten Blöcken der Datensatzdatei führt bereits das Einfügen eines neuen Datensatzes zu umfangreichen Datenverschiebungen
- Daher lässt man auf den Blöcken häufig eine Speicherreserve (also z.B.: nur zu 60% gefüllte Blöcke)
- Ist die Speicherreserve erschöpft, müssen Überlaufblöcke angelegt werden
##### Überlaufblöcke 
- Sind eine Art künstlerische Verlängerung eines Blockes 
- werden durch "Verzeigerung" mit den zu verlängernden Blöcken verbunden
##### Organisation 
- entweder pro übergelaufenem Block eine eigene Verkettung von Überlaufblöcken
- oder eine Überlaufbereich, in dem sog. Überlaufsätze sequentiell abgelegt werden(hier werden dann einzelne Sätze verkettet)
![image](https://hackmd.io/_uploads/ryThNrrO0.png)

### Zugriffsverfahren für Hash
>[!Note] Definition Hash-Verfahren 
>- mit Hilfe einer Funktion, deren Eingabewerte die Primärschlüsselwerte sind, wird eine Speicheradresse errechnet, auf der der betreffende Datensatz dann abgelegt wird 
>- das Verfahren verstreut die Datensätze im zur Verfügung stehenden Speicherbereich (daher auch Streuspeicherverfahren genannt) 
>- Speicheradressen können beispielsweise Blocknummern sein

- Mehreren Sätzen können gleiche Adressen zugewiesen werden(gewollt)
- dies führt allerdings zu Kollisionen
#### Beispiel Division mit Rest Verfahren
![image](https://hackmd.io/_uploads/BJeRwHHuR.png)
#### Kollisionsauflösung bei Hash-Verfahren 
**Methoden**
- Kollisionsbehandlung mit Überlaufbereich 
    - Reservierung bestimmter Blöcke für den Überlauf (siehe Skizze)
    - Möglichkeiten der Kollisionsbehandlung ohne Überlaufbereich 
        - Nutzung des ersten freien Speicherplatzes im Hash-Bereich nach dem durch die Hash- Funktion h bestimmten Platz h(s) 
        - Abspeicherung im ersten freien Speicherplatz nach einer Folge von Speicherplätzen, deren Adressen über Zufallszahlen berechnet werden (Schlüssel = Eingabe für Zufallszahlengenerator) 
        - Einführung einer zweiten Hash-Funktion für die kollidierten Datensätze
        ![image](https://hackmd.io/_uploads/rJg9OBrdR.png)
#### Sortiert-Logisch-Sequentielle Organisation
**Listen**
- Verkettung der Datensätze durch Zeiger 
- Blöcke sind nicht physisch benachbart 

**Vorteil**
- Vollständige Ordnung der Datensätze 
- Ordnung nach dem Sortierkriterium des Schlüssels möglich 
- unabhängig von der physischen Speicherung ergibt sich immer eine logische Ordnung

**Nachteil** 
- bei m Datensätzen sind zum Suchen 
    - durchschnittlich m/2 Datensätze zu lesen, da Ordnung nur logisch 
    - die sich auf (m/2/Anzahl Datensätze pro Block) Blockzugriffe verteilen 
- Löschen und Einfügen können eine Liste sehr ungünstig über den gesamten Speicherbereich verteilen, so dass es zu einer erheblichen Verlangsamung von Schreibzugriffen kommen kann 
![image](https://hackmd.io/_uploads/BkrDKBHu0.png)


## Datenbankmodelle?

## Relationale Algebra
### Grundoperationen 
- Zeilen heraussuchen (Selektion)
- Spalten ausblenden (Projektion)
- Vereinigung von Relationen (Union)
- Differenz von Relationen 
- Produkt von Relationen
#### Hilfsoperationen 
- Umbenennen von Spalten 

## Definition der Grundoperationen 
### Umbennenung **$\beta$** Beta

**Anwendung:**
- Bilden synonymer Attribute
- er Umbennenungsoperator $\beta$ bewirkt, dass ein Attribut “alt” der Relation R in der Ergebnisrelation R2 in Attribut “neu” umbenannt wird

**Beispiel:**
$$R2 = \beta [ Attribut\space neu \leftarrow Attribut\space  alt ] R1$$
$$Haeuser = \beta[Haus \leftarrow Gebaeude]Gebaeude$$

![image](https://hackmd.io/_uploads/B1G3VkVOA.png)

### Selektion $\sigma$ Sigma
**Anwendung:**
- Beschränkung der Tabelle auf wesentliche Informationsträger 
- Selektieren von Zeilen 
- der Selektionsoperator $\sigma$ selektiert aus der Relation R1 alle diejenigen Tupel, die einer bestimmten Bedingung $\theta$ genügen und fasst diese zur Ergebnisrelation R2 zusammen 
- Mehrere Bedingungen werden mittels logischen Operatoren zu einem Bedingungsausdruck verbunden

**Beispiel:** 
$$R2 = \sigma [ Bedingung ] R1$$
$$Einige Orte = \sigma [Gebaeude = 'B' ]\space Veranstaltungsort$$
![image](https://hackmd.io/_uploads/SyHZU1VOA.png)
### Projektion $\pi$
**Anwendung:**
- Ausblendung uninteressanter oder datengeschützter Attributwerte
- der Projektionsoperator $\pi$ selektiert bestimmte Attribute einer Relation R1 und fasst diese zur Ergebnisrelation R2 zusammen

**Beispiel:**
$$R2 = \pi [ Attributliste ] R1$$
$$Veranstaltungsgebaeude = \pi [\text{LV-Nr, Gebaeude}] Veranstaltungsort$$ 
![image](https://hackmd.io/_uploads/BJ3u_JE_C.png)
### Differenz 
**Anwendung:**
- Ausschluss von bestimmten Informationsträgern aus einer Menge

**Beispiel:**
$$R3 = R1 - R2$$
$$\text{Andere_Orte = Veranstaltungsort} - \text{Einige_Orte}$$
![image](https://hackmd.io/_uploads/SJoaYkVOA.png)

### Kartesisches Produkt 
**Anwendung:**
- generelle Paarbildung, jeder mit jedem
- die Ergebnisrelation R3 einer Produkt-Operation $\times$ zwischen den Relationen R1 und R2 entspricht der Verknüpfung jeder Zeile von R1 mit jeder Zeile von R2
- Umbennung $\beta$ erforderlich bei Namensgleichheit

**Beispiel:**
$$R3 = R1 \times R2$$
$$Spielpaarung = \text{Einige_Studenten} \times \text{Gegner_Studenten}$$
![image](https://hackmd.io/_uploads/SJ9SoyEdR.png)

## Definition Zusammengesetzte Operationen 
### Datenanfrage
### Verbund von Relationen 
#### Equi-Join $\Join$
**Anwendung:**
- bedingte Gegenüberstellungen von Daten
- im Gegensatz zum kartesischen Produkt $\times$ werden beim allgemeinen Join nur solche Zeilen der Relation R1 mit solchen Zeilen der Relation R2 verknüpft, die der Bedingung eines Vergleichoperators $\theta$ (Theta) genügen
**Beispiel:**
$$R3 = R1 \Join(\theta )\space R2 = R1\Join( Bedingung ) R2$$
$$Vorteilpaarung = \text{Einige_Studenten} ⋈[ Matr-Nr > \text{Gegner-Nr} ] \text{ Gegner_Studenten}$$
![image](https://hackmd.io/_uploads/H1T8klEO0.png)

#### Natural Join $\otimes$
**Anwendung:**
- Paarbildung und Verschmelzung von Informationen auf der Basis der Gleichheit bestimmter Merkmale (Denormalisierung)
- beim natürlichen Verbund  werden zwei Relationen R1 und R2 mit jeweils synonymen Attributen A1 und A2 vorausgesetzt
- außerdem wird eine der beiden synonymen Spalten von A1 oder A2 ausgeblendet

**Beispiel:**
$$R3 = R1 \otimes R2$$
$$Veranstaltungsadressen = Veranstaltungsort \otimes Gebaeude$$
$$Veranstaltungsadressen = Veranstaltungsort \otimes _{(Gebaeude)} Gebaeude$$
![image](https://hackmd.io/_uploads/BytNelN_C.png)
LOL
#### Division $\div$
**Anwendung:**
- Ermittlung von Informationsträgern, die alle Eigenschaften einer Menge von Bedingungen erfüllen
- die Division  setzt zwei Relationen R1 und R2 voraus, wobei das Attributschema von R2 eine echte Teilmenge von R1 ist.
- die Ergebnisrelation R3 erhält nur solche Tupel aus R1 zugewiesen, die alle Eigenschaften der Tupel von R2 erfüllen
- das Schema von R3 enthält nur solche Attribute, die nicht in R2 enthalten sind

**Beispiel:** 
$$R3 = R1 \div R2$$
$$\text{Ausgewaehlte_Studenten} = Belegungsplan \div \text{Ausgewaehlte_LV}$$
![image](https://hackmd.io/_uploads/Bk4b-xEuC.png)

## SQL
Quelle: [SQL-W3Schools](https://www.w3schools.com/sql/default.asp)

## SQL-DDL
### CREATE TABLE
Mit Create Table kann man in einer Datenbank eine neue Tabelle erstellen.

#### Syntax
```
CREATE TABLE table_name (
    column1 datatype,
    column2 datatype,
    column3 datatype,
   ....
); 
```

#### Beispiel
```
CREATE TABLE Persons (
    PersonID int,
    LastName varchar(255),
    FirstName varchar(255),
    Address varchar(255),
    City varchar(255)
);
```

### DROP TABLE
Mit **DROP** können existierende Tabellen in einer Datenbank gelöscht werden.

CASCADE CONSTRAINTS löscht kaskadierend alle Constraints der zu löschenden Tabelle. 

#### Syntax
```
DROP TABLE table_name;
```
```
DROP TABLE table_name CASCADE CONSTRAINTS;
```
#### Beispiel
```
DROP TABLE Shippers; 
```
```
DROP TABLE Shippers CASCADE CONSTRAINTS;
```
### ALTER TABLE
Mit **ALTER** können Spalten zu einer Tabelle hinzugefügt, gelöscht oder verändert werden, außerdem kann man damit auch **constraints** hinzufügen oder löschen.

#### ADD COLUMN
##### Syntax
```
ALTER TABLE table_name
ADD column_name datatype; 
```

##### Beispiel
```
ALTER TABLE Customers
ADD Email varchar(255);
```

#### DROP COLUMN
##### Syntax
```
ALTER TABLE table_name
DROP COLUMN column_name; 
```
##### Beispiel
```
ALTER TABLE Customers
DROP COLUMN Email; 
```

#### RENAME COLUMN
##### Syntax
```
ALTER TABLE table_name
RENAME COLUMN old_name to new_name; 
```

#### ALTER/MODIFY DATATYPE
##### Syntax
```
ALTER TABLE table_name
MODIFY COLUMN column_name datatype; 
```

### CONSTRAINTS
Contrains können spezifiziert werden beim erstellen oder verändern der Tabelle. 

Übliche Constraints in SQL sind:
- **NOT NULL:** Spalte darf keine NULL Werte enthalten
- **UNIQUE:** Spalten dürfen nur einzigartige Werte enthalten
- **PRIMARY KEY:** Eine Kombination aus **NOT NULL** und **UNIQUE**. Dadurch kann jede Zeile eindeutig identifiziert werden.
- **FOREIGN KEY:** Verhindert Aktionen die die Beziehung zwischen zwei Tabellen zerstört
- **CHECK:** Versichert das alle Spaleten eine Bedinung erfüllen

#### NOT NULL (CHECK)
##### Syntax
```
ALTER TABLE table_name
    ADD CONSTRAINT constraint_name
    CHECK (column_name IS NOT NULL);
```
##### Beispiel
```
ALTER TABLE prp_tab_architecture
    ADD CONSTRAINT prp_nn_architecture_name
    CHECK (name IS NOT NULL);
```

#### UNIQUE
##### Syntax
```
ALTER TABLE table_name
    ADD CONSTRAINT constraint_name
    UNIQUE (column_name);
```

##### Beispiel
```
ALTER TABLE prp_tab_package
    ADD CONSTRAINT prp_uk_package_hash
    UNIQUE (hash);
```

#### PRIMARY KEY
##### Syntax
```
ALTER TABLE table_name
    ADD CONSTRAINT constraint_name
    PRIMARY KEY(column_name);  
```

##### Beispiel
```
ALTER TABLE prp_tab_mediatype
    ADD CONSTRAINT prp_pk_mediatype
    PRIMARY KEY(mediatype_id);  
```

#### FOREIGN KEY
##### Syntax
```
ALTER TABLE table_name_01
    ADD CONSTRAINT constraint_name
    FOREIGN KEY (column_name)
    REFERENCES table_name_02;
```

##### Beispiel
```
ALTER TABLE prp_tab_package
    ADD CONSTRAINT prp_fk_package_license
    FOREIGN KEY (fk_license_id)
    REFERENCES prp_tab_license;  
```

#### FOREIGN KEY
##### Syntax
```
ALTER TABLE table_name_01
    ADD CONSTRAINT constraint_name
    FOREIGN KEY (column_name)
    REFERENCES table_name_02;
```

##### Beispiel
```
ALTER TABLE prp_tab_package
    ADD CONSTRAINT prp_fk_package_license
    FOREIGN KEY (fk_license_id)
    REFERENCES prp_tab_license;  
```

### VIEWS
Eine **VIEW** ist eine virtuelle Tabelle basierend auf dem Ergebnis eines SQL-Staements. 

#### Syntax
```
CREATE OR REPLACE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition; 
```

#### Beispiel
```
CREATE OR REPLACE VIEW [Brazil Customers] AS
SELECT CustomerName, ContactName, City
FROM Customers
WHERE Country = 'Brazil'; 
```

## SQL-DML

1. SELECT
2. DISTINCT
3. WHERE
4. ODER BY

### SQL SELECT
Mit dem **SELECT** Statement kann man Daten auswählen.

#### Syntax
```
SELECT column1, column2, ...
FROM table_name;
```

Columns sind Feldernamen einer Tabelle die man haben möchte.
Die Tabelle gibt an von welcher Tabelle man die Daten ausgewählt haben möchte.

#### Beispiel
```
SELECT CustomerName, City FROM Customers;
```

#### Select ALL
Wenn man alle Spaleten einer Tabelle haben möchte gibt es das \* Symbol.

```
SELECT * FROM Customers;
```

### SQL DISTINCT
Mit **SELECT DISTINCT** kann man nur einzigartige Werte sich anzeigen lassen.

#### Syntax
```
SELECT DISTINCT column1, column2, ...
FROM table_name;
```

Das **DISTINCT** bezieht sich auf alle ausgewählten Spalten, und gibt daher nur die einzigartigen Kombinationen der Spalten zurück.

#### Beispiel
```
SELECT DISTINCT Country FROM Customers;
```
Gibt alle Länder aus aus den die Kunden herkommen.

### SQL WHERE
Mit **WHERE** können Zeilen gefiltert werden. Es gibt nur die Daten zurück, die die Bedingung erfüllen.

> [!NOTE] 
> **WHERE** wird bei SELECT als auch UPDATE und DELETE verwendet!


#### Syntax
```
SELECT column1, column2, ...
FROM table_name
WHERE condition;
```

#### Operatoren


| Operator | Beschreibung                                      |
| -------- | ------------------------------------------------- |
| =        | Equal                                             |
| >        | Greater than                                      |
| <        | Less than                                         |
| >=       | Greater than or equal                             |
| <=       | Less than or qual.                                |
| <> or != | Not equal.                                        |
| BETWEEN  | Between a certian range                           |
| LIKE     | Search for a pattern                              |
| IN       | To specify multiple possible values for a column. |


#### Beispiele
##### Numerisch
```
SELECT * FROM Customers
WHERE CustomerID=1; 
```
```
SELECT * FROM Customers
WHERE CustomerID > 80; 
```
##### Text
```
SELECT * FROM Customers
WHERE Country='Mexico'; 
```

### ORDER BY
Mit **ORDER BY** kann man den resultierenden Datensatz in aufsteigender oder absteigender Ordnung sotieren. Zeichenketten werden alphabetisch sortiert.

#### Syntax
```
SELECT column1, column2, ...
FROM table_name
ORDER BY column1, column2, ... ASC|DESC;
```

> [!NOTE] 
> Wird die Ordnung nicht angeben, wird es aufsteigend (ASC) sortiert.

#### Beispiele
```
SELECT * FROM Products
ORDER BY Price; 
```

```
SELECT * FROM Products
ORDER BY ProductName DESC; 
```

```
SELECT * FROM Customers
ORDER BY Country, CustomerName; 
```

```
SELECT * FROM Customers
ORDER BY Country ASC, CustomerName DESC; 
```

### AND / OR 
Die drei Operatoren **AND / OR** werden in der Bedingung des **WHERE** Operators verwendet. 

* **AND:** wird als wahr ausgewertet sollten alle Werte wahr sein.
* **OR:** wird als wahr ausgewertet sollte einer der Werte wahr sein.

#### Syntax
```
SELECT column1, column2, ...
FROM table_name
WHERE condition1 AND/OR condition2 AND/OR condition3 ...; 
```

#### Beispiel
```
SELECT * FROM Customers
WHERE Country = 'Spain' AND (CustomerName LIKE 'G%' OR CustomerName LIKE 'R%'); 
```

### NOT
Der **NOT** Operator negiert den Wahrheitswert der Bedingung.

#### Syntax
```
SELECT column1, column2, ...
FROM table_name
WHERE NOT condition;
```

#### Beispiele
```
SELECT * FROM Customers
WHERE NOT CustomerID > 50;
```

```
SELECT * FROM Customers
WHERE CustomerID NOT BETWEEN 10 AND 60;
```

### INSERT
Mit **INSERT** wird ein neuer Eintrag (Zeile) in der Tabelle erstellt.

#### Syntax
```
INSERT INTO table_name
VALUES (value1, value2, value3, ...); 
```
```
INSERT INTO table_name (column1, column2, column3, ...)
VALUES (value1, value2, value3, ...); 
```

#### Beispiele
```
INSERT INTO Customers
VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway');
```
```
INSERT INTO Customers (CustomerName, ContactName, Address, City, PostalCode, Country)
VALUES ('Cardinal', 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', '4006', 'Norway');
```

### NULL-Values
Ein Feld mit NULL hat keinen Wert.,
Wenn ein Feld einer Tabelle optional ist, kann dieser NULL werden.

#### Mit NULL-Werten umgehen
##### IS NULL
###### Syntax
```
SELECT column_names
FROM table_name
WHERE column_name IS NULL; 
```

###### Beispiel
```
SELECT CustomerName, ContactName, Address
FROM Customers
WHERE Address IS NULL;
```

##### IS NOT NULL
###### Syntax
```
SELECT column_names
FROM table_name
WHERE column_name IS NOT NULL; 
```

###### Beispiel
```
SELECT CustomerName, ContactName, Address
FROM Customers
WHERE Address IS NOT NULL;
```

### UPDATE
Mit **UPDATE** können existierende Einträge verändert werden.
> [!WARNING] 
> Wird das **WHERE** weggelassen, werden alle Einträge einer Tabelle **verändert**!

#### Syntax
```
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition; 
```

#### Beispiel
```
UPDATE Customers
SET ContactName = 'Alfred Schmidt', City= 'Frankfurt'
WHERE CustomerID = 1;
```

### DELETE
Mit **DELETE** können Einträge aus der Tabelle gelöscht werden.
> [!WARNING] 
> Wird das **WHERE** weggelassen, werden alle Einträge einer Tabelle **gelöscht**!

#### Syntax
```
DELETE FROM table_name WHERE condition;
```

#### Beispiel
```
 DELETE FROM Customers WHERE CustomerName='Alfreds Futterkiste'; 
```
### Alias (AS)
Spaltennamen können mit dem **AS** Operator umbenannt werden.

#### Syntax
```
SELECT column_1 AS Column1, column_2 AS Column2
FROM table
WHERE clause;
```

#### Beispiele
```
SELECT MIN(Price) AS SmallestPrice
FROM Products;
```

### Aggregation Funktionen
Diese Funktionen berechnen Werte aufgrund von Values und gibt ein einzelnen Wert zurück.
Aggregation Funktionen werde oft in der Kombination mit **GROUP BY** verwendet.

| Funktion | Beschreibung                                                |
| -------- | ----------------------------------------------------------- |
| MIN()    | Gibt den kleinsten Wert einer ausgewählten Spalte zurück.   |
| MAX()    | Gibt den größten Wert einer ausgewählten Spalte zurück.     |
| COUNT()  | Gibt die Anzahl von Zeilen zurück                           |
| SUM()    | Gibt die Summe einer numerischen Spalte zurück.             |
| AVG()    | Gibt den Durchschnittswert einer numerischen Spalte zurück. |

> [!NOTE] 
> Aggregations Funktionen ignoriere NULL-Werte außere die **COUNT()**-Funktion.

#### MIN()
##### Syntax
```
SELECT MIN(column_name)
FROM table_name
WHERE condition; 
```

##### Beispiel
```
SELECT MIN(Price)
FROM Products;
```

#### MAX()
##### Syntax
```
SELECT MAX(column_name)
FROM table_name
WHERE condition; 
```

##### Beispiel
```
SELECT MAX(Price)
FROM Products; 
```

#### COUNT()
##### Syntax
```
SELECT COUNT(column_name)
FROM table_name
WHERE condition; 
```

##### Beispiel
```
SELECT COUNT(*)
FROM Products;
```
```
SELECT COUNT(DISTINCT Price)
FROM Products;
```

#### SUM()
##### Syntax
```
SELECT SUM(column_name)
FROM table_name
WHERE condition; 
```

##### Beispiel
```
SELECT SUM(Quantity)
FROM OrderDetails; 
```
```
SELECT SUM(Quantity * 10)
FROM OrderDetails; 
```

#### AVG()
##### Syntax
```
SELECT AVG(column_name)
FROM table_name
WHERE condition; 
```

##### Beispiel
```
SELECT AVG(Price)
FROM Products;
```
```
SELECT * FROM Products
WHERE price > (SELECT AVG(price) FROM Products); 
```

### GROUP BY
**GROUP BY** gruppiert Zeilen mit dem selben Wert. **GROUP BY** wird often mit den **Aggregation Functionen** verwendet.

#### Syntax
```
SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
ORDER BY column_name(s); 
```

#### Beispiele
```
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country;
```
```
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
ORDER BY COUNT(CustomerID) DESC;
```

### HAVING
**WHERE** kann nicht mit aggeregierten Funktionen arbeiten, deswegen wurde **HAVING** hinzugefügt.

#### Syntax
```
SELECT column_name(s)
FROM table_name
WHERE condition
GROUP BY column_name(s)
HAVING condition
ORDER BY column_name(s);
```

#### Beispiele
```
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
HAVING COUNT(CustomerID) > 5;
```
```
SELECT COUNT(CustomerID), Country
FROM Customers
GROUP BY Country
HAVING COUNT(CustomerID) > 5
ORDER BY COUNT(CustomerID) DESC;
```

### LIKE
Mit **LIKE** kann man nach speziellen Mustern in einer Spalte suche.
Diese Muster werden mit Wildcards beschrieben.

#### Wichtige Wildcards
| Wildcard | Beschreibung                                     |
| -------- | ------------------------------------------------ |
| %        | Platzhalter für eine ungewisse Anzahl an Zeichen |
| _        | Platzhalter für ein Zeichen                      |

#### Syntax
```
SELECT column1, column2, ...
FROM table_name
WHERE columnN LIKE pattern; 
```

#### Beispiel
```
SELECT * FROM Customers
WHERE city LIKE 'L_nd__'; 
```
```
SELECT * FROM Customers
WHERE CustomerName LIKE 'La%'; 
```

### IN
Der **IN** operator erlaubt das angeben mehrere Werte, dieser kann auch als Abkürzung mehrer **OR** Bedingungen sein.

#### Syntax
```
SELECT column_name(s)
FROM table_name
WHERE column_name IN (value1, value2, ...);
```

#### Beispiele
```
SELECT * FROM Customers
WHERE Country IN ('Germany', 'France', 'UK');
```
```
SELECT * FROM Customers
WHERE Country NOT IN ('Germany', 'France', 'UK');
```
```
SELECT * FROM Customers
WHERE CustomerID IN (SELECT CustomerID FROM Orders);
```

### Between
Der **Between** Operator wählt Werte aus die in einer bestimmten Bereich liegen. Die Werte können numerisch, textuell oder Daten (Datum) sein.

> [!NOTE]
> **Between** ist inklusiv: Start und Endewerte sind im Bereich enthalten!

#### Syntax
```
SELECT column_name(s)
FROM table_name
WHERE column_name BETWEEN value1 AND value2;
```

#### Beispiel
```
SELECT * FROM Products
WHERE Price BETWEEN 10 AND 20;
```
```
SELECT * FROM Products
WHERE Price NOT BETWEEN 10 AND 20;
```
```
SELECT * FROM Products
WHERE ProductName BETWEEN 'Carnarvon Tigers' AND 'Mozzarella di Giovanni'
ORDER BY ProductName;
```

### JOINS
Mit **JOIN** können mehrere Spalten von zwei oder mehreren Tabellen kombiniert werden, basierend auf den in Beziehung stehenden Spalten.

#### Typen von JOINS
![2024_07_16-12_31_32](https://hackmd.io/_uploads/rkmI3am_C.png)

- **(INNER) JOIN**: Gibt die Zeilen zurück bei dem die Werte bei beiden Tabellen übereinstimmen.
- **LEFT (OUTER) JOIN:** Gibt alle Werte der linken Tabelle und die übereinstimmenden der rechten Tabelle.
- **RIGHT (OUTER) JOIN:** Gibt alle Werte der rechten Tabelle, sowie alle übereinstimmenden der linken Tablle zurück
- **FULL (OUTER) JOIN:** Gibt alle Werte zurück wenn es eine Übereinstimmung in der linken oder der rechten Tabelle gibt.

#### INNER JOIN
DER **INNER JOIN** wählt Datensätze aus, die in beiden Tabellen passende Werte haben. 
![2024_07_16-12_39_01](https://hackmd.io/_uploads/H1Q06TmdA.png)


##### Syntax
```
SELECT column_name(s)
FROM table1
INNER JOIN table2
ON table1.column_name = table2.column_name;
```
```
SELECT column_name(s)
FROM table1
JOIN table2
ON table1.column_name = table2.column_name;
```

##### Beispiele
```
SELECT ProductID, ProductName, CategoryName
FROM Products
INNER JOIN Categories ON Products.CategoryID = Categories.CategoryID; 
```

#### LEFT JOIN
Der **LEFT JOIN** gibt alle Datensätze aus der linken Tabelle (Tabelle1) und die passenden Datensätze aus dem rechten Tabelle (Tabelle2) zurück.

![2024_07_16-12_42_11](https://hackmd.io/_uploads/Sk4q0aQO0.png)

##### Syntax
```
SELECT column_name(s)
FROM table1
LEFT JOIN table2
ON table1.column_name = table2.column_name;
```

##### Beispiele
```
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
LEFT JOIN Orders ON Customers.CustomerID = Orders.CustomerID
ORDER BY Customers.CustomerName;
```

#### RIGHT JOIN
Das **RIGHT JOIN** Keyword gibt alle Datensätze aus der rechten Tabelle (Tabelle2) und die passenden Datensätze aus dem linken Tabellen (Tabelle1) zurück. 

![2024_07_16-12_55_04](https://hackmd.io/_uploads/rJD9WCQOR.png)

##### Syntax
```
SELECT column_name(s)
FROM table1
RIGHT JOIN table2
ON table1.column_name = table2.column_name;
```

##### Beispiele
```
SELECT Orders.OrderID, Employees.LastName, Employees.FirstName
FROM Orders
RIGHT JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID
ORDER BY Orders.OrderID; 
```

#### FULL OUTER
Der **FULL OUTER JOIN** gibt alle Datensätze zurück, wenn ein es eine Übereinstimmung entweder in der linken oder rechten Tabelle gibt. 

![2024_07_16-13_05_49](https://hackmd.io/_uploads/H1pGNCQOA.png)

##### Syntax
```
SELECT column_name(s)
FROM table1
FULL OUTER JOIN table2
ON table1.column_name = table2.column_name
WHERE condition; 
```

##### Beispiele
```
SELECT Customers.CustomerName, Orders.OrderID
FROM Customers
FULL OUTER JOIN Orders ON Customers.CustomerID=Orders.CustomerID
ORDER BY Customers.CustomerName;
```

### UNION
Der **UNION** Operator wird verwendet um die Ergebnisse zwei oder mehreren **SELECT**-Statements zu kombinieren.
- Jedes **SELECT** Statment innerhalb des UNION muss die gleiche Anzahl an Spalten haben
- Die Spalten müssen alle den selben Datentyp haben
- Die Spalten müssen auch alle in der selben Reihenfolge auftreten.

>[!NOTE]
>Der **UNION** Operator wählt nur distinktierte Werte aus. Um Duplicate zu erlauben gibt es den **UNION ALL** Operator.

#### Syntax
##### UNION
```
SELECT column_name(s) FROM table1
UNION
SELECT column_name(s) FROM table2; 
```

##### UNION ALL
```
SELECT column_name(s) FROM table1
UNION ALL
SELECT column_name(s) FROM table2; 
```

#### Beispiele
##### UNION
```
SELECT City FROM Customers
UNION
SELECT City FROM Suppliers
ORDER BY City;
```

```
SELECT City, Country FROM Customers
WHERE Country='Germany'
UNION
SELECT City, Country FROM Suppliers
WHERE Country='Germany'
ORDER BY City;
```

##### UNION ALL
```
SELECT City FROM Customers
UNION ALL
SELECT City FROM Suppliers
ORDER BY City;
```


### EXIST
Der **EXISTS**-Operator wird verwendet um zu testen ob es irgendeine Zeile in einer Subquery gibt. **EXISTS** gibt **TRUE** zurück sobald es eine oder mehr Zeilen in einer Subquery gibt.

#### Syntax
```
SELECT column_name(s)
FROM table_name
WHERE EXISTS
(SELECT column_name FROM table_name WHERE condition); 
```

#### Beispiele
```
SELECT SupplierName
FROM Suppliers
WHERE EXISTS (SELECT ProductName FROM Products WHERE Products.SupplierID = Suppliers.supplierID AND Price < 20); 
```
```
SELECT SupplierName
FROM Suppliers
WHERE EXISTS (SELECT ProductName FROM Products WHERE Products.SupplierID = Suppliers.supplierID AND Price = 22); 
```

### ANY / ALL
Die **ANY** und **ALL** operatoren erlauben einen Vergleich zuzuführen zwischen einer einzelen Spalten und einer Spanne von Werten.

#### ANY
Der **ANY** Operator:
- gibt einen Wahrheitswert als Ergebnis zurück
- gibt **TRUE** zurück sollte einer der Subquerys die Bedingung erfüllen

##### Syntax
```
SELECT column_name(s)
FROM table_name
WHERE column_name operator ANY
  (SELECT column_name
  FROM table_name
  WHERE condition); 
```

>[!Note]
> Der Operator 'operator' muss ein Vergleichsoperator sein (=,<>,!=,>,>=,< or <=)

##### Beispiele
```
SELECT ProductName
FROM Products
WHERE ProductID = ANY
  (SELECT ProductID
  FROM OrderDetails
  WHERE Quantity = 10); 
```

#### ALL
Der **ALL** Operator
- gibt einen Wahrheitswert zurück
- Gibt **TRUE** zurück wenn alle Values der Subquery die Bedinung erfüllen.
- Wird in **SELECT**, **WHERE** und in **HAVING** Statements verwendet.

##### Syntax
###### ALL with SELECT
```
SELECT ALL column_name(s)
FROM table_name
WHERE condition;
```

###### ALL with WHERE or HAVING (Überhaupt in ORACLE möglich?) 
```
SELECT column_name(s)
FROM table_name
WHERE column_name operator ALL
  (SELECT column_name
  FROM table_name
  WHERE condition); 
```

##### Beispiele
```
SELECT ALL ProductName
FROM Products
WHERE TRUE; 
```
```
SELECT ProductName
FROM Products
WHERE ProductID = ALL
  (SELECT ProductID
  FROM OrderDetails
  WHERE Quantity = 10); 
```

### Kommentar
Kommentare werden mit zwei Bindenstrichen eingeleitet.
```
 SELECT * FROM Customers -- WHERE City='Berlin'; 
 -- SELECT * FROM Customers;
SELECT * FROM Products;
```