Zur Navigation

Normalisierung von Datenbanktabellen

am Beispiel von Datenbanktabellen für ein Wörterbuch

1 Ranma (Gast)

Das Wikibook „Einführung in SQL“ enthält die so ziemlich verständlichste Erklärung zu den Normalformen. Davon gibt es mindestens fünf. Die ersten drei davon sollen für jede Datenbank sinnvoll sein, weitere nichts mehr bringen und nur mehr Rechenzeit verbrauchen. Das heißt, daß man sich an folgende fünf Regeln halten sollte.

1. Jede Spalte enthält nur atomische (also nicht weiter teilbare) Werte.
2. Spalten, die gleiche oder gleichartige Informationen enthalten, sind in eigene Tabellen (Relationen) auszulagern.
3. Jede Tabelle enthält einen Primärschlüssel.
4. Alle Informationen in den Spalten, die nicht Teil des Primärschlüssels sind, müssen sich auf den gesamten Primärschlüssel beziehen.
5. Informationen in den Spalten, die nicht Teil des Primärschlüssels sind, dürfen funktional nicht voneinander abhängen.

Davon gehören die ersten drei Regeln zur ersten Normalform, während die zweite und die dritte Normalform jeweils nur eine zusätzliche Regel haben und sich auf Daten beziehen, die in mehreren zusammengehörenden Tabellen gespeichert sind. Es gibt einige Erklärungen zur Normalisierung. Manche mit Beispielen dazu. In den Beispielen werden zumeist Datensätze verwendet, die eins zu eins zusammengehören. Das muß bei richtigen Datenbanktabellen jedoch nicht der Fall sein. Hauptsächlich daraus ergeben sich einige Verständnisprobleme.

Zu 1.: Das verstehe ich, obwohl ich es noch nicht ganz umgesetzt habe. Solange man aus einem Eintrag noch zusätzliche Informationen extrahieren kann, soll man das auch tun und die extrahierten Informationen in einer zusätzlichen Tabellenspalte unterbringen. In meinen Wörterlisten ist so manche Information nicht eindeutig abgegrenzt, darum werde ich einige Tabellen noch mehrmals von Skripten abgrasen lassen müssen, bis alle Informationen in eigenen Tabellenspalten untergebracht sein werden.

Zu 2.: Verstehe ich nicht. Hätte ich gleiche Informationen in mehreren Spalten in einer Tabelle, dann kämen manche Spalten doppelt oder mehrfach vor. Wieso sollte ich die in eine weitere Tabelle auslagern, also zusätzlich zu einer Spalte, die die Information enthält nochmal speichern?

Allerdings hätte ich auch Informationen, konkret die Angabe von Fachgebieten (normalerweise in den Wörterlisten als [math.] [med.] [geo.] und so weiter), die keinmal, einmal oder auch zu mehreren (zum Beispiel zusätzliche Angabe [US] oder [GB] in der Liste für Englisch) in einem Datensatz vorkommen können. Vielleicht ist das gemeint, denn da weiß ich tatsächlich nicht, ob ich in solchen Fällen sämtliche Inhalte von eckigen Klammern zusammen in eine Tabellenspalte quetschen soll oder vielleicht drei getrennte mache, die dann in den meisten Fällen leer bleiben würden. Eine eigene Tabelle dafür würde aber kaum etwas daran ändern, daß die meisten Datensätze dann trotzdem nur eine oder keine Spalte füllen würden.

Zu 3.: Die meisten meiner Tabellen haben einen Primärschlüssel bekommen, der aus einer Kombination von Spalten besteht. Meine drei Tabellen, auf die ich Informationen aus der Liste für Japanisch verteilt habe, besitzen keinen Schlüssel oder Index. Nirgendwo in den drei Tabellen gibt es eine Spalte, deren Einträge sich nicht wiederholen dürften. Wegen der Wiederholungen pro Spalte (aber nicht pro ganzem Datensatz), wüßte ich nicht, welche Spalte sich als Index eignen würde. Bei einer Kombination aus Spalten wären sie in allen drei Tabellen unterschiedlich. Bei einer zusätzlichen Spalte, die einfach durchzählt, wäre der Index wiederum bei allen drei Tabellen unterschiedlich. Aber für eine Ausgabe müßte ein Skript auf alle drei Tabellen zugreifen.

