Winzen reloaded: Normalisiert – und jetzt?

In den vorangegangenen Schritten hatte ich anhand der Daten zur Winzengruppe, die @derguenther bereitgestellt hat, knapp und blumig erklärt, wie man eine Datenbank darauf entwickeln kann, die zumindest grundlegend (also nicht im orthodoxen, sondern forschungsdienlichen Sinn) normalisiert ist.

Jetzt stellt sich die Frage: Was mache ich jetzt damit?

Der Sinn einer normalisierten (relationalen) Datenbank wird nicht automatisch klar, wenn man bislang Excel gewohnt war. Eine relationale Datenbank wie mySQL ist immer dann stark, wenn Datensätze mit einander in Beziehung stehen. Bei historischen Personendaten ist das immer ganz besonders interessant, wenn man Beziehungen, Zeitverläufe etc. erfassen will. Wer kennt wen? Wer hielt sich wann wo auf?

Gehen wir das an der Winzengruppe mal durch – wir könnten folgende Dinge visualisieren wollen:

  • eine “Personenakte” – alle wichtigen Personendaten, die bekannten Wohnsitze, die bekannten Mitgliedschaften in NS-Organisationen im Kontrast zu bekannten Widerstandsaktivitäten, alle wichtigen “Zeitstempel” belegter Aktivitäten.
  • Einen Zeitstrahl  – also alle Aktivitäten, die bestimmte Personen zwischen bestimmten Daten unternahmen
  • Eine Karte – also eine Abbildung, wo welche Aktivitäten bestimmter Personen zwischen bestimmten Zeiten stattfanden.
  • Eine Beziehungsvisualisierung – welcher Akteur kennt wenn, wer überwacht wen, wer verrät wen (und wen nicht), wer agiert von Amts wegen / aus freien Stücken für / gegen wen?

So konservativ ein “Aktenblatt”, so verrückt eine Beziehungsgraph am Ende aussehen mag – am Anfang steht immer das Ergebnis einer Abfrage, und das ist zunächst eine tabellarische Liste von Datensätzen.

Hier kommen jetzt das Kernstück ins Spiel, die für nahezu alle relationalen Datenbanken namensgebend ist: Die Structured Query Language (SQL). Jeder SQL-Dialekt ist ein bisschen eigen, aber der Kern ist immer gleich:

SELECT 
<* oder kommagetrennte Liste der Spaltennamen> 
FROM 
<Tabellenname oder kommagetrennte Liste mit Alias> 
WHERE 
<Filterkriterium> 
ORDER BY <Sortierungskriterium>;

SQL ist im Kern eine gut lesbare Sprache, in der Regel kann man einfache SQL-Abfragen als einen Satz lesen und verstehen:

SELECT LastName, FirstName, BirthDate FROM SamplePerson WHERE PersonId = 102;

Will man einen exakten Datensatz erhalten, sollte man gezielt nach einem Primärschlüssel abfragen – das ist jener Wert, der den Datensatz eindeutig bestimmt. Aber woher sollte man den kennen? Der Anwendungsfall ist eigentlich immer dann gegeben, wenn man vorher nach einem Namen gesucht hat, z.B. so:

SELECT PersonId, LastName, FirstName FROM SamplePerson WHERE LastName = 'Mustermann' OR FirstName = 'Max' ORDER BY LastName ASC, FirstName ASC;

Diese Abfrage holt die Werte für PersonId, LastName, FirstName aus der Tabelle mit den Personendaten, wo der Nachname Mustermann ist oder der Vorname Max. Die Ergebnismenge wird zuerst aufsteigend nach dem Nachnamen, dann aufsteigend nach dem Vornamen sortiert. Damit kann man z.B. eine Liste herstellen, die anhand der PersonId auf die erste Abfrage verweist.

Jetzt gibt es natürlich ein “Problem”: Wir haben ja gerade erst die Daten auf mehrere Tabellen verteilt. Wie kommen wir denn da wieder ran.

Es gibt mehrere Wege mit unterschiedlichen Ergebnissen:

  • SELECTs über mehrere Tabellen
    Solche Abfragen ergeben in der Regel ein Kreuzprodukt, d.h. für jeden Datensatz in Tabelle A wird je ein Datensatz mit jedem einzelnen Datensatz von Tabelle B erstellt. Existieren in beiden Tabellen gleichnamige Spalten, wird ein impliziter JOIN vermutet und durchgeführt. Ansonsten kommt ein Kreuzprodukt heraus, das man mit WHERE-Bedingungen ausfiltern muss, um irgendwelche brauchbaren Ergebnisse in der Hand haben will. Die typische Verwendung hierfür ist eigentlich der implizite JOIN, daher verweise ich erstmal auf den Abschnitt zu JOINs.
  • SELECTs mit Sub-SELECTs
    Mit Subselects kann man sehr dynamisch filtern, indem man das Ergebnis einer Abfrage als Filterkriterium einer anderen Abfrage nimmt. Ich könnte z.B. in Erfahrung bringen, welche PersonenId als Beschuldigte in einer Gerichtsverfahrens-Tabelle vorkommen, also z.B. so:
