Archive for the ‘Programmierung’ Category.

Normalisierung von Datenbanktabellen – Die 1. Normalform

This entry is part 1 of 3 in the series Data Warehouse, 3NF und Dimensional Modelling

Am besten lernt man, wenn man lehrt! Da ich mich momentan intensiver mit Themen wie Data Warehouse, Data Vault, 3NF und Dimensional Modelling beschäftige, versuche ich in den Artikeln dieser Reihe für mich ein wenig Licht in das Begriffsdunkel zu bringen. Quellen dieser Artikel sind die entsprechenden Wikipedia-Artikel, Google Ergebnisse und die 7. Auflage des Buchs „Fundamentals of Database Systems“ von Elmasri und Navathe, das es bei Amazon für knapp 45 Euro gibt.

In diesem Artikel soll es um die Normalformen gehen, siehe dazu den Wikipedia-Artikel für die Grundlagen.

Betrachten wir als Beispiel einen Satz Musikdaten, bestehend jeweils aus Interpret, Albumtitel, Erscheinungsjahr, Geburtsjahr des Interpreten, Titelliste:


Gabi Mustermann - Gabi singt, 2000, 1963, {1. Gabi singt laut, 2. Gabi singt leise, 3. Gabi singt weiter}
Max Mustermann - Debütalbum, 2001, 1960, {1. Von der Liebe, 2. Vom Leben, 3. Vom Ableben, 4. Duett mit Gabi} 

Diese Daten werden wir im Folgenden in die entsprechenden Normalformen bringen.

1NF

Für die 1. Normalform gilt (laut Wikipedia): Jedes Attribut der Relation muss einen atomaren/atomischen Wertebereich haben, und die Relation muss frei von Wiederholungsgruppen sein.

  • Atomar heißt, dass zusammengesetzte, mengenwertige oder geschachtelte Wertebereiche (also relationenwertige Attributwertebereiche) nicht erlaubt sind. Der Wertebereich keines Attributs einer Relation in 1NF kann in weitere (sinnvolle) Teilbereiche aufgespaltet werden.
  • Frei von Wiederholungsgruppen bedeutet, dass Attribute, die gleiche oder gleichartige Information enthalten, in eine andere Relation ausgelagert werden müssen.

Angewandt auf unser Beispiel bedeutet

  • atomar, dass wir sinnvoll aufteilbar Attribute wie Interpret-Albumtitel in entsprechende einzelne Attribute aufteilen müssen.
  • frei von Wiederholungsgruppen, dass die Liste der Lieddaten auf einzelne Zeilen verteilt werden muss.

Für unsere Musikdaten ergibt sich daher die folgende 1NF:

Interpret Album Erscheinungsjahr Geburtsjahr Tracknummer Titel
Gabi Mustermann Gabi singt 2000 1963 1 Gabi singt laut
Gabi Mustermann Gabi singt 2000 1963 2 Gabi singt leise
Gabi Mustermann Gabi singt 2000 1963 3 Gabi singt weiter
Max Mustermann Debütalbum 2001 1960 1 Von der Liebe
Max Mustermann Debütalbum 2001 1960 2 Vom Leben
Max Mustermann Debütalbum 2001 1960 3 Vom Ableben
Max Mustermann Debütalbum 2001 1960 4 Duett mit Gabi

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Die ersten Schritte mit Amazon RDS

Beruflich werde ich mich in der nächsten Zeit intensiver mit AWS Anwendungen beschäftigen, daher hier ein Überblick über die ersten Schritte mit Amazon RDS.

RDS steht für „Amazon Relational Database Service“ und unterstützt eine Reihe von Datenbanken, aktuell MySQL, MariaDB, Oracle, Postgres, MS SQL und andere.

Schritt 1 besteht darin, die zu nutzende Datenbank auszuwählen, ich nutze hier die preiswerteste MariaDB Instanz, die es im Rahmen von FreeTiers.

In Schritt 2 definieren wir den Namen der Datenbank-Instanz sowie Login und Passwort des Administrators.

In Schritt 3 legen wir die Instanzgröße und Speichergröße fest, die automatische Größenerweiterung habe ich deaktiviert.

In Schritt 4 wird die VPC definiert, keine Ahnung welchen Zweck das hat.