In dem Wikibook steht auch noch, daß ein Primärschlüssel keine weiteren Informationen enthalten, sondern nur Index (falls Index und Schlüssel keine Synonyme sind, dann gibt es da noch etwas, das ich nicht verstehe) sein sollte. Vor dem Eintragen konnte ich das nicht machen, weil dann doppelte Datensätze nicht als doppelt erkannt und verworfen hätten werden können. Natürlich sind in den Tabellen mit Schlüsseln aus kombinierten Spalten nur nichtdoppelte Datensätze enthalten. Dadurch sollte sich ein anderer Schlüssel nachträglich einbauen lassen. Datensätze sollen auch nicht von einer bestimmten Reihenfolge abhängig sein. Bei einer Tabelle (Japanisch Schreibweisen und Aussprachen) habe ich das nicht richtig hinbekommen. Ich dachte mein Skript macht das, aber es ist ziemlich schwierig hinzubekommen. Jedenfalls ohne die Datensätze unnötig zu vervielfachen.

4. Keine Ahnung, was das bedeuten soll. Das Wikibook sagt die Lösung sei, weitere Tabellen anzulegen.

5. Ich bin mir nicht sicher, was das bedeuten soll. Das Wikibook sagt wieder die Lösung sei, weitere Tabellen anzulegen. Ich glaube vorerst, daß diese Regel erfüllt ist, falls man die Informationen in einer Spalte auch in einer anderen Tabelle unterbringen könnte und sie trotzdem wiederfinden würde. Vielleicht aber auch genau andersherum.

Manche Datensätze enthalten nicht nur einzelne Wörter, sondern ganze Sätze. Darunter können Sätze mit zusätzlichen Informationen zu einzelnen Wörtern sein oder Beispielsätze für die Verwendung eines Wortes. Ich werde wahrscheinlich noch einige Beispieldatensätze bringen, wo ich nicht weiterkomme. Aber erstmal muß ich noch eine Wörterliste einlesen, einige noch weiter atomisieren und dann habe ich noch die Englisch-Wörterlisten vom FreeDict-Projekt, bei denen ich aufgegeben habe. Aber sie enthalten noch zusätzliche Informationen, vor allem die Aussprache in Lautschrift. Persönlich brauche ich die zwar nicht unbedingt, aber es wäre doch schade, wenn ich die schon vorhandenen Informationen verschwenden würde. Diese möchte ich darum auch noch irgendwie meiner Tabelle für Englisch (die mit der Wörterliste der TU Chemnitz befüllt wurde, noch nicht atomisiert) zukommen lassen.
Ranma

04.11.2015 04:19

2 Jörg Kruse

Ein Beispiel für 2.:

Wenn Datensatz 1 die Angabe [math.] hat, Datensatz 9 die Angaben [math.] und [med.] und die Datensätze 2 bis 8 keine Angaben, dann würde die Zusatztabelle so ausschauen:

Index  Wort-ID   Angabe
1      1         math
2      9         math
3      9         med

... würde also viel weniger Platz beanspruchen als mehrere Einzelspalten in der Haupttabelle

zu 3.:

wenn man eine Spalte mit der Eigenschaft AUTO_INCREMENT anlegt, zählt MySQL den Index von selbst hoch. Die Indexe sind auch wichtig für die Verknüpfungen der Tabellen per JOIN

Ich werde wahrscheinlich noch einige Beispieldatensätze bringen, wo ich nicht weiterkomme.

Ja, ich denke an konkreten Beispielen lässt sich leichter diskutieren und erklären. Vielleicht finden sich dabei auch Anwendungsbeispiele für 4. und 5. (sonst werde ich mir noch welche überlegen)

04.11.2015 21:37

3 Ranma (Gast)

Also meint 2. schon das, was ich vermutete. Nur daß ich nicht ganz so viele Tabellen vermutet hätte. Schließlich können in einem Eintrag sehr viele Zusatzinformationen stecken:

Zypern {n} /CY/ [geogr.]      	Cyprus

