Michael Schröpl: Status(gelesen?) von messages an mehrere user speichern

Beitrag lesen

Hi Andreas,

Tabelle: "pm"
+----+-----+----+---------+---------+--------+------+
| ID | von | an | subject | message | status | time |
+----+-----+----+---------+---------+--------+------+
| 1  |...  |... |...      |...      |...     |...   |
+----+-----+----+---------+---------+--------+------+
| 2  |...  |... |...      |...      |...     |...   |
+----+-----+----+---------+---------+--------+------+

Aha. _Eine_ Tabelle.
Das ist ja nun nicht wirklich das, was man unter einer Datenbank
versteht, aber für eine stikte 1:1-Relation könnte es noch taugen.

So, das klappt prima bei den messages, die ich von einem User zu
einem anderen schicke

Sehnsewohl. ;-)

So weit so gut. Nur würde ich auch gerne vom Admin aus messages
an ALLE user senden

Na also - da ist sie ja, die 1:n-Beziehung, die sich mit der einen
Tabelle nicht mehr ausdrücken läßt. Fein ... :-)

aber wenn ich sowas einfach in der Tabelle ablege, sieht zwar der
erste, dass er eine neue Nachricht hat, aber sobald der sie liest
wird sie als "gelesen" markiert

Das darf sie nicht. Denn dieses Feld "gehört" ja nicht diesem Leser,
sondern eigentlich allen.
Genau das ist das Problem: Das verkraftet Dein Datenmodell nicht.

Auch wenn ich das anders abfrage, dass die Nachricht z.B. nicht
als "gelesen" markiert wird, habe ich auf der anderen Seite das
Problem, dass die Nachricht bei jedem für immer als "neu" stehen
bleibt. Das kann man auch mit der einen Tabelle nicht umgehen.

Richtig. Deine Tabelle kann für _eine_ Nachricht bisher nur einen von
zwei Statuswerten darstellen: "gelesen" und "nicht gelesen".
So schwarz-weiß ist Deine Welt aber inzwischen nicht mehr - Du brauchst
jetzt "Grautöne".

Hat das Sinn für jeden neuen User immer eine eigene Tabelle zu
erstellen?

Um Himmelswillen, nein!

Ich wieß dass man das so pauschal nicht unbedingtr sagen kann,

Doch, das kann man in diesem Fall ganz bestimmt.
Es darf nicht notwendig sein, Dein Programm anzupassen, nur weil ein
neuer Benutzer dazu kommt.

kann man denn hier allgemein zu einer Vorgehensweise raten?

Ja.

Also die Usrdaten sind auch nicht sehr umfangreich, ca. 15 Spalten.
Auch das Datenvolumen wird in absehbarer Zeit sehr überschaubar
bleiben, ausgehend von 1.000-10.000 Auktionen pro Jahr, mit im
Schnitt 10 Bietern.

Das wäre noch nicht mal entscheidend. Die richtige Vorgehensweise ist
in diesem Falle nicht wirklich vom Datenvolumen abhängig.
Ein einziger Artikel, auf den dann doch tausend Leute bieten wollen,
darf Dir nicht weh tun - damit muß Dein Modell locker fertig werden.

Was würdet Ihe empfehlen?

Eine saubere relationale Zerlegung.

Du verwendest doch eine relationale Datenbank, weil Du Relationen, also
Beziehungen darstellen willst.
Dazu mußt Du allerdings die Objekte herausarbeiten, zwischen denen die
Beziehungen existieren - und die Art der Beziehung herausfinden.

Einerseits hast Du eine Beziehung zwischen den Nachrichten und ihren
Attributen. Das ist die naheliegende 1:1-Beziehung, die Du bereits
modellierst hast: Jede Nachricht hat jedes Attribut einmal.
Das "Objekt" ist in diesem Falle die Nachricht, repräsentiert durch
ihre ID; die übrigen Spalten Deiner Tabelle sind dessen Eigenschaften.