Danach benötigt RDS einige Minuten, um die Datenbank anzulegen. Aus dem Internet ist die Datenbank damit noch nicht erreichbar, wir müssen noch die Datenbank modifizieren und „Publicly accessible“ auf „YES“ setzen. Die Modifikation soll sofort erfolgen.

Jetzt kann man beispielsweise aus HeidiSQL die Datenbank mit den Parametern Endpoint, Benutzername und Passwort erreichen.

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

„Spiele“-Kritik: While True learn()

Per Zufall bin ich vor einigen Tagen auf ein Juwel im Steam-Shop gestoßen: „while True learn()“. Es ist kein Spiel im klassischen Sinne, sondern mehr eine Simulation zum Lernen von KL/ML-Algorithmen.

Die Geschichte ist schnell erzählt: Programmierer programmiert, kommt nicht weiter, seine Katze übernimmt und erklärt ihm in Katzensprache, was er tun muss. Da er kein Katzisch spricht, baut er mit Hilfe aus dem Netz schrttweise ein System zur Verständigung mit der Mieze.

Das Spiel geht anfangs recht einfach los, ein oder zwei Blöcke positionieren, Verbindungslinien setzen, los.

Über zeitliche Einschränkungen und Kostendruck kommt man aber schnell an den Punkt, an dem man denken muss.

Von mir eine absolute Empfehlung!

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Erste Schritte mit Flask

Hier ein Link zu einem Video, das die ersten Schritte mit Flask zeigt: https://www.youtube.com/watch?v=QjtW-wnXlUY

Über set FLASK_APP=fl-01.py (wenn der Name der Datei so lautet) und flask run startet man das ganze.

from flask import Flask
 
app = Flask(__name__)
 
@app.route('/')
def index():
    return('<h1>Hello World</h1>')
 
 
@app.route('/<name>')
def namer(name):
    return('<h1>Hello {}</h1>').format(name)

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Die „passendste“ Datei mit Python ermitteln (fuzzywuzzy)

Für eine Anwendung habe ich eine Möglichkeit gesucht, die „passendste“ Datei in einem Verzeichnis zu suchen. Dies kann relevant sein, wenn die Anwendung eine bestimmte Datei in einem Verzeichnis erwartet, die aber leicht anders benannt wurde als es die Vorgabe erfordert.

Das folgende Beispielprogramm nutzt die Levenshtein-Funktionen der fuzzywuzzy Bibliothek, um die Datei zu finden, die das größte Maß an Gleichheit zum Muster besitzt.

Man kann natürlich auch RegExps benutzen, mit der fuzzywuzzy Bibliothek ist es aber auch recht intuitiv.

# -*- coding: utf-8 -*-
import os
from fuzzywuzzy import fuzz
 
def guess_file(template, path):
    max_ratio = 0
    file_max_ratio = ''
 
    for file in os.listdir(path):
        file_wo_suffix = os.path.splitext(file)[0]
 
        ratio = fuzz.ratio(file_wo_suffix, template)
        if ratio > max_ratio:
            max_ratio = ratio
            file_max_ratio = file
 
    return(file_max_ratio, max_ratio)
 
 
print(guess_file('Meine Inputdaten','R:/'))

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Virtuelle Python-Umgebungen nutzen

Bisher nutze ich immer die lokale Python-Installation bzw. Distributionen wie WinPython oder Anaconda, für einen meiner Linux-Server möchte ich jedoch virtuelle Umgebungen nutzen, die von der lokalen Python-Installation strikt getrennt sind. Hier die notwendigen Schritte:

python3 -m venv /home/uwe/vpython

Falls das nicht geht: apt-get install python3-venv installiert das venv Modul

cd /home/uwe/vpython/bin

source activate kann nicht direkt aufgerufen werden, es muss (bei der Bash/zsh) mittels source aufgerufen werden. Verlassen kann man die virtuelle Umgebung mittels deactivate.

Der Prompt ändert sich zu (vpython) uwe@zotac:~/vpython/bin$, unsere virtuelle Umgebung ist fertig.

In der Umgebung können wir jetzt weitere Pakete installieren:

(vpython) uwe@zotac:~/vpython/bin$ pip3 install pandas
Collecting pandas
  Downloading https://files.pythonhosted.org/packages/a4/5f/1b6e0efab4bfb738478919d40b0e3e1a06e3d9996da45eb62a77e9a090d9/pandas-1.0.4-cp37-cp37m-manylinux1_x86_64.whl (10.1MB)
    100% |████████████████████████████████| 10.1MB 33kB/s
Collecting pytz>=2017.2 (from pandas)
  Downloading https://files.pythonhosted.org/packages/4f/a4/879454d49688e2fad93e59d7d4efda580b783c745fd2ec2a3adf87b0808d/pytz-2020.1-py2.py3-none-any.whl (510kB)
    100% |████████████████████████████████| 512kB 629kB/s
Collecting python-dateutil>=2.6.1 (from pandas)
  Downloading https://files.pythonhosted.org/packages/d4/70/d60450c3dd48ef87586924207ae8907090de0b306af2bce5d134d78615cb/python_dateutil-2.8.1-py2.py3-none-any.whl (227kB)
    100% |████████████████████████████████| 235kB 1.2MB/s
Collecting numpy>=1.13.3 (from pandas)
  Downloading https://files.pythonhosted.org/packages/d6/c6/58e517e8b1fb192725cfa23c01c2e60e4e6699314ee9684a1c5f5c9b27e1/numpy-1.18.5-cp37-cp37m-manylinux1_x86_64.whl (20.1MB)
    100% |████████████████████████████████| 20.1MB 16kB/s
Collecting six>=1.5 (from python-dateutil>=2.6.1->pandas)
  Downloading https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
Installing collected packages: pytz, six, python-dateutil, numpy, pandas
Successfully installed numpy-1.18.5 pandas-1.0.4 python-dateutil-2.8.1 pytz-2020.1 six-1.15.0
(vpython) uwe@zotac:~/vpython/bin$

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Overviews of SQL Joins (with LaTeX code)

Here’s a short overview of SQL joins, find the source code of the document attached to the PDF (use Adobe Reader to access it).

SQL Joins

\documentclass[12pt]{article}
\usepackage{xcolor}
\usepackage{arev}
\usepackage{attachfile}
 
 
\usepackage{tikz}
\usetikzlibrary{shapes,snakes}
\def\firstcircle{(0,0) circle (2cm)}
\def\secondcircle{(0:3cm) circle (2cm)}
 
\colorlet{circle edge}{blue!50}
\colorlet{circle area}{blue!20}
\colorlet{white area}{white}
 
\tikzset{
filled/.style={fill=circle area, draw=circle edge, thick},
outline/.style={draw=circle edge, thick},
white/.style={fill=white area, draw=circle edge, very thick}
}
 
\begin{document}
 
\textattachfile{\jobname.tex}{\LaTeX~Code}
 
\section{Inner Join}
 
Inner joins return those records, that are present in table 1 and table 2.
 
\begin{center}
\begin{tikzpicture}[scale=1, every node/.style={scale=1}] % Inner Join
    \begin{scope}
        \clip \firstcircle;
        \fill[filled] \secondcircle;
    \end{scope}
    \draw[outline] \firstcircle node {A};
    \draw[outline] \secondcircle node {B};
\end{tikzpicture}
\end{center}
 
\section{Left Join}
 
Every record from table 1 is returned, regardless if it has a matching record in table 2. If the record has a matching record in table 2 this record from table 2 is returned as well.
 
\begin{center}
\begin{tikzpicture}[scale=1, every node/.style={scale=1}] % Left Join
    \begin{scope}
        \clip \firstcircle;
        \draw[filled] \firstcircle node {A}
                                     \secondcircle;
    \end{scope}
    \draw[outline] \firstcircle
                   \secondcircle node {B};
\end{tikzpicture}
\end{center}
 
\clearpage
 
\section{Left Outer Join}
 
Those records from table 1 are returned, that do not have a match in table 2.
 
\begin{center}
\begin{tikzpicture}[scale=1, every node/.style={scale=1}] % Left Outer Join
    \draw[filled] \firstcircle node {A};
    \draw[white] \secondcircle node {B};
    \draw[outline] \firstcircle node {A};
\end{tikzpicture}
\end{center}
 