Elemente wie /CY/ waren mir beim analysieren der Struktur garnicht aufgefallen. Kommt sehr selten vor. Ich habe diese Einträge vorerst auf nur zwei Spalten aufgeteilt. Die Originaleinträge der Wörterliste sahen nämlich noch etwas komplizierter aus als man vom gezeigten Eintrag her vermutet. Eigentlich hätte ich Synonyme noch aufteilen müssen, die sind zumeist durch ; getrennt:

ein Schuss {m}; eine Portion [Mengenangabe]	      dollop [fig.]

Das Beispiel habe ich auch deshalb ausgewählt, weil die Angaben in den eckigen Klammern auf der englischen und der deutschen Seite nicht übereinstimmen. Meistens stehen sie nur auf einer Seite. So etwas wie hier macht die vorgeschlagene Tabelle schwieriger. Sollte sich die Tabelle auf Kombinationen von Wörtern beziehen, dann sogar unmöglich. Man beachte auch, daß die grammatische Angabe in den geschweiften Klammern (es gibt nirgends eine Erklärung dazu, aber solche Angaben kommen so oft vor, daß ich mir sicher bin, daß es sich hier um eine Genus-Angabe handelt; auch andere grammatische Angaben stehen gerne in geschweiften Klammern) nur auf die erste Variante bezieht und für die andere sogar falsch wäre.

Aufteilen nach ; ist aber schwierig, weil praktisch kein Ersteller einer Wörterliste die nötige Disziplin hat solche Delimiter in eindeutiger Weise zu verwenden:

an {prp; wo? +Dat.; wohin? +Akk.}   	          at; on; by; to {prp}

Ein Beispiel für mehrere Angaben in eckigen Klammern:

an Verfolgungswahn leiden    	  to wear a tinfoil hat [coll.] [fig.]

Oft ist ein Wort in einer anderen Sprache mehrdeutig. Das heißt, daß es für ein Wort mehrere Einträge geben muß, sogar solange noch nicht weiter aufgeteilt wurde:

abblenden {vi} [auto]	                  to dip [Br.] / dim [Am.] one's headlights/lights

abblenden {vt} (Fotografie; Optik)     	to stop out

ausblenden; abblenden {vi} (Film, TV)	to fade out (film, TV)

Undiszipliniert: einmal werden innerhalb der runden Klammern , verwendet, dann wieder ; während die englischen Synonyme durch / getrennt sind, aber die deutschen durch ; Außerdem stehen da tatsächlich die Fachgebiete in der zweiten und dritten Zeile in runden Klammern, statt wie in der ersten Zeile und sonst üblich in eckigen Klammern.

Weil ein Skript kaum mit so einem Durcheinander klarkommen kann, deshalb sind die Einträge noch nicht weiter aufgeteilt. Natürlich kann man es etwas standardisieren, damit habe ich jetzt schon ein bißchen Übung, obwohl ich meistens nur ein Skript verwende, um die Fehler zu finden und sie dann per Hand korrigiere. Das dauert aber immer Stunden.

Wäre es angemessen aus der ersten Zeile des letzten Beispieles vier Zeilen zu machen (jeweils nach / unterteilt)?

Ich sollte eine zusätzliche Tabelle für die Angaben in eckigen Klammern haben, eine weitere für die Angaben in den geschweiften Klammern und falls in runden Klammern noch Angaben zu finden sein sollten, die in solche gehören, dann auch dafür noch eine extra Tabelle?

Wie ich schon erwähnte, ich konnte keinen eindeutigen Index von vorneherein einbauen, weil dann auch doppelte Einträge eindeutig gewesen wären. Infolgedessen wäre dann die Datenbanktabelle vielleicht voll mit doppelten und dreifachen Einträgen, weil solche durch INSERT IGNORE nicht mehr verworfen worden wären. Der Index hätte sie ja scheinbar eindeutig gemacht, obwohl sie keine zusätzlichen Informationen enthalten hätten. Falls MySQL kein Problem mit dem hochzählen eines nachträglich eingefügten Indexes haben sollte, dann wäre da kein Problem.

Einträge für Japanisch habe ich bereits auf drei Tabellen verteilt, weil es mir dabei schnell einsichtig wurde, daß das insgesamt weniger Einträge bedeutet. Das sieht so aus:

