• Jetzt anmelden. Es dauert nur 2 Minuten und ist kostenlos!

LEFT JOIN nur bei jeweils neustem Datum

scbawik

Senior HTML'ler
Hallo!

Wäre gut wenn sich jemand mal folgendes ansehen kann:
http://sqlfiddle.com/#!2/1d48b/1

Kurze Erklärung was ich möchte.
Ziel ist, alle News zu selektieren, die beim letzten Kommentar (nur beim letzten - Feld "published") positiv ("gefaellt_mir") bewertet wurden. News die zwar schon mal mit gefaellt_mir kommentiert wurden aber nicht beim allerneusten Kommentar, sollen nicht selektiert werden. Es zählt also nur der jeweils neuste Kommentar.

Die richtige Ausgabe wäre in meinem Beispiel nur die News mit der news_id 3.
Die News mit der news_id 2 wurde zwar schon mal positiv kommentiert - allerdings nicht beim aktuellsten Kommentar. Deshalb darf sie nicht ausgegeben werden.

Ich bitte euch darum, keine Subqueries zu verwenden (wenn es überhaupt ohne geht). Ich habe nämlich schon eine gut funktionierende Abfrage mit dependent Subqueries welche aber unter MySQL 5.1 nicht korrekt optimiert wird und daher mehrere Stunden benötigt. Ein Update der MySQL-Version ist leider nicht möglich. Daher erhoffe ich mir von den JOINS dass der MySQL-Optimizer damit klar kommt.

In Wirklichkeit ist die Abfrage viel komplizierter und geht über 9 Tabellen. Das mit dem Datum ist allerdings der letzte "Knackpunkt" nachdem ich die Abfrage mit JOINS aufgebaut habe.

Wenn jemand meint es geht garnicht ohne Subqueries, wäre ich auch froh, dann wäre ich bestätigt.

Edit: Eine non-dependent Subquery ist natürlich schon ok, damit kommt der Optimizer ja klar.
 
Zuletzt bearbeitet:
Woran erkennt man denn die "neueste News"? An der ID? Dann wäre das ein ungünstiges Kriterium und dein Statement müsste lediglich so aussehen:

Code:
SELECT * FROM
  news AS n LEFT JOIN
  comments AS c USING (news_id)
WHERE
  c.comments_id IS NOT NULL AND
  c.gefaellt_mir = 1
GROUP BY
  n.news_id
ORDER BY
  c.news_id DESC,
  c.published ASC

Wenn Du im eigentlichen Statement, welches Du nicht zeigst, noch ein Newsdatum hättest, müsste man das aber sicher anders lösen.
 
Hm, aktuell scheint gerade SQLFiddle down zu sein.

Das Datum ist im Feld "c.published".

Das eigentliche Statement könnte ich schon zeigen, aber es ist so lang und macht für jemanden der nicht ins Projekt involviert ist, keinen Sinn, so dass ich mir denke darauf keine Antwort zu erhalten.

Edit: Achso, es geht nicht um die neuste News, sondern um den neusten Kommentar zu jeder News.
Ich möchte wissen, welche News, beim jeweils aktuellsten Kommentar, mit gefaellt_mir bewertet wurde.
 
Zuletzt bearbeitet:
Okay, neue Möglichkeit gefunden:

Code:
SELECT * FROM
  news AS n LEFT JOIN
  (SELECT * FROM comments GROUP BY news_id ORDER BY published DESC) AS c USING (news_id)
WHERE
  c.comments_id IS NOT NULL AND
  c.gefaellt_mir = 1
GROUP BY
  n.news_id

Jetzt ist aber das Problem, dass GROUP BY nicht den neusten comment nimmt, sondern einfach den ersten den er findet (denke ich).
Würde die Subquery zu jeder news_id den jeweils aktuellsten (published) Kommentar ausspucken - hätte ich mein Ziel erreicht. Hoffe ich...

Also nochmal in Kurzfassung:

Wie kann ich bestimmen, dass beim GROUP BY die Daten vom jeweils neusten Kommentar genommen werden:
Code:
SELECT * FROM comments GROUP BY news_id ORDER BY published DESC

Habe die Lösung:

Wieder mal typisch, wenn ich um Hilfe bitte komm ich selbst drauf. Sieht zwar mies aus, aber mit MySQL habe ich nach diesen Ärger ohnehin abgeschlossen.

Code:
SELECT * FROM (SELECT * FROM comments ORDER BY published) AS c_temp GROUP BY news_id

Trotzdem Danke, threadi.
 
Zuletzt bearbeitet:
Ich möchte wissen, welche News, beim jeweils aktuellsten Kommentar, mit gefaellt_mir bewertet wurde.

Das verstehe ich noch nicht ganz, vor allem den Halbsatz "beim jeweils aktuellsten Kommentar". Es gibt also X News zu denen es jeweils Y Kommentare geben kann. Jeder Kommentar kann 1malig mit "gefällt mir" markiert werden. Soweit richtig?
Was ich an dem Part rein Strukturell nicht verstehe ist wieso ein Kommentar nur 1 "gefällt mir" haben kann. Wenn es mehrere Besucher gibt, kann ja nur einer das Häkchen setzen, alle anderen schauen in die Röhre. Aber ok .. :)
Und davon willst Du nun die News anzeigen die die neueste Markierung von "gefällt mir" bei einem beliebig alten Kommentar haben? Das passt nun auch nicht zu deinem Datenbankmodell. Die Markierung "published" steht doch für den Kommentar, wann dieser veröffentlicht wurde - nicht für die Markierung "gefällt mir" mit der jemand (1 Nutzer Oo) diesen Kommentar markiert.