Dieses Objekt hat Deiner Meinung nach noch ein weiteres Attribut, nämlich
seinen "Lesestatus".
Dieser ist nun aber gerade _keine_ 1:1-Beziehung mehr, sondern eine 1:n-
Beziehung zwischen einem Sender und n Lesern! Die Nachricht ist hier gar
nicht mehr das Objekt selbst.
Zur Repräsentation brauchst Du also ein n-Tupel aus lauter einzelnen
Schaltern, die auf "gelesen" oder "ungelesen" stehen können.
Deine Tabelle hat aber nur Platz für einen Schalter.
Und pro Nachricht sind es auch noch unterschiedlich viele - eine Tabelle
mit beliebig, aber konstant vielen Spalten löst Dein Problem nicht (es
verschlimmert die Lage nur, auch wenn ich schon öfters solche "Lösungen"
als reale Implementierung gesehen habe - weia), genauso wie eine Tabelle
pro Benutzer es nicht löst.

Bisher hast Du nur Zeilen in Deiner Tabelle, welche durch _eine_ Spalte
eindeutig beschrieben werden. Diese Eigenschaft nennt man "Primärschlüssel
der Tabelle". Technisch gesehen kann jede Tabelle nur einen einzigen sol-
chen Primärschlüssel besitzen; inhaltlich kann es durchaus vorkommen, daß
sich mehrere Spalten dafür eignen würden.
Deine zweite Tabelle wird einen Primärschlüssel haben, der aus _zwei_
Spalten bestehen wird, nämlich der _Kombination_ aus ID und Leser. Das
erlaubt Dir, 1:n-Beziehungen darzustellen. (Und sogar m:n-Beziehungen.)
Genau damit kannst Du in dieser neuen Tabelle sämtliche Lesezustände
darstellen (und sonst nichts!) - der Schalter ist dann die dritte Spalte
dieser Tabelle. Nun hat jeder Leser einer Nachricht seine eigene Zeile
für diese Nachricht in dieser Tabelle - keiner überschreibt mehr etwas
Fremdes. Die einzelnen Benutzer-Tabellen, die Du anlegen wolltest, haben
wir nun in eine einzige Tabelle "gefaltet".

Sicherlich willst Du irgendwann den "allgemeinen Lesezustand" einer Nach-
richt herausfinden - eine typische Fragestellung wäre "gibt es noch jeman-
den, der die Nachricht nicht gelesen hat?".
Dazu wirst Du die Nachricht über die erste Tabelle adressieren - vielleicht
mußt Du ihre ID ja erst finden - und dann über diese ID als gemeinsamem
Spaltenwert aus der zweiten Tabelle alle zugehörigen Lesezustände holen
und prüfen.
Diese Verknüpfung zwischen den beiden Tabellen nennt man in SQL einen
"JOIN", und das wird für den Rest Deines SQL-Lebens Dein ständiger Be-
gleiter werden.
Überlege Dir mal, wie Du diese Aufgabe mit vielen einzelnen Benutzer-
Tabellen hättest lösen wollen! Du hättest zuerst mal den Namen der Tabelle
berechnen müssen, um die SQL-Abfrage auf diese Tabelle erzeugen zu können.
Mit einer einzigen großen Tabelle sieht diese SQL-Abfrage immer gleich aus

  • der Benutzername taucht einfach in der WHERE-Klausel auf, um die Lese-
    schaltermenge dieses Benutzers aus der Gesamtmenge herauszufiltern.

In der Datenbanktheorie gibt es übrigens Verfahren, wie man eine solche
Zerlegung zwingend herleiten oder doch mindestens den entsprechenden
Bedarf zuverlässig feststellen kann - das nennt sich dann "Normalformen".
Ein solcher Entwurf ist nämlich bei zwei Tabellen noch problemlos durch
Hinsehen möglich - aber stell Dir mal vor, Du hast hundert Tabellen, oder
tausend, oder ...

Noch etwas solltest Du aus diesem Fall mitnehmen: Bei relationalen Daten-
banken ist eine korrekte Datenmodellierung unbezahlbar - die SQL-Abfragen
schreiben sich anschließend beinahe von selbst.
Ein mißlungener Entwurf dagegen ist oftmals nicht nur umständlicher zu
behandeln, sondern fehleranfälliger, inperformanter (hier kann es leicht
um mehrere Zehnerpotenzen gehen) und mit viel mehr Pflegeaufwand der
eigenen Software verbunden. Einen Fehler in dieser Phase zu übersehen
kann den gesamten Software-Entwurf zum Scheitern verurteilen - das ist
in SQL viel schlimmer als bei Drittgenerations-Sprachen.

Viele Grüße
      Michael