1000390 	あっという間に	0
1000390 	あっと言う間に	0
1000390 	あっとゆう間に	0
1000390 	あっというまに	0
1000390 	あっという間に	1
1000390 	あっと言う間に	1
1000390 	あっとゆうまに	0
1000390 	あっと言う間に	1
1000390 	あっとゆう間に	1

1000390 	&exp;

1000390 	eng  	just like that
1000390 	eng         in the twinkling of an eye
1000390 	eng  	in the blink of an eye
1000390 	eng  	in the time it takes to say "ah!"
1000390 	ger   	im Nu
1000390 	ger   	im Handumdrehen
1000390 	ger   	in einem Augenblick
1000390 	ger   	wie mit einem Schlag (etwa: in der Zeit, in der man gerade nur {Transcr.: a} sagt)
1000390 	spa  	tal que así (lit: en lo que se tarda en decir "Ah!")
1000390 	spa  	en un abrir y cerrar de ojos
1000390 	spa  	en un pestañeo

In der linken Spalte ist jeweils die schon in der Originalliste enthaltene Eintragsnummer. Dort war alles in XML-nodes gekapselt. Die untere Tabelle ist am leichtesten zu verstehen. Sie enthält in der mittleren Spalte eine Angabe, in welche Sprache übersetzt wird. In der rechten Spalte steht dann die Übersetzung. HIer zeigt die letzte deutsche und die erste spanische Variante, daß darin zusätzliche Informationen enthalten sein können. Sollten solche in eine eigene Tabelle oder eine eigene Spalte? Oder können sie bleiben wo sie sind? Schließlich ergeben sie einzeln keinen Sinn, außer vielleicht als wiederum eigenständige Übersetzung, denn so wurde das schon in der Originalliste in der englischen Übersetzung (die hier auch aufgeführt ist) gelöst...

Die mittlere Tabelle enthält Anmerkungen, die vielerlei Art sein können. Ich habe sämtliche sinnvolle in eine eigene Tabelle mit nur einer Spalte (außer dem des Original-Eintrag-Indexes) dafür aufgenommen. Sie beginnen alle mit & und enden auf ; so daß man das für besondere HTML-Zeichen halten könnte, aber das ist wohl nur ein Artefakt, das beim Erstellen der Originalliste entstanden ist. Eigentlich sind es englische Abkürzungen, die auch dokumentiert sind. Außerdem ist dokumentiert, daß die Originalliste schon ein paar Mal in der Struktur veränder worden ist, dabei dürfte so manches Artefakt entstanden sein. Ich vermute, daß das auch für andere Listen ein Problem war, obwohl es dort nicht dokumentiert ist.

Die obere Tabelle enthält die japanischen Varianten. Dazu sollte ich etwas erklären. Im Japanischen werden vier Schriftarten nebeneinander und durcheinander verwendet. Aus dem Chinesischen übernommene Schriftzeichen. Denen kann auch der Japaner nicht ansehen, wie er sie aussprechen sollte (der Chinese übrigens auch nicht, schon garnicht, wenn es um die japanische Aussprache geht). Zwei Silbenschriften, die zwar irgendwann mal aus der chinesischen Schrift abgeleitet wurden, aber eigenständig Japanisch sind und die Aussprache eindeutig anzeigen. Schließlich noch lateinische Buchstaben, die aber nur selten verwendet werden. Das hauptsächlich in Abkürzungen, wo man sie dann einigermaßen wie im Englischen (aus dem sowieso die meisten Abkürzungen übernommen werden) ausspricht. Der vierte Eintrag von oben und der dritte Eintrag von unten in der mittleren Spalte der oberen Tabelle bestehen nur aus japanischen Silben. Damit legen sie auch die Aussprache der Einträge in den anderen Zeilen fest!