\section{Right Join}
 
Every record from table 2 is returned, regardless if it has a matching record in table 1. If the record has a matching record in table 1 this record from table 1 is returned as well.
 
\begin{center}
\begin{tikzpicture}[scale=1, every node/.style={scale=1}] % Right Join
    \begin{scope}
        \clip \secondcircle;
        \draw[filled] \firstcircle \secondcircle node {B};
    \end{scope}
    \draw[outline] \firstcircle node {A} \secondcircle;
\end{tikzpicture}
 
\end{center}
 
\clearpage
 
\section{Right Outer Join}
 
Those records from table 2 are returned, that do not have a match in table 1.
 
\begin{center}
\begin{tikzpicture}[scale=1, every node/.style={scale=1}] % Right Join 2
    \draw[filled]   \secondcircle node {B};
    \draw[white]  \firstcircle node {A};
    \draw[outline] \secondcircle node {B};
\end{tikzpicture}
\end{center}
 
 
 
\section{Theta Join}
 
Every row from dataset 1 is multiplied by every row of dataset 2. Usually a mistake unless you really want this Cartesian product.
 
\begin{center}
\begin{tikzpicture}[scale=1, every node/.style={scale=1}] % Theta
    \draw[filled] \firstcircle node {A} \secondcircle node {B};
\end{tikzpicture}
\end{center}
 
\clearpage
 
\section{Full Outer}
 
Returns all records from table 1 and table 2 regardless if they have matches in the other table. Records, that do match, are linked together via key. 
 
\begin{center}
\begin{tikzpicture}[scale=1, every node/.style={scale=1}] % Full Outer
    \draw[filled] \firstcircle node {A};
    \draw[filled] \secondcircle node {B};
    \begin{scope}
        \clip \firstcircle;
         \fill[white] \secondcircle;
        \draw[outline] \secondcircle;  
        \draw[outline] \firstcircle;  
    \end{scope}
\end{tikzpicture}
\end{center}
 
\end{document}

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

SQL: Nur den aktuellsten Eintrag aus einer gejointen Tabelle laden

Ich habe seit ein paar Monaten wieder verstärkt Gelegenheit, meine rostigen SQL-Kenntnisse aufzufrischen. Kürzlich bin ich dabei an einer kleinen Herausforderung vorbeigekommen, die mich doch ein paar Minuten mehr beschäftigt hat. Gegeben sind zwei Tabellen, Namen und Adressen.

Namen

ID Name
1 Anna Amsel
2 Bernd Borstel
3 Cesar Causel
4 Dagmal Dack

Adressen

ID NameID Adresse
1 1 Amselweg 2
2 2 Badgasse 34
3 3 Chausseeweg 123
4 3 Dorfstraße 34
5 1 Alabasterpfad 32

ID ist jeweils der Primary Key, NameID der Fremdschlüssel von Adressen auf Namen. Ziel der Übung ist es, alle Namen mit der (sofern vorhanden) aktuellsten Adresse abzufragen.

Ein inner join bringt ganz klar das falsche Ergebnis, denn Dagmar Dack fehlt in der Ergebnismenge, Anna und Cesar sind zweimal vertreten.

SELECT n.Name, a.Adresse FROM Namen n JOIN Adressen a ON n.ID = a.NameID ;

Ein left join muss her, was das Ergebnis aber nur ein wenig besser macht: Dagmar ist jetzt drin, Anna und Cesar aber immer noch doppelt:

SELECT n.Name, a.Adresse FROM Namen n JOIN Adressen a ON n.ID = a.NameID ;

Beholfen habe ich mir dann mit einem Subselect:

SELECT n.Name, a.Adresse FROM Namen n
LEFT JOIN (SELECT MAX(ID) ID, MIN(NameID) NameID, MIN(Adresse) Adresse FROM Adressen GROUP BY NameID) a
ON n.ID = a.NameID

Ergebnis

Name Adresse
Anna Amsel Alabasterpfad 32
Bernd Borstel Badgasse 34
Cesar Causel Chausseeweg 123
Dagmal Dack NULL

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Monatskalender für LaTeX mit Python erzeugen

