Zum Inhalt springen

[SQL - MySQL] Distinct


David301

Empfohlene Beiträge

Ich habe folgende kleine abfrage:

SELECT DISTINCT P.threadid, P.userid, P.timestamp, T.headline

FROM forum_threads T, forum_posts P

WHERE T.forenid =1

AND T.threadid = P.threadid ;

Diese Abfrage wird auf einem MySQL-Server ausgeführt. Mein Problem ist, dass das DISTINCT nicht mehr funktioniert, sobald ich die Spalte P.timestamp dazu nehme. Dann bekomme ich auch doppelte threadids ausgegeben.

Kann es daran liegen, dass timestamp nicht NOT NULL ist? Das kann ich aber auch nicht ändern. Oder liegt es am Format? Habe das Format Timestamp gewählt. Hab vorher immer mit Oracle gearbeitet und da habe ich für Datum/Zeit-Angaben immer DATE benutzt. Aber DATE scheint ja unter MySQL keine Zeit zu enthalten.

Das Ziel ist jedenfalls, die forum_posts auf die forum_threads zu joinen aber nur den ersten Treffer aus forum_posts zu erhalten. Wenn jemand eine Idee hat, wie man das anders umsetzt, ist das auch ok.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ungetestet:


SELECT DISTINCT P.threadid, P.userid, P.timestamp, T.headline

FROM forum_threads T, forum_posts P

WHERE T.forenid =1

AND T.threadid = P.threadid GROUP BY P.threadid, P.userid

Darf man Fragen, welche Darstellung Dein Ziel ist?

Weil Threads ohne Einträge werden ja dann gar nicht angezeigt...

Link zu diesem Kommentar
Auf anderen Seiten teilen

Diese Abfrage wird auf einem MySQL-Server ausgeführt. Mein Problem ist, dass das DISTINCT nicht mehr funktioniert, sobald ich die Spalte P.timestamp dazu nehme. Dann bekomme ich auch doppelte threadids ausgegeben.

Das liegt daran, dass der Timestamp die Zeit bis zu einer Genauigkeit von 1 tausendstel Sekunde enthält. Wenn du jetzt 1 eintrag in jede Tabelle direkt hintereinander machst, stimmt zumindest dieser Bruchteil einer Sekunde ziemlich sicher nicht überein. Mit Distinct filterst du nur die Ergebnisse, die in alle gewählten Spalten gleich sind.

Der Aufbau deiner DB ist mir nicht ganz klar. Du hast eine eigene Tabelle, in der du Threads speicherst, aber die eigentliche Information zu einem Thread kommt ja doch aus dem Beitrag... irgendeinem Beitrag(?). Wieso gibst du deinem Thread nicht noch die Felder Überschrift, erstellt (timestamp) und userid? Dann hätte jeder Thread genau 1 Überschrift, 1 Ersteller und 1 Zeitpunkt, wann er erstellt wurde. Ausserdem würde die Abfrage "SELECT * FROM forum_threads" genügen ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hi,

Kann es daran liegen, dass timestamp nicht NOT NULL ist? Das kann ich aber auch nicht ändern. Oder liegt es am Format? Habe das Format Timestamp gewählt. Hab vorher immer mit Oracle gearbeitet und da habe ich für Datum/Zeit-Angaben immer DATE benutzt. Aber DATE scheint ja unter MySQL keine Zeit zu enthalten.

timestamp ist dafür nicht geeignet, da er sich bei jeder Änderung des Datensatzes aktualisiert.

Nimm anstatt DATE einfach DATETIME, dann haste auch die Zeit mit drin.

Gruß Jaraz

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wunderbar, das funktioniert. Danke

Ziel ist die Auflistung aller threads in einem Forum. Threads ohne Inhalt sind sowieso nicht vorgesehen. Um den Erstellungszeitpunkt und den Author zum Thread zu haben, wird einfach der erste Post verwendet.

Hast du das auch schonmal mit einem Thread probiert, in dem zwei verschiedene User einen Post geschrieben haben? Diese sollten dann nämlich trotzdem beide erscheinen. Daher geht das IMO auch nicht ganz...

Ich kann Jesterday nur zustimmen.