Die drei Einträge mit dem 言 darin gleichen sich in der mittleren Spalte, desweiteren auch die erste und die fünfte Zeile, sowie die dritte und die letzte Zeile. Obwohl es neun Zeilen sind, enthalten sie also fünf Schreibvarianten. Zwei davon geben die Möglichkeiten der Aussprache an. In den meisten Fällen treffen alle Aussprachemöglichkeiten auf alle Schreibvarianten zu. Dafür ist die rechte Spalte da. In dem Normalfall stehen dort alle Werte auf Null. Im Ausnahmefall stand in der Originalliste ein XML-Node <restr></restr>, der eine Aussprachevariante enthielt, welche nur für die Schreibvarianten im selben übergeordneten XML-Node zutrifft. Dieser übergeordnete ist natürlich nur ein untergeordneter zu <entry></entry>, der noch weitere Schreibvarianten und Aussprachevarianten enthalten kann. Die Begrenzung habe ich versucht, mit dem Wert 1 in der rechten Spalte darzustellen. Ich befürchte allerdings, daß mir das mißglückt ist, weil ich nämlich aus dem gezeigten Beispiel nicht feststellen kann, ob sich beispielsweise die drittletzte Zeile auf die beiden Einträge darüber oder die beiden Einträge darunter bezieht. Auf jeden Fall dürfte es mißglückt sein, die Zeilen hier nicht von ihrer Reihenfolge zueinander abhängig zu machen.

Du brauchst dir keine Beispieldaten zu überlegen. Ich habe nämlich noch jede Menge davon. Hunderttausende Einträge. (Und dabei streikt mein Skript, mit dem ich Chinesisch eintrage...) Da wird auf jeden Fall genug dabei sein, auch für 4. und 5. Nur sollte erstmal die erste Normalform hergestellt werden...
Ranma

05.11.2015 04:16

4 Jörg Kruse

Ich sollte eine zusätzliche Tabelle für die Angaben in eckigen Klammern haben, eine weitere für die Angaben in den geschweiften Klammern und falls in runden Klammern noch Angaben zu finden sein sollten, die in solche gehören, dann auch dafür noch eine extra Tabelle?

Theoretisch könntest du diese Angaben auch in einer Tabelle unterbringen, wobei in einer zusätzlichen Spalte die Art der Angabe definiert wird, z.B. allgemein für eckige und grammatikalisch für geschweifte Klammern:

Index  Wort-ID    Angabenart         Angabe
1       1         allg.              math
2       9         allg.              math
3       9         allg.              med
4      10         allg.              auto
5      10         gramm.             vi

Falls MySQL kein Problem mit dem hochzählen eines nachträglich eingefügten Indexes haben sollte, dann wäre da kein Problem.

Das sollte gehen

Die untere Tabelle ist am leichtesten zu verstehen. Sie enthält in der mittleren Spalte eine Angabe, in welche Sprache übersetzt wird. In der rechten Spalte steht dann die Übersetzung. HIer zeigt die letzte deutsche und die erste spanische Variante, daß darin zusätzliche Informationen enthalten sein können. Sollten solche in eine eigene Tabelle oder eine eigene Spalte? Oder können sie bleiben wo sie sind? Schließlich ergeben sie einzeln keinen Sinn, außer vielleicht als wiederum eigenständige Übersetzung, denn so wurde das schon in der Originalliste in der englischen Übersetzung (die hier auch aufgeführt ist) gelöst...

Ich würde sie in einer eigenen Spalte unterbringen, ggf. mit der Bezeichnung `erklaerung`. Eine separate Tabelle ist wohl nicht angebracht, weil sich die Erklärung direkt auf die Übersetzung des japanischen Wortes bezieht.

Im Ausnahmefall stand in der Originalliste ein XML-Node <restr></restr>, der eine Aussprachevariante enthielt, welche nur für die Schreibvarianten im selben übergeordneten XML-Node zutrifft. Dieser übergeordnete ist natürlich nur ein untergeordneter zu <entry></entry>, der noch weitere Schreibvarianten und Aussprachevarianten enthalten kann.

Das ist etwas schwierig nachzuvollziehen - kannst du mal zum besseren Verständnis einen <entry>-Knoten hier posten?

05.11.2015 18:23

5 Ranma (Gast)

Folgendes ist der Originaleintrag zum Beispiel aus meinen Japanisch-Tabellen.