Hier ein Beispiel, wie man mit Python kleine Monatskalender erzeugen kann. Geht auch mit LaTeX allein, ich möchte aber verschiedene Output-Formate (Markdown, HTML, etc.) erzeugen und dabei die komplette Kontrolle über den Code behalten.

# -*- coding: utf-8 -*-
 
import calendar
import datetime
 
def number_of_weeks(year, month):
    """
        Returns a tupel with the ISO no of the first and week and the no of weeks
    """
    tup_month_days = calendar.monthrange(year, month)
    first = datetime.date(year, month, 1)
    last = datetime.date(year, month, tup_month_days[1])
    first_week = first.isocalendar()[1]
    last_week = last.isocalendar()[1]
    return (first_week, last_week, last_week-first_week+1)
 
def gen_cal_latex(year, month):
    """
        https://stackoverflow.com/questions/9459337/assign-value-to-an-individual-cell-in-a-two-dimensional-python-array
    """
    c = calendar.TextCalendar()
    week_month_first, week_month_last, no_of_weeks = number_of_weeks(year, month)
 
    # generate calendar list, using tupel as a key    
    m = {(i, j):' ' for i in range(no_of_weeks) for j in range(7)}
 
    for tupel_date in c.itermonthdays4(year, month):
        t_year, t_month, t_day, t_weekday = tupel_date
        # use only dates inside the required month
        if t_month == month:
            temp_date = datetime.date(t_year, t_month, t_day)
            # check in which week we are with the current date
            # to get index for the list
            week_no = temp_date.isocalendar()[1]
            m[week_no % week_month_first, t_weekday] = t_day
 
    print(r'\begin{tabular}{rrrrrrr}')
    print(r'Mo & Di & Mi & Do & Fr & Sa & So \\')
    for i in m:
        if i[1] < 6:
            print('{0} &'.format(m[i]), end='')
        else:
            print('{0}'.format(m[i]),end='')
        if i[1] == 6:
            print(r'\\')
    print(r'\end{tabular}')
 
gen_cal_latex(2020, 4)

Erzeugt werden kleine Monatskalender der Form

\begin{tabular}{rrrrrrr}
Mo & Di & Mi & Do & Fr & Sa & So \\
  &  &1 &2 &3 &4 &5\\
6 &7 &8 &9 &10 &11 &12\\
13 &14 &15 &16 &17 &18 &19\\
20 &21 &22 &23 &24 &25 &26\\
27 &28 &29 &30 &  &  & \\
\end{tabular}

Per Copy & Paste kann man den Code in ein LaTeX-Dokument kopieren, natürlich lässt sich das alles auch direkt in eine LaTeX-Datei schreiben.

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website

Ein Xerox 860 System sucht ein neues Zuhause

Aus dem Nachlass eines Nachbarn habe ich gestern ein Xerox 860 System bekommen.

Wer es nicht kennt (so wie ich bis gestern noch):

Bevor PCs und Macs den Markt aufrollten, gab es auch Systeme für die Verarbeitung von Texten, die sich durch hohe Kosten und (aus heutiger Sicht) ungewöhnliche Maße auszeichnen.

Das Xerox 860 war so etwas wie der Rolls-Royce unter diesen Systemen. 128 KByte (!) RAM, keine Festplatte, zwei 8″ Diskettenlaufwerke in einem 80 Kilo Block, dazu ein fast 30 Kilo schwerer Drucker und ein Schwarz-Weiss-Monitor.

Es gibt sogar einen Basic-Interpreter dafür, das System ist wohl CP/M kompatibel.

Da die Maschine nicht wirklich wohnzimmer-tauglich ist, suche ich ein Plätzchen in einem Museum oder einer privaten Sammlung dafür. Ich möchte kein Geld dafür haben, die Maschine muss nur in Köln abgeholt werden.

UPDATE 17.05.2020

Die Xerox hat, zusammen mit einer SUN, einer VAX und weiteren Stücken, ihren Weg in das Technikmuseum Matthias Schmitt (www.tecmumas.de) angetreten.

Uwe

Uwe Ziegenhagen likes LaTeX and Python, sometimes even combined. Do you like my content and would like to thank me for it? Consider making a small donation to my local fablab, the Dingfabrik Köln. Details on how to donate can be found here Spenden für die Dingfabrik.

More Posts - Website