Diese Felder gehören eigentlich in die Tabelle Threads mit rein...

Gruß,

Markus

Das würde ich nicht sagen - da ja jeder einzelne Post einen Ersteller und ein Datum hat, machen die Felder in der Tabelle Post schon Sinn. In Threads wären sie redundant. Und wie er sagt, gibt es ja auch keine Threads ohne Posts - also ist der erste Post automatisch der Text des Threads. So wird es AFAIK in fast jedem Forensystem gemacht. Die Überschrift des Threads ist ja schon in der Tabelle Threads vorhanden, wenn es allerdings so wie hier im Forum wäre, wo jeder Post eine eigene Überschrift haben kann, wäre de Spalte ebenfalls in Posts besser aufgehoben! Ich würde zur Ermittlung des ersten Posts und auch der Reihenfolge der Posts vielleicht noch ne feste Nummer in die Tabelle Posts einfügen, die bei jedem ersten Post mit 1 beginnt und hochgezählt wird - dann könnte man ganz einfach über PostNr = 1 nur die jeweils ersten Posts pro Thread anzeigen lassen...

Also meine Lösung wäre dann folgende (Hoffe, die Syntax passt zu MySQL)


SELECT P.threadid, P.userid, P.timestamp, T.headline

FROM forum_threads T

  JOIN forum_posts P ON (T.threadid = P.threadid and P.PostNr = 1)

WHERE T.forenid = 1

Link zu diesem Kommentar
Auf anderen Seiten teilen

Oh, sind ja noch einige Antworten gekommen.

@Jesterday:

timestamp wird ja auch nicht mit DISTINCT aussortiert sondern die Threadid. Es werden also zu erstmal alle Posts eines Threads ausgelesen (Where threadid = x) und durch das DISTINCT soll nur der erste Treffer mit der threadid stehen bleiben. (DISTINCT threadid) Das funktioniert auch solange man nicht auch noch timestamp selected. Finde ich komisch.

Der Aufbau mit den 2Tabellen gefällt mir eigentlich ganz gut und ich hatte eigentlich nicht vor jedem User die Möglichkeit einer Überschrift zu geben, da es eigentlich nicht nötig ist. Fände es nicht so praktisch die Threadlist komplett aus der Poststabelle auszulesen.

@beetFreeQ:

Die Idee mit dem Extrafeld für den Threaderstelle ist gar nicht schlecht. Wäre dann wahrscheinlich auch performanter. Allerdings ist es wegen des ORDER BY timestamp unnötig das Teil hochzuzählen. Habe mir gerade überlegt, eine "Bool"-Variable dafür anzulegen(Threadersteller true oder false ). Welcher Datentyp sollte ich da verwenden. Gibt es einen BOOL in SQL? INT mit 0 und 1 würde ja auch gehen.

Ob deine Syntax so auf MySQL funzt kann ich nocht nicht sagen. Habe ich auf Oracle aber auch so gelernt. Allerdings haben mich die Leute während meines Praktikums blöd angeguckt als ich denen sowas abgeliefert habe. Hatten dei anscheinend noch nicht gesehen. Seitdem schreibe ich das immer mit WHERE und AND. Obwohl es eigentlich etwas unübersichtlicher ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

@Jesterday:

timestamp wird ja auch nicht mit DISTINCT aussortiert sondern die Threadid. Es werden also zu erstmal alle Posts eines Threads ausgelesen (Where threadid = x) und durch das DISTINCT soll nur der erste Treffer mit der threadid stehen bleiben. (DISTINCT threadid) Das funktioniert auch solange man nicht auch noch timestamp selected. Finde ich komisch.

DISTINCT bezieht sich auf die Ergebnismenge, nicht das Feld dahinter.

SELECT DISTINCT Feld1, Feld2 FROM Tabelle liefert dir ein Ergebniss, in dem alle Datensätze drin sind, die unterschiedlichen Werte für Feld1 und Feld2 (in Kombination) haben.

SELECT DISTINCT Feld1, DISTINCT Feld 2 FROM Tabelle liefert dir höchstwahrscheinlich nur einen Fehler ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Gabs hier nicht gerade noch nen EDIT-Knopf?