<entry>
<ent_seq>1000390</ent_seq>
<k_ele>
<keb>あっという間に</keb>
</k_ele>
<k_ele>
<keb>あっと言う間に</keb>
</k_ele>
<k_ele>
<keb>あっとゆう間に</keb>
</k_ele>
<r_ele>
<reb>あっというまに</reb>
<re_restr>あっという間に</re_restr>
<re_restr>あっと言う間に</re_restr>
</r_ele>
<r_ele>
<reb>あっとゆうまに</reb>
<re_restr>あっと言う間に</re_restr>
<re_restr>あっとゆう間に</re_restr>
</r_ele>
<sense>
<pos>&exp;</pos>
<gloss>just like that</gloss>
<gloss>in the twinkling of an eye</gloss>
<gloss>in the blink of an eye</gloss>
<gloss>in the time it takes to say "ah!"</gloss>
<gloss xml:lang="ger">im Nu</gloss>
<gloss xml:lang="ger">im Handumdrehen</gloss>
<gloss xml:lang="ger">in einem Augenblick</gloss>
<gloss xml:lang="ger">wie mit einem Schlag (etwa: in der Zeit, in der man gerade nur {Transcr.: a} sagt)</gloss>
<gloss xml:lang="spa">tal que así (lit: en lo que se tarda en decir "Ah!")</gloss>
<gloss xml:lang="spa">en un abrir y cerrar de ojos</gloss>
<gloss xml:lang="spa">en un pestañeo</gloss>
</sense>
</entry>

Die Aussprachezeilen beziehen sich also auf die Einträge, die darauf folgen. Dafür ist mir jetzt schleierhaft, wozu die ersten drei Einträge mit japanischem Text dienen sollen. Wahrscheinlich wurde die Datei auch nicht überlegter erstellt als meine Datenbanktabellen.

Die einzelnen Elemente enthalten außer dem <entry>node nicht immer die gleichen nodes. Darum noch den direkt nachfolgenden als weiteres Beispiel.

<entry>
<ent_seq>1000400</ent_seq>
<r_ele>
<reb>あっぷあっぷ</reb>
</r_ele>
<sense>
<pos>&adv;</pos>
<pos>&n;</pos>
<pos>&vs;</pos>
<gloss>floundering while nearly drowning</gloss>
<gloss xml:lang="ger">(1) ertrinkend</gloss>
<gloss xml:lang="ger">nach Luft schnappend</gloss>
<gloss xml:lang="ger">(2) bis zum Hals in Schwierigkeiten steckend</gloss>
<gloss xml:lang="ger">(1) nach Luft schnappen</gloss>
<gloss xml:lang="ger">am Ertrinken sein</gloss>
<gloss xml:lang="ger">(2) in großen Schwierigkeiten stecken</gloss>
<gloss xml:lang="spa">estar a punto de ahogarse</gloss>
</sense>
<sense>
<gloss>suffering</gloss>
</sense>
</entry>

Nach dem Skript zum Auswerten werde ich sicherlich gleich als nächstes gefragt. In einer WHILE-Schleife kam Zeile um Zeile in ein Array, welches bei </entry> immer geleert wurde, damit der Speicher nicht überlief. Folgendes ist der Hauptteil für die Auswertung, dann kam natürlich noch das Senden an die Datenbank dazu.

if(substr_count($Subentry,'<ent_seq')>0): // Das ist nur einmal pro Eintrag möglich.
        $Nummer=(int)strip_tags($Subentry);
// Nur einmal pro Eintrag wahrscheinlich:
elseif(substr_count($Subentry,'<field')>0):
        $Tech[]=strip_tags($Subentry);
elseif(substr_count($Subentry,'<pos')>0):
        $Grammat[]=strip_tags($Subentry);
        // Eintrag 1000400 hatte ich natürlich da noch nicht gesehen...
elseif(substr_count($Subentry,'<misc')>0):
        $Anderes[]=strip_tags($Subentry);
elseif(substr_count($Subentry,'<lsource')>0):
        if(substr_count($Subentry,'xml:lang=')>0):
              $Ursprung[]=substr($Subentry,strpos($Subentry,'"')+1,3);
        else:
              $Ursprung[]='eng';
        endif;
        $Ursprung[]=strip_tags($Subentry);
