ER Diagramm: Zwischentabelle mit nicht eindeutiger Nummer

erdiagram

#1

Erstmal: Wir habn drei Datenbankkategorien: Datenbanksysteme>Allgemeines (22x) Datenbanksysteme>Programmierung (24x) und Java-Forum>Datenbankprogrammierung (118x), ich hab jetzt nur die Nichtunterkategorie “Datenbanksysteme” gewählt.

Jetzt zur Frage: Möchte einen Vorkabeltrainer schreiben, kleines Projekt, bei dem:
Es gibt Benutzer, ein Benutzer kann mehrere Sätze habn.
Ein Satz kann mehrere Vokabeln habn.
Eine Vokabel kann in mehreren Trainings stehen.
Ein Training kann mehrere Vokabeln habn.

Das ER Diagramm:

( generiert mit: Link )

Eine Trainingszusammenfassung soll so werden:

Trainingsnummer: 123
(am: 19.11.17)
Anzahl Vokabeln: 15
Tabelle mit: Vokabelbeschreibung, VokabelA, VokabelB, Anzahl Richtig, Anzahl Falsch
… … … … … (15x)

Frage: In welche Tabelle kommt TrainingNr? Wenn es die Trainingsnummer: 123 gibt, wie wähle ich die nächste Trainingsnummer 124 (nicht unique, deswegen nicht auto increment)?

Danke für eure Antworten


#2

Gibt es denn nicht eine TrainingSession, in der 123 und 124 eigentlich Primärschlüssel sein sollten?


#3

Ich bekomme gerade einen ganz komischen Irrtum:

Error: Invalid Instance definition. Only one autoincrement field allowed.

Innerhalb von Training:

    Nummer: {
        type: Sequelize.INTEGER,
        allowNull: false,
        defaultValue: 1,
        autoIncrement: true
    },

Verknüpfungen außerhalb von Training:

User.hasMany(Satz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Satz.hasMany(Vokabel, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Vokabel.hasMany(Training, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Satz.belongsTo(User, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Vokabel.belongsTo(Satz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });

Hilfe: https://github.com/sequelize/sequelize/issues/2999 :

If you want a field that is AI but not the PK you need to define your own PK using a UUID type.


Das hab ich nicht genau verstanden. Es kann sein dass das ER bezüglich “Zwischen” und “Training” falsch ist

Danke für deine Antwort!


#4

Falsch ist so ein hartes Wort… :grin:

Ich jedenfalls hätte dort eine Dreiecksbeziehung:

Benutzer(BenuzerId) - Training(BenutzerId,TrainingId)
                          |
Vokabel(VokabelId) - VokabelTraining(TrainingId,VokabelId,TrainigResult['Richtig'|'Falsch])

Die Vokabeln würde ich nicht explizit Benutzern zuordnen, sonst muss man die ja für jeden Benutzer neu eingeben. Man könnte aber jedem Benutzer einen Wortschatz zuordnen in dem sich dann eine Auswahl von Vokabeln befindet.

bye
TT


#5

:blush:


Danke erst mal für den Tipp!
Das mit der Dreiecksbeziehung in etwa so:

const Training = sequelize.define('Training', {
    id: {
        type: Sequelize.INTEGER,
        primaryKey: true
    },
    Nummer: {
        type: Sequelize.INTEGER,
        allowNull: false,
        defaultValue: 1,
        autoIncrement: true
    },
    Beschreibung: {
        type: Sequelize.STRING,
        allowNull: false,
        defaultValue: 'unbekanntes Training'
    }
});
const VTraining = sequelize.define('VTraining', {
    Richtige: { // eine id (PK) wird über die Assoziation un implizit hinzugefügt
        type: Sequelize.INTEGER,
        allowNull: false,
        defaultValue: 1
    },
    Falsche: {
        type: Sequelize.INTEGER,
        allowNull: false,
        defaultValue: 1
    }
});
User.hasMany(Satz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Satz.hasMany(Vokabel, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
User.hasMany(Training, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Training.hasMany(VTraining, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Vokabel.hasMany(VTraining, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Satz.belongsTo(User, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Vokabel.belongsTo(Satz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Training.belongsTo(User, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
VTraining.belongsTo(Training, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
VTraining.belongsTo(Vokabel, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });

Läuft auch. :slight_smile:

Edit, ein Benutzer hat immer eigene Vokabeln die er eintippt. — Vokabeln möchte ich nicht “vorgeben”.


#6

Aber vielleicht “sammeln” und dann allen zur Verfügung stellen?

bye
TT


#7

Wie ginge das? Ein Satz hat mehrere Vokabeln und ein Benutzer soll dann mehrere Sätze mit Vokabeln habn dürfen.

Eine “Zwischentabelle” BenutzerSatz?

Edit, das mit dem AI in zwei Spalten geht doch nicht! Dann ist die Frage, wie man an die nächsthöhere gelangt?

Die Assoziationen sind jetzt

User.hasMany(UserSatz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Satz.hasMany(UserSatz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Satz.hasMany(Vokabel, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
User.hasMany(Training, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Training.hasMany(VTraining, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Vokabel.hasMany(VTraining, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });

UserSatz.belongsTo(User, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
UserSatz.belongsTo(Satz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Vokabel.belongsTo(Satz, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
Training.belongsTo(User, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
VTraining.belongsTo(Training, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });
VTraining.belongsTo(Vokabel, { foreignKey: { allowNull: false }, onDelete: 'CASCADE' });

(nicht zu lange nachdenken, der zweite Teil ist der gespiegelte erste Teil, beide bedeuten qua dasselbe)

Eine Zusammenfassung so

                                        UserSatz.findOne({ where: { UserId: uid }, include: { model: Satz } }).then(us => {
                                            Vokabel.findAll({ where: { SatzId: us.Satz.id }, include: { model: VTraining } }).then(vs => {
                                                console.log('Find successfully.');
                                                vs.forEach(v => {
                                                    var ri = 0;
                                                    var fa = 0;
                                                    v.VTrainings.forEach(vt => {
                                                        ri += vt.Richtige;
                                                        fa += vt.Falsche;
                                                    });
                                                    console.log("ERGEBNIS:", v.VA, v.VB, ri, fa, ri / (ri + fa));
                                                });
                                            });
                                        }).catch(err => {
                                            console.error('Find error:', err);
                                        });

Wenn zB eingefügt wurde

                                    VTraining.bulkCreate([{
                                        TrainingId: t.id,
                                        VokabelId: vs[0].id,
                                        Richtige: 2,
                                        Falsche: 2
                                    }, {
                                        TrainingId: t.id,
                                        VokabelId: vs[2].id,
                                        Richtige: 1,
                                        Falsche: 4
                                    }, {
                                        TrainingId: t.id,
                                        VokabelId: vs[2].id,
                                        Richtige: 2,
                                        Falsche: 4
                                    }, {
                                        TrainingId: t.id,
                                        VokabelId: vs[2].id,
                                        Richtige: 3,
                                        Falsche: 4
                                    }]).then(vts => {

dann ist Ausgabe

ERGEBNIS: hallo1 hello2 2 2 0.5
ERGEBNIS: wie geht es dir3 how are you4 0 0 NaN
ERGEBNIS: wetter5 weather6 6 12 0.3333333333333333
ERGEBNIS: Tschüß7 Bye8 0 0 NaN

(Nummern hinter VA und VB eingefügt, aber nicht von belang)
Dh, Vokabel 0 wurde einmal trainiert mir 2x richtig und 2x falsch === 0.5 richtig; Vokabel 2 wurde 3mal trainiert mit 6x richtig und 12x falsch === 0.333 richtig.


#8

Hab noch ein ER erstellt. (Die Spalten würdn verwirren)

User hat keinen FK.
VTraining fasst Vokabels und Trainings zusammen.
Jeder Satz hat sozusagen einen Owner.
Die Zwischentabelle UserSatzs benutze ich gar nicht…

Wäre das ER so richtig?