Status(gelesen?) von messages an mehrere user speichern
Andreas
- datenbank
Hallo!
Hätte da nochmal ein konzeptionelles Problem:
Ich hab das jetzt wunderbar(naja, für netscape noch nicht wirklich gut) mit private messanges geschafft, und zwar speichere ich die immer in der DB wie folgt:
Tabelle: "pm"
+----+-----+----+---------+---------+--------+------+
| ID | von | an | subject | message | status | time |
+----+-----+----+---------+---------+--------+------+
| 1 |... |... |... |... |... |... |
+----+-----+----+---------+---------+--------+------+
| 2 |... |... |... |... |... |... |
+----+-----+----+---------+---------+--------+------+
So, das klappt prima bei den messages, die ich von einem User zu einem anderen schicke, im status schreibe ich standardmäßig "neu", und prüfe dann bei jedem user immer, ob es neue Datensätze für Ihn gibt. Nach dem lesen setze ich status = "gelesen".
So weit so gut. Nur würde ich auch gerne vom Admin aus messages an ALLE user senden, 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 und alle anderen haben bemerken das nicht mehr. 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.
Hat das Sinn für jeden neuen User immer eine eigene Tabelle zu erstellen? Wird dann nur irgendwann sehr unübersichtlich befürchte ich! Ich wieß dass man das so pauschal nicht unbedingtr sagen kann, da Ihr ja auch den Rest nicht so kennt, kann man denn hier allgemein zu einer Vorgehensweise raten? 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.
Nur die Komunikation muß funktionieren!
Was würdet Ihe empfehlen?
Grüsse
Andreas
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
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
Hallo!
Vielen, vielen Dank für Deine ausführliche Antwort! Hat mir sehr geholfen und werde versuchen dass so gut wie möglich auf die gesamte DB anzuwenden!
Also werde ich in meine Db eine neue Tabelle einfügen mit drei Spalten, message_ID, leser_ID und status.
Wenn ich das so mache kann ich ja auch hervorragend vorher auswählen, z.B. an ausgewählte Leser schicken, und dann werden halt hier die entsprechenden Einträge gemacht, auch die Auswertung auf der anderen Seite, wirklich super!!!
Und im Prinzip ist das ja schon eine m*n Beziehung, da es ja nicht nur mehrere Leser gibt, sondern auch mehrere Messages, nur wird meist eine Message an mehrer User geschickt.
Nur eine kurze Frage, muß ich in mysql dann die beiden Spalten als Primärschlüssel deklarieren? Was ich noch nicht ganz verstehe, was mir der Primärschlüssel _praktisch_ bringt, für die Theorie und die Entwicklung der Datenbank sicher sinnvoll, aber in der Praxis, z.B. bei JOINS suche ich mir doch eh die Spalten aus, über die die Tabellen "verbunden" werden sollen, jedenfalls soweit ich das weiß! Und bei einzelnen Tabellen-Abfragen ist das eh irrelevant.
Warum macht man das denn dann in der Praxis?
Vielen Dank nochmal!
mfg
Andreas
Hallo Andreas,
Ich hab das jetzt wunderbar(naja, für netscape noch nicht wirklich gut) mit private messanges geschafft
Netscape spielt hier nun wirklich keine Rolle, da es sich nicht um browserspezifische Anforderungen handelt.
Der ausfuehrlichen Darstellung von Michael ist nichts mehr hinzuzufuegen. Er hat alles wie immer sehr treffend und genau beschrieben.
Tabelle: "pm"
+----+-----+----+---------+---------+--------+------+
| ID | von | an | subject | message | status | time |
+----+-----+----+---------+---------+--------+------+
| 1 |... |... |... |... |... |... |
+----+-----+----+---------+---------+--------+------+
| 2 |... |... |... |... |... |... |
+----+-----+----+---------+---------+--------+------+
Als Nachtrag vielleicht nur ein Trivialbeispiel fuer Deine Nachrichten.
Tabelle 1:
Message-Nummer
Subject
Body
Sendedatum
Anzahl User
Absender
usw. (spezielle Kategorisierung)
Tabelle 2:
Message-Nummer
Empfaemger
Status
Lesedatum
Der Bezug wird immer ueber die Message-Nummer hergestellt, weitere Verknuepfungen koenntest Du ueber die sonstigen Kategorisierungen herstellen.
Gruesse
Wilhelm
Hallo!
Netscape spielt hier nun wirklich keine Rolle, da es sich nicht um browserspezifische Anforderungen handelt.
Ja, das selbst nicht, war auf einen alten Thread von mir bezogen, da wo ich nach Lösungen für ein möglichst aktuelles messaging-Fenster gesucht habe, im IE kein Problem, aber im NN hebe ich nur unbefriedeigende Lösungen gefunden, da sich jedesmal der Frame kpl. neu aufbaut, was IMHO sehr nervig ist, im IE bekommt man das nicht mit!
Tabelle 1:
Message-Nummer
Subject
Body
Sendedatum
Anzahl User
Absender
usw. (spezielle Kategorisierung)
Wozu denn Anzahl der User? Könnte ich doch ggfs auch aus Tabelle 2 abfragen?!
Tabelle 2:
Message-Nummer
Empfaemger
Status
Lesedatum
Was würdet Ihr mir raten, wie ich ein Datum am besten in mySQL(mit php) abspeichere? Also ich kenne da genug Varianten, aber irgendwie finde ich das alles nicht richtig optimal. Zum einen der Timestamp, den kann ich ohne Probleme in php auslesen, nur wird der bei jeder Änderung geändert, so dass das z.B. für Absendedatum nicht in Frage kommt. Jetzt gibt es ja die Varienten DATE, DATETIME, und TIME. Gibt es hier eine Möglichkeit, z.B. automatisch in einem der Felder die aktuelle Zeit als Voreinstellung einzustellen, wenn ein neuer Datensatz angelegt wird? Soweit ich weiß kann man in PHP einfach now() bei inserts scheiben, mich interessiert nur, ob man sowas wie einen Timestamp nützen kann, der sich aber hinterher nicht mehr verändert, ohne das man das mit einträgt.
Oder wie ist das überhaupt mit den formatierten Zeit-Feldern, was bringen die denn für Vorteile, als wenn man einfach ein varchar Feld nimmt, und die Zeit so aus php einträgt?
Und die letzte Frage, was nehme ich da am besten(wie formatiert), wenn ich den Zeitpunkt in der Tabelle in php zur Berechnung einer Zeitdifferenz oder ähnliches verwenden will, z.B. mit date()?
Grüsse
Andreas