// Üblicherweise mehrere pro Eintrag:
elseif(substr_count($Subentry,'<gloss')>0):
        if(substr_count($Subentry,'xml:lang=')>0):
              $Sprache[]=substr($Subentry,strpos($Subentry,'"')+1,3);
        else:
              $Sprache[]='eng';
        endif;
        $Begriff[]=strip_tags($Subentry);
        // $Begriff und $Sprache enthalten immer gleich viele Elemente.
elseif(substr_count($Subentry,'<keb')>0 or substr_count($Subentry,'<reb')>0):
        $Japanisch[]=strip_tags($Subentry);
elseif(substr_count($Subentry,'re_restr>')>0):
        $Japanisch[]='Restr.! : '.strip_tags($Subentry);
        // Das sind zwei Informationen in einem Array-Element. Wird später aufgelöst.
        // Aber so bekomme ich die Information später an die richtige Stelle in einer
        // FOREACH-Schleife.
else:; // Angaben aus welchem Korpus Wörter in die Liste kamen sind uninteressant...
endif;
$Alles=array_merge($Tech,$Grammat,$Anderes,$Ursprung);

Ich sehe jetzt erst, daß ich aus dem Eintrag von 1000400 nur einen von drei <pos>-Informationen gezogen habe, weil in den meisten Einträgen das nur einmal vorkommt. Es soll, so glaube ich, die möglichen Positionen im japanischen Satz bezeichnen. Dafür dürfte es sich nicht lohnen, das Skript nochmal zu verbessern und nochmal laufen zu lassen. Falls das mit der Information zur Restriktion nicht hingehauen hat, dann muß es schon sein. Hauptsächlich ist mir da nicht klar, wie die Zusammengehörigkeit ohne Berücksichtigung der Reihenfolge in die Tabelle aufgenommen werden kann. In der XML-Datei folgen sie zu dem Zweck innerhalb eines Nodes aufeinander, auch wenn sie wiederum eigene untergeordnete Nodes haben.

Im zweiten Beispiel hier scheint eine Bedeutung nachträglich eingetragen worden zu sein. Meine Auswertung erwischt diese trotz des extra Nodes. Listen in normalen Textadateien sind einfacher auszuwerten.
Ranma

06.11.2015 03:28

6 Jörg Kruse

Für mich ist es etwas schwierig, ohne Kenntnisse des Japanischen diese Struktur nachzuvollziehen :) - eine Erklärung zu diesem Wörterbuch habe ich noch auf dieser Seite gefunden:

http://www.edrdg.org/jmdict/jmdictart.html

Zu einem entry kann es, wie dein erstes Beispiel zeigt, mehrere kanji und mehrere kana Wörter geben, zu einem kana Wort mehrere Restriktionen. Wenn man diese XML-Struktur sauber in einer Datenbankstruktur abbilden möchte, benötigt man von daher wohl drei Tabellen:

Tabelle kanji_words:

kanji_id   entry_id    kanji_word
555        1000390     あっという間に
556        1000390     あっと言う間に
557        1000390     あっとゆう間に

Tabelle kana_words:

kana_id    entry_id    kana_word
1111       1000390     あっというまに
1112       1000390     あっとゆうまに

Tabelle restrictions:

restriction_id   kana_id   kanji_id
3333             1111      556
3334             1111      557
3335             1112      556
3336             1112      557

06.11.2015 17:10 | geändert: 06.11.2015 17:19

7 Ranma (Gast)

Also, ich glaube, die vierte Regel ( == zweite Normalform) verlangt, daß der Primärschlüssel einer Tabelle aus nur einer Spalte bestehen soll. MySQL erlaubt Schlüssel aus mehreren Spalten, in meinen Tabellen für das Wörterbuch bestehen sie oft aus der Kombination der Spalten für Wörter anderer Sprachen und für deren deutsche Übersetzung.

Demnach und vielleicht sogar schon wegen der zweiten Regel sollten die Wörter eigentlich in eigenen Tabellen (also eine pro Sprache, nicht pro Paar) untergebracht sein und nur deren Index-Nummern in einer weiteren Tabelle miteinander kombiniert???