Irgendwie ist der weg, obwohl ich eingelogt bin.

Sorry für den Doppelpost aber irgendwie kann ich meine Beiträge nicht bearbeiten.

@Jesterday: Du hast Recht. Das DISTINCT bezieht sich wirklich auf alle Spalten aus der gleichen Tabelle. Das ist ja blöd. Bei Oracle ist das aber nicht so.

Aber ist ja nicht so schlimm. Die GROUP BY Lösung funktioniert ja.

Jetzt fehlen mir nur noch Kommentare zu der Lösung mit der "BOOL"-Spalte. :D

Link zu diesem Kommentar
Auf anderen Seiten teilen

Zu den Posts einen Primary Key erfassen mit fortlaufender Nummer - am besten gleich Autoincrement - und dann mit einem SELECT MIN() den kleinsten Post für den jeweiligen Thread auslesen. Der kleinste Wert im Primary Key, des jeweiligen Topics ist auch der erste. Damit wäre die zusätzliche Spalte überflüssig.

Übrigens sind Threads und Posts 2 verschiedene Objekte im DBMS. Ergo 2 verschiedene Tabellen und nicht beides in eine oder gemischt. Die gehören zudem obligatorisch 1:n verknüpft. 1 Thread muss 1 oder mehr Posts haben.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das würde ich nicht sagen - da ja jeder einzelne Post einen Ersteller und ein Datum hat, machen die Felder in der Tabelle Post schon Sinn. In Threads wären sie redundant. Und wie er sagt, gibt es ja auch keine Threads ohne Posts - also ist der erste Post automatisch der Text des Threads. So wird es AFAIK in fast jedem Forensystem gemacht.

Weiss ich jetzt gar nicht, ob das in jedem forensystem so gemacht wird, kann ich mir daheim bei phpBB aber mal ansehen (wenn ich es nicht vergessen).

Kann mir das aber ehrlichgesagt nicht vorstellen.

Stell dir mal vor, aus irgendeinem Grund muss der erste Beitrag gelöscht werden (oder wird es), dann hast du auf einmal einen neuen Thread mit neuem Thema und neuem Ersteller, neuem Erstellungszeitpunkt... aber alten Beiträgen.

Für den ersten Beitrag mag das vielleicht dann redundant sein, aber die theoretische Lösung (x. Normalform) ist in der Praxis nicht unbedingt immer die beste.

EDIT:

IMHO sollten die Threads vollkommen unabhängig von den Beiträgen darin sein. Und ich bin auch der Meinung, dass das in fast jedem Forensystem so gemacht wird ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Weiss ich jetzt gar nicht, ob das in jedem forensystem so gemacht wird, kann ich mir daheim bei phpBB aber mal ansehen (wenn ich es nicht vergessen).

Kann mir das aber ehrlichgesagt nicht vorstellen.

Stell dir mal vor, aus irgendeinem Grund muss der erste Beitrag gelöscht werden (oder wird es), dann hast du auf einmal einen neuen Thread mit neuem Thema und neuem Ersteller, neuem Erstellungszeitpunkt... aber alten Beiträgen.

Für den ersten Beitrag mag das vielleicht dann redundant sein, aber die theoretische Lösung (x. Normalform) ist in der Praxis nicht unbedingt immer die beste.

EDIT:

IMHO sollten die Threads vollkommen unabhängig von den Beiträgen darin sein. Und ich bin auch der Meinung, dass das in fast jedem Forensystem so gemacht wird ;)

Hmm, war mir auch nicht 100% sicher - hab's nur so gelernt und auch für sinnvoll gehalten. Aber klar, wenn der erste Post gelöscht werden muss, passen die Daten nicht mehr zusammen, aber ist es denn besser, einen Thread von Benutzer X zu haben, der dank Löschens des ersten Posts mit einer Antwort von Benutzer Y anfängt? ;) - Ist so oder so etwas unglücklich, einfach so einen ersten Post zu löschen...

Link zu diesem Kommentar
Auf anderen Seiten teilen

aber ist es denn besser, einen Thread von Benutzer X zu haben, der dank Löschens des ersten Posts mit einer Antwort von Benutzer Y anfängt? ;) -