Unabhängig von diesen für mich offenen Fragen bzgl. der Tabellenstrukturen würde ich vom Statement her eher in diese Richtung tendieren (hab jetzt nicht nochmal nach den konkreten Spaltenbezeichnungen geschaut, denke aber du erkennst was ich meine):
Code:
SELECT n.news_id, c.kommentar
FROM (
 SELECT n.news_id, c.kommentar
 FROM news n
 INNER JOIN comments c ON c.news_id = n.news_id AND c.gefaellt_mir
 GROUP BY n.news_id
 ORDER BY c.published DESC
)
ORDER BY n.news_id ASC
 
Ich danke dir für deine Antwort, habe jedoch schon eine Lösung gefunden. Werde mir deinen Ansatz trotzdem noch ansehen.

Zur Vollständigkeit versuche ich noch mal zu erläutern wie es gemeint ist.

Es gibt X News zu denen es jeweils Y Kommentare geben kann.
Jeder Kommentar kann vom Verfasser des Kommentars mit einem "Gefällt mir" (gefaellt_mir = 1) oder "Gefällt mir nicht" (gefaellt_mir = 0) belegt werden. Dieses "Gefällt mir" nimmt Bezug auf die News, nicht auf den Kommentar.

Aber ist erledigt, Danke für deine Hilfe!
 
Ach, die liebe Vorfreude. Die Abfrage liefert jetzt zwar die richtigen Ergebnisse. Die Performance hat sich aber nur mäßig verbessert:

Code:
SELECT * FROM
  news AS n LEFT JOIN
  (SELECT * FROM (SELECT * FROM comments ORDER BY published) AS c_temp GROUP BY news_id) AS c USING (news_id)
WHERE
  c.comments_id IS NOT NULL AND
  c.gefaellt_mir = 1
GROUP BY
  n.news_id

Beim Beispiel-Datensatz merkt man davon natürlich nichts, aber bei der richtigen Datenbank (comments hat rund 700.000 Einträge) ist bei der ersten Abfrage erstmal Warten angesagt (SHOW PROCESSLIST: "Building tmp table").

Danach geht es schnell (ich denke mal wegen dem Cache) aber es sollte eigentlich immer schnell gehen.

Ich werde jetzt aber noch ein paar Feinheiten ändern, vielleicht klappt es dann besser.
 
Zuletzt bearbeitet:
Gut, konnte die Performance Probleme beheben. Habe jetzt noch ein letztes Problem:

Ich habe die Abfrage folgendermaßen geändert (ist eine andere Abfrage in anderem Zusammenhang):

Code:
SELECT * FROM
  news AS n LEFT JOIN
  (SELECT * FROM (SELECT * FROM comments ORDER BY published) AS c_temp GROUP BY news_id) AS c USING (news_id)
WHERE
  (
    c.comments_id IN (SELECT comments_id FROM comment-ratings WHERE rating = 1)
  )
GROUP BY
  n.news_id

Hier werden alle News, deren letzter Kommentar (Hier jetzt der Kommentar, nicht mehr die News) zumindest 1x positiv (rating = 1) bewertet wurde, selektiert. Passt soweit, klappt wunderbar.

Jetzt möchte ich aber zusätzlich die News abfragen, die gar keine Kommentare haben. Logischerweise ist bei diesen c.comments_id NULL und das IN-Statement liefert daher false.
Deshalb habe ich die Abfrage wie folgt geändert:

Code:
SELECT * FROM
  news AS n LEFT JOIN
  (SELECT * FROM (SELECT * FROM comments ORDER BY published) AS c_temp GROUP BY news_id) AS c USING (news_id)
WHERE
  (
    c.comments_id IS NULL OR
    c.comments_id IN (SELECT comments_id FROM comment-ratings WHERE rating = 1)
  )
GROUP BY
  n.news_id

Also WENN c.comments_id NULL ist ODER c.comments_id in der Tabelle comment-ratings vorhanden ist.
Ich habe also verglichen mit der 1. Abfrage nur "c.comments_id IS NULL OR" hinzugefügt.

Dieses vermeintlich leichte Kriterium verlangsamt meine Abfrage aber von 0.1 Sekunden auf rund 60 Sekunden.

Aus meiner Sicht ist "IS NULL" eine der einfachsten Abfragen die es gibt?

Das Ergebnis stimmt dann zwar, aber das ist ja viel zu lange.

Irgendeine Idee weshalb das so ist?


PS: Falls du dich fragst wieso ich überhaupt so etwas komisches machen will? Ich bastle gerade an einer Klasse bei der Suchkriterien beliebig kombiniert werden können für ein Projekt. Und das ist eine mögliche, wenn auch realitätsfremde, Konstellation.

Danke schon mal fürs lesen :)

Update:

Gerade habe ich ein erstaunliches Verhalten bemerkt.
Wenn ich
Code:
c.comments_id IS NULL
durch
Code:
c.comments_id = NULL
ersetze.

Läuft die Abfrage wieder blitzschnell. Allerdings stimmt das Ergebnis nicht mehr! Die News ohne Kommentare fehlen.
 
Zurück
Oben