Meinem bisherigem Verständnis nach, dient die Normalisierung dazu, den Verbrauch von Ressourcen (vor allem Zeit beim Zugriff) bei der Verwendung von Datenbanken zu minimieren. Demnach gibt es vor allem zwei einleuchtende Prinzipien dabei. Das eine ist die Vermeidung redundanter Informationen (da muß ich vielleicht noch ein paar entfernen) und das andere ist die Vermeidung leerer Datenfelder. In diesem Sinn weitergedacht, was ist sinnvoller: viele Tabellen mit wenigen Einträgen oder wenige Tabellen mit sehr vielen Einträgen? Also konkret: tut sich eine Abfrage leichter über mehrere Tabellen, die jeweils Wörter einer Sprache enthalten, oder über eine Tabelle, die mit einer weiteren Spalte anzeigt, um welche Sprache es sich jeweils handelt? Für mich hätte die letztere Variante auf jeden Fall den Vorteil, daß ich keine zusätzlichen Tabellen anlegen muß, wenn ich es ermögliche, Wörter weiterer Sprachen durch ein Formular einzugeben...
Ranma

13.11.2015 04:15

8 Jörg Kruse

Also, ich glaube, die vierte Regel ( == zweite Normalform) verlangt, daß der Primärschlüssel einer Tabelle aus nur einer Spalte bestehen soll.

Der Primärschlüssel kann durchaus zusammengesetzt sein, aber dann sollten Datenfelder, die sich auf nur einen Teil des Primärschlüssels beziehen, in eine eigene Tabelle ausgelagert werden.

Demnach und vielleicht sogar schon wegen der zweiten Regel sollten die Wörter eigentlich in eigenen Tabellen (also eine pro Sprache, nicht pro Paar) untergebracht sein und nur deren Index-Nummern in einer weiteren Tabelle miteinander kombiniert???

Ja, wobei die Tabelle z.B. `uebersetzungen` heißen könnte

Meinem bisherigem Verständnis nach, dient die Normalisierung dazu, den Verbrauch von Ressourcen (vor allem Zeit beim Zugriff) bei der Verwendung von Datenbanken zu minimieren.

Eher im Gegenteil - man vermeidet dadurch aber Inkonsistenzen. Wenn z.B. in einer Büchertabelle immer auch der Name des Autoren eingetragen wird, dann kann es leicht mal passieren, dass er unterschiedlich geschrieben wird. Bei einer Suche nach allen Büchern eines Autoren werden dann womöglich nicht alle gefunden. Wenn die Autoren in eine eigene Tabelle ausgelagert werden, dann ist der Name immer eindeutig, weil er nur einmal eingegeben wurde.

Aus Performance-Gründen kann es sogar mal angezeigt sein, an einer bestimmten Stellen eine Tabellen zu denormalisieren. Dann muss man sich allerdings in der betreffenden Applikation um die Konsistenz kümmern.

13.11.2015 16:33 | geändert: 13.11.2015 16:35

9 Ranma (Gast)


Der Primärschlüssel kann durchaus zusammengesetzt sein, aber dann sollten Datenfelder, die sich auf nur einen Teil des Primärschlüssels beziehen, in eine eigene Tabelle ausgelagert werden.

Aber das heißt schon falls der Primärschlüssel aus nur einer Spalte besteht, dann ist die Regel automatisch immer erfüllt?

In den Dateien, aus denen ich die Wörterlisten hole, gibt es viele geöffnet bleibende Klammern, mal eckige statt runde Klammern oder umgekehrt, Verwendung von Delimitern zusätzlich als Satzzeichen. Letztere finde ich ganz besonders ärgerlich. Die anderen genannten Fehler sind auch nervig. Das sind wohl Beispiele für Inkonsistenzen. Ich muß erst Stunden aufwenden, um die Muster in den Fehlern anderer zu finden. Korrigieren lassen sie sich sowieso nur, falls sie einem Muster folgen. Eine solche schlechte Verarbeitkarkeit möchte ich für meine Datenbanktabellen natürlich nicht. Dann dürfte ich jetzt wohl den Sinn der Normalisierung begriffen haben...
Ranma

14.11.2015 04:03

10 Ranma (Gast)

Außerdem:

http://www.php-faq.de/q-mysql-eignung.html

Das spricht wohl ganz klar für eher weniger und dafür viel größeren Tabellen.
Ranma

14.11.2015 04:16