SQL Cossacks

Massendatenimport - Arbeitsschritte, Probleme, Best Practices

Dr. Carsten Kumke

Einleitung

Die Weboberfläche SQL Cossacks bietet - natürlich - Möglichkeiten, Datensätze

  • anzulegen

  • zu ändern und

  • zu löschen.

Die Nutzung ist aber nur dann sinnvoll, wenn es darum geht, einzelne Datensätze zu bearbeiten. In vieler Hinsicht sind hier auch noch Verbesserungen einzubauen, so z.B.

  • muss das System reagieren, wenn durch eine Änderung auch verbundene Datenobjekte betroffen sind,

  • muss das System signalisieren und verzweigen, wenn zusätzliche Strukturen und Abhängigkeiten geschaffen werden müssen,

  • sollte das System, Vorschläge machen können (z.B. bei der Prüfung, ob ein Name bereits vorhanden ist)

  • und …​ und …​ und …​

Die Übernahme (der Import) von Massendaten ist über diese - zugegebenermaßen noch unzureichenden - Oberflächen nicht sinnvoll.

Massendatenimport

In den vergangenen zwanzig Jahren wurden vermehrt Kosakenregister oder Eideslisten von Kosakenverbänden publiziert. Diese Listings von Regimentern oder Hundertschaften einzeln einzugeben, ist weder ökonomisch, noch sinnvoll. Es bedarf daher eines Arbeitsprozesses, die Listings zu

  • extrahieren,

  • die Daten aufzubereiten,

  • Doubletten zu erkennen oder

  • Einträge bereits bekannten Kosaken zuzuordnen und - schließlich -

  • die Listings auf Datenbank-Ebene einzuspielen.

Die Einzelschritte dazu sind zahlreich und auch trickreich.

Der folgende Foliensatz stellt das Vorgehen - wie ich es mir in den vergangenen Jahren definiert habe - zusammen, gibt Tipps und weist auf Klippen hin, die zu umgehen oder zu vermeiden sind.

Arbeitsschritte (Überblick)

plantumlsteps
Figure 1. Arbeitsschritte

Dateinamenkonventionen

Jeden der oben genannten Arbeitsschritte fixiere ich mit einer gesonderten Archivdatei. Auf diese Weise kann ich v.a. bei strukturellen Fehlern immer einen früheren Arbeitsschritt zurückfallen.

PräfixFormatStatus

1*.txt

Text

Datenübernahme aus Ursprungsdatei

2*_raw.ods

ods, xlsx

Aufteilung Zeileninformation in Datenfelder

3*_check.ods

ods, xlsx

Eintrag IDs bekannter Kosaken, Systemnamen

4*_<Tabelle>.ods

ods, xlsx

Datentümpel (pro Zieltabelle)

5[1..n]_<Tabelle>.csv

csv

Vorstruktur, bereinigte Daten für Import

6[1..n]_<Tabelle>.sql

sql

Importdatei mit vollständigen INSERTS (Test)

7[1..n]_<Tabelle>_final.sql

sql

Getestete Importdatei (Produktion).

Achtung !

Ich will es nicht verhehlen ! Die Arbeiten sind mühselig und, je komplexer die Anwendung und ihr Datenmodell wird, werden sie in Zukunft wahrscheinlich noch mühlseliger werden, als es heute schon ist.

In den letzten Monaten (Mai 2023) habe ich die Register von Poltava 1723/1726 bearbeitet. Es handelte sich dabei um zwei Listen (einer Publikation) mit insgesamt gut 7.800 Kosaken.

Von der Datenübernahme bis zur Einspielung in das Produktivsystem hat es - obgleich ich schon einige Übung für mich in Anspruch nehmen konnte - ca. 8 (in Worten: acht) Wochen gedauert.

Wohlgemerkt - bei einem Rentner-Arbeitstag von ca. 6-8 Stunden.

Meine "Entwicklungsumgebung"

Vorab einige Informationen über die Tools, die ich einsetze. Ich bin überzeugt, dass Windows ebenfalls ausreichende Unterstützung liefert. Meine Erfahrungen (schon in den 1990er Jahren) waren aber die, dass Linux die besten Tools zur Verfügung stellt. U.a. die Nutzung von utf8-Zeichensätzen wurde lange von Microsoft mit der Borniertheit des Platzhirschen vernachlässigt.

Table 1. Tools
Tool

OS

Linux Debian

pdf-Reader

Okular, gscan2pdf,

Texterkennung

tesseract, cuneiform, gocr

txt-Editor