hm... ich denke da an einen Thread, in dem Benutzer Links zu ihren Lieblingswebseiten, oder Bildern o.ä. posten. Threadüberschrift "Lieblingslinks".

Ok, natürlich ist das etwas aus der Luft gegriffen, aber ich wollte nur auf die vermeidbare Abhängigkeit von Thread und Beitrag hinweisen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Also der weitere Posts hängen vom ersten Post und der vom Topic ab? Wenn ich das richtig verstehe, dann lösch ich also den ersten Post und dann wird nicht einer der anderen Posts zum ersten sondern die anderen Post liegen ohne Beziehung, weil der jeweilige Foreign Key nicht mehr gleich dem jeweiligen Primary Key ist. Damit sehe ich gar keine Posts mehr zu dem Thema.

Es ist nur sinnvoll die Beiträge, auch wenn es der erste sein mag, in einer anderen Tabellen zu speichern als das Topic. Allein schon, wenn ein Topic sich ändert, dann muss der Name des Topics in mehreren Datensätzen geändert werden. Und das Ganze auch noch fehlerfrei und ohne Transaktionen oder Stored Procedures in MySQl. Zudem um herraus zu finden wer ein Topic erstellt hat, kann man auch einfach den Primary Key des jeweiligen Users mit in die Topic- Tabelle übernehmen. Man sollte nur nicht vergessen auch hier User nur im Vordergrund zu löschen, weil ansonsten das SELECT fehlschlägt. Aber dafür kann man ja mit nem Bool (User gelöscht? Ja, Nein)in der Usertabelle arbeiten.

Im phpbb sind die übrigens getrennt und mit fällt kein Forensystem ein , wo es so ist, wie Du beschreibst.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es ist meiner Meinung optimal so wie es ist.

- Eine Tabelle für Threads/Topics mit ID, Überschrift

- Eine Tabelle mit Posts mit UserID, Text, Zeitpunkt...

- Werden alle Threads eines Forums angezeigt, wird der erste Post (identifiziert durch frühestes Datum) verwendet für Erstellungsdatum und Author

- Würde der erste Post gelöscht, würde der zweite Post zum Ersteller, was aber eigentlich egal ist, da ich es sehr viel wahrscheinlicher finde, dass der Thread gesperrt wird anstatt dass der erste Post gelöscht wird

-Beim Aufruf des Threads werden alle Posts mit der Threadid, geordnet nach dem Zeitpunkt, angezeigt

Finde ich so schonmal gut.

Hab mir gerade mal kurz die Doku angesehen. Ist es nicht totaler Schwachsin in die Poststabelle die forenid mit reinzunehmen?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Naja es ist im Prinzip wieder denormalisiert da eine transitive Abhängigkeit zwischen dem Post und dem Forum besteht und diese sollte eigentlich in der 3. Normalform weiter augeschlüsselt werden. Der Grund für die direkte Verknüpfung sollte Performance sein um den letzten Post in einem Forum anzeigen zu können ohne den Weg über das Topic zu gehen.

Um die Performance zu steigern wird oft nach dem Normalisieren wieder denormalisiert.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Dein Kommentar

Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.

Gast
Auf dieses Thema antworten...

×   Du hast formatierten Text eingefügt.   Formatierung wiederherstellen

  Nur 75 Emojis sind erlaubt.

×   Dein Link wurde automatisch eingebettet.   Einbetten rückgängig machen und als Link darstellen

×   Dein vorheriger Inhalt wurde wiederhergestellt.   Editor leeren

×   Du kannst Bilder nicht direkt einfügen. Lade Bilder hoch oder lade sie von einer URL.

Fachinformatiker.de, 2024 by SE Internet Services

fidelogo_small.png

Schicke uns eine Nachricht!

Fachinformatiker.de ist die größte IT-Community
rund um Ausbildung, Job, Weiterbildung für IT-Fachkräfte.

Fachinformatiker.de App

Download on the App Store
Get it on Google Play

Kontakt

Hier werben?
Oder sende eine E-Mail an

Social media u. feeds

Jobboard für Fachinformatiker und IT-Fachkräfte

×
×
  • Neu erstellen...