SELECT PersonId FROM Gerichtsverfahren;

Allerdings könnten jetzt mehrere PersonIds vorkommen, falls mehrere Verfahren gegen eine Person anhängig sind oder waren. SQL hat dafür das Keyword DISTINCT.

SELECT DISTINCT PersonId FROM Gerichtsverfahren;

Jetzt landen nur noch von einander unterschiedliche PersonIds in der Ergebnismenge. Und damit fragen wir nun die Personentabelle ab:

SELECT LastName, FirstName FROM Person WHERE PersonId IN (SELECT DISTINCT PersonId FROM Gerichtsverfahren);

Jetzt bekommen wir eine Liste von Vornamen und Nachnamen der Personen, gegen die mindestens ein Gerichtsverfahren anhängig war.

  •  JOINs
    Der Name lässt vermuten, worum es geht: Die Daten einer Tabelle werden mit den  Daten einer zweiten Tabelle zusammengeführt. JOINs verbinden immer exakt zwei Tabellen miteinander, man kann allerdings mehrere JOINs nacheinander durchführen und in eine Ergebnismenge eingehen lassen.
    Es gibt zwei Arten – INNER und OUTER sowie zwei (respektive drei) Richtungen.

    • INNER JOINs
      beschreiben einen Vorgang, wenn für jeden Datensatz in Tabelle A mindestens ein Datensatz in Tabelle B existiert. In der Ergebnismenge tauchen nur Datensätze auf, die in beiden Tabellen verwurzelt sind.
      Wir könnten hier z.B. Vorname, Nachname des Beschuldigten in einem Gerichtsverfahren holen und die Bezeichnung des Verfahrens und seinen Gegenstand aus der zweiten Tabelle.
    • OUTER JOINs
      In der Ergebnismenge tauchen in Abgrenzung zu INNER JOINS nun alle Datensätze einer Tabelle auf, verbunden mit Datensätzen aus der zweiten Tabelle, wo Treffer existieren.

      • LEFT JOINs
        holen alle Datensätze der ersten Tabelle und ergänzen die Werte aus der zweiten Tabelle, wo Treffer gefunden werden. Ansonsten bleiben die entsprechenden Spalten leer.
        Wir könnten hier eine Liste der Personen mit Vorname und Nachname erstellen lassen und jeweils Gegenstand und Ergebnis des letzten anhängigen Gerichtsverfahrens anzeigen lassen.
      • RIGHT JOINs
        holen alle Datensätze der ersten Tabelle, für die ein Treffer in der zweiten Tabelle gefunden wird. Für diese Treffer werden die Werte aus der zweiten Tabelle auf den Datensatz ergänzt. Außerdem entstehen für alle Datensätze aus der zweiten Tabelle, für die die erste Tabelle keine Treffer aufweist. Wir könnten also alle bearbeiteten Fälle eines bestimmten Gerichts anzeigen lassen, und Vornamen und Nachnamen von Personen ergänzen, die in der Datenbank bereits existieren. So ließe sich etwa ablesen, ob bestimmte Tatvorwürfe gegen die untersuchte Gruppe häufiger auftreten als gegen eine Vergleichsgruppe, ob die Verfahrensausgänge sich unterscheiden.
      • FULL (OUTER) JOINs
        machen beides – Sie zeigen Datensätze aus A ohne B, A mit B und B ohne A. Im Prinzip ist das nichts anderes als eine Denormalisierung.

Das ist – im Prinzip – die ganze Magie. Es gibt noch eine Menge SQL-Details, die wichtig und hilfreich sind, aber das werden wir dann Schritt für Schritt dazufügen.

Heimwerken

Um das Ganze auszuprobieren, braucht Ihr einen Webserver – dazu kann man wie schon mal gesagt auf dem eigenen Rechner den XAMPP-Webserver installieren (https://www.apachefriends.org/de/index.html) – das ist eines der wenigen Pakete, was sofort einen lauffähigen Webserver, Datenbankserver,  PHP, Perl etc. mitbringt. Oder Ihr klickt Euch auf OpenShift von RedHat eine kostenlose OpenShift-Instanz anlegen (www.openshift.com). OpenShift ist eine sogenannte Platform-as-a-Service (PaaS), d.h. ein Dienstleister, bei dem Ihr bedarfsorientiert eine Entwicklungsplatform bekommt. Heroku ist die bekanntere PaaS-Firma, allerdings ist Heroku limitierter und teurer. Für den Anfang erstellt Ihr Euch am Besten einfach erstmal eine Applikation mit der Programmiersprache Eurer Wahl  (z.B. PHP 5.4), und wenn diese Applikation erstellt wurde, ergänzt ihr die vorgeschlagenen Add-Ons für Datenbank (z.B. mySQL) und die Verwaltungsoberfläche für die Datenbank (z.B. phpMyAdmin) hinzufügen. Und dann kann’s losgehen – im nächsten Teil.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

*

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.