kate, kwrite, (atom), VSCodium …​

Tabellenkalkulation

Libreoffice CALC

Rohdaten

Das Register von 1654 (die Bodjanskij-Ausgabe von 1874) habe ich noch manuell erfasst. Das heißt: Ich habe die Liste, die aus gut 40.000 Kosaken bestand, händisch abgeschrieben. Dieses Vorgehen kann ich heute nicht mehr empfehlen, da sich auch bei größter Sorgfalt der Fehlerteufel schnell einschleicht.

Dank der Veröffentlichung in pdf-Dateien können die (meisten) Register heute per Copy & Paste übernommen und in eine normale Text-Datei übertragen werden. Allerdings birgt auch dies gewisse Risiken. U.a. die Angewohnheit, Kosakenlisten in zwei Spalten darzustellen, sorgt bei der Übernahme der Daten häufig für nicht unerheblichen Nachbearbeitungsbedarf.

Die Fähigkeiten der Texterkennung funktioniert für Altkirchenslavische Lettern nicht immer korrekt! Hier gibt es je nach Ausgangsdokument charakteristische Abweichungen.

Rohdaten (1): Zeichen

Bei der Textübernehme gilt es einiges zu beachten:

  • Die Namen sollten so erfasst werden, wie sie in der Quelle verzeichnet sind (späteres Tabellenfeld: orig_name, orig_familija)

  • Transliteration findet für Zeichen statt, die im mordernen Kyrillischen nicht üblich sind, d.h.

    • Ѣ (jat') → e

    • Ѳ (fita) → f

    • Ѡ (omega) → o

  • Auch das 'tverdyj znak' (ъ) kann verschwinden, sofern es heute keinerlei Bedeutung mehr spielt.

  • Probleme bei Nutzung von Texterkennungstools:

    • kirchenslavische Sonderzeichen werden nicht erkannt,

    • statt 'tverdyj znak' (ъ) erkennt das System 'mjachkij znak' (ь),

    • Ѣ (jat') wird in die wirrsten Buchstabenkombinationen umgesetzt,

    • Unsauberkeiten im Quelldokument führen zu Fehlinterpretationen.

Rohdaten (2): Zeilen

Bei der Übernahme der Daten aus der Vorlage sollten möglichst alle Informationen übernommen und so in die Abschrift eingetragen werden, dass sie später (in der CALC-Tabelle) berücksichtigt werden können:

  • Übernahme der Seitenzahlen in einer extra Zeile

  • Übernahme der Rubriken/Überschriften in einer extra Zeile

  • Spaltenweises einlesen der Namenslisten

source

raw

Rohdaten (3): Zeilen

Ziel ist es,

  • für jede Art der Information eine Zeile zu verwenden

  • bestimmte Informationsarten schon bei Übernahme zu kennzeichnen, nämlich

    • Seitenzahlen beginnen mit //

    • Rubriken sind mit vorangestelltem Tab gekennzeichnet

    • Namen und Zusatzinformationen für einen Kosaken sind in einer Zeile, ggf. mit Tab oder Kürzel (#) gekennzeichnet.

Das erleichtert die erste Rohbearbeitung über alle Daten entweder in der Textdatei oder später in der Tabellenkalkulation.

Rohdaten (4): Vorstrukturieren

Den Abschluss bilden vereinheitlichende Aufgaben, die v.a. mit Suche/Ersetze-Funktionen umgesetzt werden können. Hierbei hat sich v.a. die Nutzung von regulären Ausdrücken als sehr einfach und Ziel führend erwiesen, nämlich:

  • bei der Korrektur charakteristischer Übertragungsfehler, z.B. (urrprünglich Ѣ) "'К" → "e"

  • bei der Vereinheitlichung von Zusatzinformationen: пеший и убогий, убогий пеший etc.

  • Vorstrukturierung der verschiedenen Info innerhalb einer Zeile: Name Rang "mit Sohn" # von einem Hof.

Auf diese Weise können alle Informationen in die Tabellenkalkulation übernommen werden.

  • Für jeden Informationsblock besteht eine Zeile.

  • Zusammengehörige, aber unterschiedliche Datentypen betreffende Informationen sind innerhalb einer Zeile mit Kürzeln wie # gekennzeichnet.

Strukturdaten

In der Tabellenkaklulation geht es vornehmlich darum, die Rohdaten zu vollständigen Datenstrukturen umzuformen und für jede Datenbank-Tabelle eine (gekapselte) Importdatei herzustellen.

Hier wird sich darüber hinaus erweisen, ob die benötigten Strukturen auch bereits in der Datenbank enthalten sind. U.a. wird man also prüfen müssen, ob auch alle genannten kurinni, sotni etc. bereits angelegt sind. Ggf. sind fehlende Daten nachzupflegen.

Da wir in diesem Schritt schon ganz nah an der Datentechnik der SQL Cossacks-Webseite sind, entstehen auch immer wieder Fragen, inwieweit das System sinnvoll erweitert werden muss. Beispiel:

Bei der Bearbeitung des Registers von 1723 für Myrhorod tauchten im Text massenweise Angaben zu Familienbeziehungen auf. So etwa

"Никита Шапочка В него пять синов, Авраам, Андрей, Кондрат, Петро и Василь"

Seitdem gibt es Datentabellen für Familien und Familienbeziehungen.

Strukturdaten (1): Erste Schritte

Da die Rohdaten konsequent nach Zeilen gegliedert sind, kann das txt-File einfach in Calc importiert werden. Sofern Zeilen weise bereits vorstrukturiert wurde (mit # oder Tab) können diese Zeichen beim Import bereits als Feldtrenner angegeben werden.

Anschließend geht es erst einmal darum, diejenigen Zeilen zu verarbeiten, die sich nicht auf einzelne Kosaken beziehen. Das sind u.a. die Seitenzahlen, "Rubriken" wie Ort (kurinnja, sotnja) und ggf. Status. Statusangaben (pešij, konnyj, možnyj, ubogij, aber auch "Leistet Dienst mit anderen von einer Hofstelle") packen wir - je nach Bedarf - in gesonderte Spalten.

Sind in einem Register auch Familienmitglieder (Beispiel: "в него брат Сидор"), dann duplizieren wir diese Zeile, so dass es einen Eintrag für den zuerst genannten Bruder und eine für den Bruder - in diesem Falle "Sydir" - gibt. In einer eigenen Spalte können wir den Verwandtschaftsgrad festhalten: Bruder.

Insofern ist es wichtig, dass die ursprüngliche Reihenfolge der Zeilen immer wieder hergestellt werden kann, - die Verwandschaftsbezihung Bruder → Bruder ergibt sich erst aus dem Kontext der Abfolge!

Strukturdaten (2): Erste Schritte

Das Ergebnis dieses Arbeitsschrittes sollte sein, dass

  • für jede Person eine Zeile genutzt wird,

  • für jeden alle Angaben und Informationen, die eindeutig genug sind, bereits sauber voneinander getrennt und enthalten sind.

Table 2. Spalten (initial)

Rohdaten

rank

polk_id

sotnja_id

kurinnja_id

source_id

page

STATUS

FAMILIE

Стефан Кочерженко

KKO

33

111

1063

186

83

Dienst gemeinsam von einem Hof, в него брат Сидор

Bruder

Strukturdaten (3): Nützliche Helfer

Da im Verlaufe der folgenden Schritte Umsortierungen immer wieder nötig werden, nutze ich eine weitere Spalte, um über eine Sortierung die ursprüngliche Abfolge immer wieder herstellen zu können. Deshalb erstelle ich noch eine Spalte register_position, mittels der alle Daten abhängig von der militärischen Einheit durchnummeriert werden. Dies ist u.a. dann der Fall, wenn man im Verlaufe der Bearbeitung die erfassten Daten nochmals mit der Quelle abgleichen will.

Sobald alle Zusatzinformationen auf die Zeilen jedes Kosaken verteilt sind, können sämtliche leeren Zeilen gelöscht werden.

Es ist weiterhin hilfreich, wenn man für jeden der im folgenden dargestellten Schritte den Zwischenstand in einer gesonderten Datei abspeichert. Ich habe da so meine Erfahrungen gemacht …​

Strukturdaten (4): Namen

Was bis hierhin vorliegt ist eine durchgängige Liste von Kosaken.

Im nächsten Schritt wenden wir uns den Namen zu. Hier kommen gleich vier Namensvarianten ins Spiel, die in der DB zu füllen sind:

  1. Name, wie in der Quelle geschrieben

  2. Name, wie in der Quelle (transskribiert)[1]

  3. vereinheitlichter Systemname (transskribiert)[1]

  4. vereinheitlichter Systemname (Kyrillica)

Die Rohdaten-Spalte mit den Namen wird

  • mit der Funktion Daten ▸ Text in Spalten aufgelöst und

  • auf die Spalten orig_familija, orig_imja, orig_sufiks_imena verteilt,

  • Anschließend kopieren wir diese Spalten in die Spalten sys_name, sys_firstname und sys_add_name sowie utf_name, utf_firstname und utf_add_name.

1. Transskription erfolgt über wissenschaftliche Regeln deutscher Bibliotheken.

Strukturdaten (5): Systemnamen

Da Schreibweisen im 17. und 18. Jahrhundert wenig genormt waren, müssen die Namen für die Spalten Systemnamen vereinheitlicht werden. Hierbei orientiere ich mich weitgehend an ukrainischen Telefonbüchern oder https://uk.wikipedia.org.

Ich selbst arbeite in diesen Schritten gerne mit den transkribierten Namen, d.h. ich übersetze die Zeichen in den Spalten sys*_ über Suche-Ersetze-Aufrufe in das lateinische Alfabet.

Diese 1:1-Umsetzung ist nur ein Zwischenschritt, denn nun folgt

  1. der Aufruf jedes Namens in der Datenbank, um zu prüfen, ob der genannte Kosak oder Name bereits bekannt ist,

  2. wenn ein Kosak bekannt ist bzw. gefunden wird, erfassen der cossack_id in einer eigenen Spalte (Löschen des Namens in den Spalten sys*)

  3. für die verbleibenden Kosaken wird ein entsprechender Einheitsname gewählt.

Grundsätzlich ist es für die Suche nach Kosaken besser, wenn die Transskription als erstes vorgenommen wird. Anschließend kann man die Zeilen alfabetisch ordnen und so die Suche nach Kosaken bündeln.

Strukturdaten (6): Suche

Für die Suche stehen auf https://sc7.kumke.net mehrere Möglichkeiten zur Verfügung, die jede für sich einen spezifischen Zweck verfolgen. Es kann

  1. nach den Namen selbst gesucht werden,[1]

  2. nach den Registern unter Organisation ▸ Polk | Hundertschaft | Kurinnja ▸ Register oder aber

  3. nach dem Listing von Kosaken für einzelne Ortschaften Orte

Am wertvollsten hat sich bei der Erfassung von Registern die unter 3) genannte Suche erwiesen. Es werden alle Kosaken, die in dem Ort bereits erfasst wurden, aufgelistet.

Sollten bei einer Suche nur wenige Kosaken gefunden werden, könnte es sich um eine neuere kurinnja handeln. In solchen Fällen empfiehlt es sich über Kosaken ▸ Erweiterte Suche die Suche auf die sotnja auszudehnen.

1. Die Suche über Kosaken ▸ Suche berücksichtigt sowohl die Felder sys* und utf* in der Tabelle cossacks als auch die Felder orig* in der Tabelle military_positions. Auf diese Weise wird der Kosak auch nach bereits bekannten Namenschreibweisen gesucht.

Struturdaten (7): Kosaken im Ort

suche poltava ort
Figure 2. Listing von Kosaken für den Ort Poltava

Strukturdaten (8): Vornamen

Schwierig gestaltet sich bei der Systemnamen-Recherche immer die Umsetzung von Kosenamen in Langnamen:

  • Ist Pas’ko nun als Opanas oder als Pavlo umzusetzen ?

  • Wie geht man mit Les’ko um ? Levon, Oleksij oder Leontij …​

Hier gibt es keine Eselsbrücke, - die Hilfe eines Muttersprachlers wäre nötig. In einzelnen Quellen aber gibt es aber (regionaler Bezug) durchaus charakteristische Eigenheiten. So erwiesen sich in Poltava viele Les’ko als Oleksij und nicht Leontij.

Für welche Lösung man sich auch immer entscheidet - in den Spalten orig* kann immer rekonstruiert werden, wer im Original wie wurde.

Strukturdaten (9): Bereinigte Daten

Sind alle Kosaken im System gesucht und die gefundenen entsprechend (gefüllte cossack_id) markiert worden, sieht die Tabelle in etwa folgendermaßen aus:

register verified
  • Für bekannte Kosaken benötigen wir keinen Systemnamen mehr - er wird anhand der vorhandenen cossack_id aus der Datenbank gezogen.

  • Neue Kosaken haben noch keine id, dafür benötigen wir den Systemnamen.

  • Sämtliche sonstige Informationen befinden sich in einer Zeile der Tabelle

    • Daten zum militärischen Rang, Regiment, Hundertschaft etc. sind bereits gefüllt,

    • Daten zur Quelle (source_id) sowie Band, Dokumentennummer (falls vorhanden), Seitenzahl sind ebenfalls vorhanden.

    • Weitere Informationen, die erst später bearbeitet/extrahiert werden, befinden sich ggf. in den Spalten danach.

Strukturdaten (10): cossack_id

Natürlich kann man neue Kosaken in der späteren Importdatei ohne id an das System übergeben. Die Datenbank gibt für das Indexfeld id dann einen Wert (next autoincrement) vor. Dieses Verhalten macht das Handling über alle Datenbanktabellen her jedoch äußerst komplex. Schließlich müssten wir dann Zeilenweise, d.h. für jeden Kosaken, alle ihn betreffenden Tabellen und deren Einträge sequentiell importieren und für jeden Datensatz das System mit dem tag @last mitteilen, dass die letzte ID genutzt wird.

  • Tabelle residences

  • Tabelle cossack_comments

  • Tabelle military_positions

  • Tabelle cossack_families

  • Tabelle cossack_relatives

Um die Datenbanktabellen einzeln und unbhängig voneinander speisen zu können, gebe ich deshalb die id für jeden Kosaken vor. Die Tabellenkalkulation bietet hier einfache Wege …​

Strukturdaten (11): sys*, utf*, orig_names

Wenn man - wie ich - auf der Basis der lateinischen Umschrift gearbeitet hat, sind folgende Arbeiten zu erledigen:

  • Kopieren der Spalten sys_name, sys_firstname, sys_add_name in die Spalten utf_name, utf_firstname, utf_add_name

  • Transskribieren der utf*-Felder in Kyrillica[1]

  • Die noch unbehandelten Spalten orig_name, orig_firstname und orig_addname sind dann noch ins Latinica zu transkribieren.

1. Achtung ! Reihenfolge beachten, da das lateinische Alfabet kyrillische Zeichen z.T. nur durch Zeichenkombinationen wiedergeben kann (h → г vor ch → х führt bei Chmel’nyc’kyj eben zu Цгмельницький)

Strukturdaten (12): Familien

Sind in einer Quelle Familieninformationen enthalten ("Пилипъ Бутенко з синами Яремою и Даниломъ на едномъ дворе"), so befinden sich nach dem oben genannten Vorgehen für eine Zeile in der Quelle jetzt drei Zeilen, wobei Pylyp in der Familienspalte als Vater und die Söhne Jarema und Danylo als Sohn ausgewiesen sind.

Da inzwischen auch alle Kosaken über eine ID identifizierbar sind, können wir die Strukturen für die Tabellen cossack_families und cossack_relatives aufbereiten.

Über die gesonderten Tabellenfelder family_id, father_id, mother_id für die cossack_families und die Felder [relatives]_id, family_id, cossack_id können nun die Familienzusammenhänge Datenbank konform vorstrukturiert werden. Auch hier werden die IDs für die Familien von mir vorgegeben.

families
Figure 3. Familien- und Verwandte

Strukturdaten (13): Fehlende Organisationsdaten

Bei der Aufbereitung der Daten werden u.U. Änderungen oder Erweiterungen in den Stammdaten notwendig. Dies betrifft v.a.

  • Anlage und Zuordnung von Orten (locations), kurinni und Kurinnja-Sotnja-Beziehungen (sotkur)

  • Änderung von Zugehörigkeiten von sotni zu polky (polksot-Tabelle)

  • - natürlich - die Quellenangaben (sources-Tabelle).

Diese Strukturen sollten am besten bei der Bearbeitung der Daten im System angelegt werden. Schließlich kann man eine bisher unbekannte Kurinnja nicht mit einer ID identifizieren, wenn diese noch nicht angelegt ist.

Datentümpel

Was ist der Status bis hierher ?

  • Bekannte Kosaken sind identifiziert und in der Tabelle mit id gekennzeichnet,

  • Neue Kosaken haben einen Systemnamen (in Latinica und Kyrillica) und eine vorgegebene id,

  • Daten für die Tabelle military_positions sollten vollständig sein und ggf. fehlende Organisationseinheiten bereits im System angelegt worden sein,

  • ggf. vorhandene zusätzliche Informationen, wie etwa Status, Rolle oder Familienbeziehungen, sind noch unbearbeitet, aber für jeden Kosaken in einer Zelle hinterlegt.

Diese Datenstruktur dient nunmehr als Ausgangspunkt für die Erstellung von eigenen Dateien jeweils für eine Datenbanktabelle. Das bedeutet, dass die Datenfelder, die nicht zur Import-Tabelle gehören, in jedem Schritt zu löschen sind.

Schauen wir uns doch mal grob die zu bedienenden Datenstrukturen an …​[1]

1. Mehr zum Datenmodell siehe 40 Jahre SC7

Relationen

cossacks relations

Datentümpel: military_positions

Da alle Daten für diese Tabelle bereits ermittelt sein sollten, bleibt hier zunächst nur

  • die überflüssigen Spalten (sys*, utf*) zu löschen,

  • diejenigen Informationen zu löschen, die nicht zu den Positionsdaten gehören (Familienbeziehungen, Bemerkungen zum Kosaken),

  • eine neue Spalte id (für military_positions) einzufügen,

  • die zusätzlichen, noch nicht bearbeiteten Informationen zu sichten, um zu entscheiden, wo sie abgelegt werden sollen.

Auch die IDs in dieser Tabelle geben wir dem System vor. Sollte nämlich aus den Zusatzinformationen Inhalte in die military_positions_comments abgelegt werden, dann können wir diese mit den vorgebenen IDs zuordnen.

Datentümpel: cossack_remarks oder military_positions_comments ?

Für die bisher noch nicht näher bewerteten Zusatzinformationen ist nun zu entscheiden, wo sie am besten platziert werden sollen, -

  • bei den Stammdaten des Kosaken oder

  • bei den Positionsdaten der militärischen Karriere ?

Die Entscheidung hierüber kann knifflig sein: Was bedeutet "Fußvolk, völlig verarmt" ? Ist es nicht eher ein sozialer Status, der in den Stammdaten (unter cossacks_remarks) besser aufgehoben wäre ? Wie soll damit umgegangen werden, wenn ein "Kosakenplatz" vom Vater und seinen drei Söhnen versehen wird ?

Ich habe ich mich entschlossen, derlei Informationen einstweilen als Kommentar zur militärischen Position abzuspeichern.

  • Einerseits bleibt der Zusammenhang zur ursprünglichen Quelle gewahrt,

  • auch lässt sich die Information genau datieren und

  • auch Änderungen an einem solchen Status - die es zwischen den Eidesleistungen immer gegeben hat - können später noch nachvollzogen werden.

Datentümpel: Finalisierung military_positions (1)

db milpos
  • Noch zu verarbeitende Zusatzinformationen werden inklusive Referenz-id in einer gesonderten Tabelle abgespeichert.

  • Es sollten danach nur noch Felder in der Tabelle sein, die zur Datenbank-Tabelle military_positions gehören:

    • Leere Felder müssen nun mit NULL gefüllt werden,

    • Die Datumsfelder date_begin und date_end mit Werten gefüllt sein, Format JJJJ-MM-TT

    • Das Feld created_at enthält den Wert NOW()

Datentümpel: Finalisierung military_positions (2)

An Anfang und Ende der Tabelle erstellen wir nun zwei neue Spalten, in denen wir tags einfügen, die später durch die entsprechenden SELECT-Anweisungen ersetzt werden sollen. So etwa

  • #mil-pos_begin# in der ersten Spalte

  • #mil-pos_end# in der letzten Spalte

Jetzt kann die Tabelle als csv-Datei abgespeichert werden:

  • Zeichensatz: Unicode (UTF8)

  • Feldtrenner: ;

  • Zeichenkettentrenner: '

Die Felder date_begin und date_end müssen als Textfelder exportiert werden, d.h. im csv mit Zeichenkettentrenner '' hinterlegt sein.

Datentümpel: military_positions_comments

Die Kommentare zu den militärischen Positionen sind schnell erledigt. Die hinterlegten Informationen sollten so aufbereitet sein, dass sie einen sinnvollen Satz ergeben.

Die military_position_id sollte aus dem vorhergehenden Bearbeitungsschritt bekannt sein. Es brauchen nur diejenigen Zeilen in der Tabelle zu verbleiben, die Zusatzinformationen enthalten. Folgende zusätzliche Spalten sind einzubauen und zu füllen:

  • IDs in der military_position_comments-Tabelle → gefüllt mit: NULL

  • Am Ende die Spalten

    • user_initials → 'cku'

    • created_at → 'NOW()'

Schließlich bauen wir am Anfang und Ende der Tabelle jeweils wieder die SELECT-Tags ein:

  • #mp_comment_begin#

  • #mp_comment_end#

Das ganze wird dann wiederum als csv-Datei abgespeichert.

Datentümpel: cossacks (1)

Wenn man jeweils für jeden Bearbeitungsschritt eine Version seiner Tabellendatei zwischengespeichert hat, kann man jetzt auf die Datensätze zurückgreifen, die nach der Verfikation der Kosakennamen entstanden sind.

Hier finden wir ja nun, solche Kosaken, bereits bekannt sind und solche, die neu sind.

Für die bereits bekannten Kosaken ist lediglich zu prüfen, ob ggf. Zusatzinformationen in die Tabelle cossack_remarks oder in die residences einzuspielen sind. Ist dies nicht der Fall, dann können alle Zeilen mit diesen Kosaken aus der Tabelle gelöscht werden, da diese Informationen bereits im System sind.

Es verbleiben jetzt lediglich diejenigen Kosaken, die neu angelegt werden müssen.

Datentümpel: cossacks (2)

Für die neuen Kosaken sind nun die Datenstrukturen anzulegen:

Table 3. Tabellenspalten Neue Kosaken (initial)

Feld

Inhalt

Aktion

id

Vorgegebene Kosaken-ID

Sollte bereits vorliegen

sys* - uft*

Systemname (transskribiert - Kyrillica)

Sollte bereits vorhanden sein.

gender_id

Mann = 0, Frau = 1

Sollte bereits vorhanden sein.

birth - death

Geburts- / Todesdaten

Zu diesem Zeitpunkt meist: NULL

user_initials

Initialen des Bearbeiters

hier: cku

region_id

Region = polk_id

Polk_id aus Positionsdaten

created_at

Timestamp

NOW()

Datentümpel: cossacks (3)

Anfangs- und Endtags für die SELECT-Anweisungen machen den Abschluss dieser Arbeiten, d.h. die erste und letzte Spalte sind entsprechend mit

  • #cossack_begin#

  • #cossack_end#

zu füllen.

Da (wenn) die Positionsdaten noch nicht gelöscht wurden, kann man noch die Spalte kurinnja_id und die Spalte cossack_id in eine neue Tabelle exportiert werden. Aus diesen Fragmenten können wir später die Tabelle residences befüllen.

Ist das geschehen, können alle anderen Spalten aus der Tabelle gelöscht werden und die Tabelle selbst als csv-Datei exportiert werden.

Datentümpel: residences

Leider sind die IDs für kurinni und Orte (locations) nicht bzw. nicht immer identisch. Dies macht es erforderlich, die kurinnja_id auf die location_id umzuschreiben. Eine Arbeit, die nun einmal zu machen ist.

Ist das erfolgt, steht man vor einer Tabelle mit den folgenden Spalten:

  • id

  • cossack_id

  • location_id

Auch hier fügen wir nun noch entsprechende Tags in die erste und letzte Spalte ein:

  • #residence_begin#

  • #residence_end#

und exportieren das Ganze in eine csv-Datei.

Datentümpel: cossack_families & cossack_relatives

Für die Aufspielung der Familiendaten sind nur die Datenstrukturen herzustellen, die im Schritt Strukturdaten bereits zusammengetragen wurden.

Table 4. Datenfelder Kosakenfamilien

Tabelle cossack_families

Tabelle cossack_relatives

id

id

father_id

family_id

mother_id

cossack_id

user_initials

user_initials

created_at

created_at

In die erste und letzte Spalte fügen wir noch die SELECT-Tags ein und speichern jeweils eine csv-Datei für families und relatives ab.

Importdaten

Am Ende des Bearbeitungsblocks Datentümpel sollten nun folgende csv-Dateien vorliegen:

  • 51_poltava_1723_new-cossacks.csv

  • 52_poltava_1723_residences.csv

  • 53_poltava_1723_cossack_families.csv

  • 54_poltava_1723_cossack_relatives.csv

  • 55_poltava_1723_cossack_remarks.csv

  • 56_poltava_1723_military_positions.csv

  • 57_poltava_1723_military_positions_comments.csv

Die Daten sind bereits so gebündelt, dass sie sich nur noch auf eine Datenbanktabelle beziehen. Es dürfen sich keine Leerzeilen mehr darin befinden.

Die Nummerierung 5x entspricht bereits der Reihenfolge, in der die späteren Importe vorgenommen werden müssen. Da wir die IDs selbst vorgeben, müssen erst die neuen Kosaken in die Datenbank importiert werden. Danach können die anderen Daten eingespielt werden. Den Abschluss bilden die Kommentare zu den Positionen, die ja abhängig von den IDs der Positionsdaten sind.

Inserts

Diese Bearbeitungsphase ist an sich schnell erledigt. Im wesentlichen besteht sie nur aus Suche-/Ersetze-Funktionen, um die SQL-Befehle in die Dateien zu bringen.

Allerdings: Hier bezahlt man letztlich für alle möglichen Schludrigkeiten und Fehler, die man auf dem Weg bis hierhin begangen hat!

Für jede Tabelle sind Befehle anzulegen, die der Datenbank angibt, wie sie mit jeder Zeile umgehen soll. Zum Beispiel öffnen wir die Datei 51_poltava_1723_new-cossacks.csv mit einem Texteditor und ersetzen den Tag #cossack_begin# durch folgenden Text

INSERT INTO `cossacks`(`id`, `sys_name`, `sys_firstname`, `sys_add_name`,
`utf_name`, `utf_firstname`, `utf_add_name`, `gender_id`, `birth`, `death`,
`user_initials`, `region_id`, `created_at`) VALUES (

Den End-Tag #cossack_begin# ersetzen wir durch

);

Jede Zeile stellt jetzt einen vollständigen SQL-Befehl dar, mit dem die Daten in die Datenbank eingespielt werden.

Fährnisse

Auf folgende Dinge muss unbedingt geachtet werden, weil sie zu Fehlermeldungen, zum Abbruch des Importvorgangs oder aber zur Zerrüttung der Daten führen können:

  • Die Spaltenköpfe aus der Tabellenkalkulation in der ersten Zeile müssen natürlich entfernt werden.

  • Die Anzahl und die Reihenfolge der Datenfelder im Insert-Befehl müssen natürlich stimmig sein, mit der Abfolge der Datenfelder in der csv.

  • Datumsfelder müssen als Textfelder hinterlegt sein, d.h. 1723-00-00 muss mit Textkennung umgeben sein ('1723-00-00') !

  • Systemtags wie NULL, NOW() etc. dürfen nicht mit Textkennung versehen sein; ebenso numerische Werte wie IDs.

  • Apostrophe in den transskribierten Namenfeldern müssen mit Backslash (\) "abgefangen" sein (\').

Importdatei

Sobald die Bearbeitung abgeschlossen ist, kann man die Dateien als *.sql-Dateien abspeichern.

sql
Figure 4. sql-Datei für neue Kosaken

Gute Texteditoren, bei denen man den Modus auf SQL (MySQL) einstellen kann, weisen einen durch Verwendung von Farben schon darauf hin, dass etwas an einzelnen Stellen nicht stimmen kann.

Finalisierung der anderen Datentöpfen

Das selbe Verfahren findet für alle anderen Datentabellen statt. Das bedeutet, in jeder csv-Datei werden die entsprechenden Inserts angebracht und die für sql notwenigen Änderungen durchgeführt.

Jede Datei wird am Ende als sql-Datei abgespeichert.

Hilfreich ist es, wenn man sich die oben genanten Dateinamenkonventionen bedient und neben dem Präfix ''6'' auch bereits festlegt, in welcher Reihenfolge die Dateien zu importieren sind (in der Tabelle als [1..n] gekennzeichnet).

Im allgemeinen wird die Reihenfolge etwa so aussehen:

  1. new cossacks

  2. cossack_remarks

  3. cossack_families

  4. cossack_relatives

  5. residences

  6. military_positions

  7. military_positions_comments

Test

Liegen für alle Datenbanktabellen die sql-Dateien vor, sollte man den Importprozess auch testen. Hierzu verwende man eine aktuelle Kopie der Datenbank (oder erstelle eine Sicherungskopie, um den initialen Zustand jederzeit wiederherstellen zu können) und spiele die Daten in korrekter Reihenfolge ein.

Bricht das System den Import vorzeit ab, sollte man den früheren Zustand wiederherstellen. Ersatzweise kann man im Testsystem auch anhand der verwendeten neuen IDs oder anhand des timestamps im Feld created_at die bis dahin importierten Daten wieder löschen.[1]

Ist der Import für alle Dateien erfolgreich, sollte (Stichproben weise) im Testsystem geprüft werden, ob auch alles korrekt ist (z.B. Aufruf jeder Kurinnja unter Orte). Ist dies der Fall, darf man sich beglückwünschen und sich die Freigabe für den Import in das Produktivsystem erteilen.

1. Man kann natürlich auch nur den Fehler bereinigen und am Abbruchpunkt mit dem Import wieder einsetzen. Das würde aber bedeuten, dass man die Importdateien wieder auf mehrere Dateien aufteilen müsste, was den Import-Prozess auf der Produktivumgebung doch wieder beeinträchtigt.

Verwendete Hilfen

Dieser Foliensatz

Allen Mitwirkenden an diesen Tools der Open Source-Gemeinde sei hiermit Dank ausgesprochen !

Fragen ?

Jederzeit unter

Michendorf, 01.12.2023