Anatol: MySQL-Zwickmuehle

Hallo Forum!

Ich stecke leider gerade in der MySQL-Zwickmuehle. Ich hoffe ich kann das Problem irgendwie deutlich machen.
Im Grunde genommen ist es eine simple SELECT-Abfrage mit nur einer Tabelle. Hier ein Auszug aus der Tabelle content_module.

table: content_module
+----+------------+----------+------+
| id | content_id | position | type |
+----+------------+----------+------+
| 79 | 1          | 0        | 1    |
| 80 | 1          | 1        | 1    |
| 81 | 1          | 2        | 0    |
| 82 | 1          | 3        | 1    |
| 83 | 1          | 4        | 1    |
| 3  | 2          | 0        | 1    |
| 4  | 3          | 0        | 0    |
... etc ...
+----+------------+----------+------+

Die Tabelle ist eine Zwischentabelle. Man muss sich das folgendermassen vorstellen: es gibt verschiedene Beitraege, die sich aus einem oder mehreren Inhaltsmodulen zusammensetzen. In einer anderen Tabelle werden Informationen zum Beitrag gespeichert (Datum, Autor, etc...), diese Tabelle content_module speichert, welche Inhaltsmodule zu einem solchen Beitrag gehoeren, weitere Tabellen speichern die Inhalte der verschiedenartigen Inhaltsmodule (Text, Grafik, Datei, Tabelle, Diagramm, etc...)

In obigem Beispiel hat der Beitrag mit der content_id = 1 fuenf Inhaltsmodule von Typ 0 bzw. 1. Die Position gibt an, in welcher Reihenfolge die Inhaltsmodule ausgegeben werden.

Soweit ist das denke ich nicht besonders aussergewoehnlich.

Es gibt nun eine Uebersichtsseite, in der das jeweils erste Inhaltsmodul eines Beitrags angezeigt wird. Gibt es mehrere Inhaltsmodule zu einem Beitrag, so wird ein Link "lesen Sie mehr" angezeigt. Soweit klar?

ZUM EIGENTLICHEN PROBLEM:

Eine SQL-Query, die ich fuer diese Uebersichtsseite verwende lautet:

"SELECT id,
 position,
 type,
 CASE WHEN COUNT(content_id) > 1 THEN 1 ELSE 0 END AS more
 FROM content_module
 WHERE content_id = '1'
 GROUP BY content_id
 ORDER BY position"

Ich erzeuge in der Zeile mit CASE also die Spalte "more", die den Wert 1 erhaelt, wenn es mehr als 1 Inhaltsmodul gibt, bzw. 0, wenn es eben nur ein Inhaltsmodul gibt. Je nachdem, ob dieser Wert 0 oder 1 ist wird ein Link "lesen Sie mehr" angezeigt oder eben nicht.

Soweit macht es fuer mich Sinn. Das Problem ist nun, dass mich COUNT() zwingt GROUP BY zu verwenden. GROUP BY wiederum verhindert, dass die Ausgabe nach der Spalte "position" sortiert wird. Denn eigentlich soll ja nur der erste Beitrag mit position = 0 ausgegeben werden. Dies ist aber nicht gewaehrleistet, da ORDER BY nach GROUP BY ausgefuehrt wird und GROUP BY das Ergebnis in diesem Fall ohnehin nur auf eine einzige Zeile zusammenfasst. Als Ergebnis erhalte ich also ein Inhaltsmodul beliebiger Position.

Verwende ich z.B.
"... WHERE content_id = '1'
AND position = '0' ..."
dann macht die Zeile mit CASE keinen Sinn mehr, da sowieso nur eine Zeile ausgegeben wird. Die Spalte "more" wuerde also immer den Wert 0 erhalten.

Klar koennte ich auch einfach alle Zeilen ausgeben lassen und dann per PHP nachsehen, ob es mehr als ein Inhaltsmodul gibt und danach entscheiden, ob ein "lesen Sie mehr"-Link gesetzt werden soll oder nicht. Eine reine SQl-Loesung waere mir aber lieber. Und wenn's auch nur darum geht, mal wieder was dazuzulernen.

Ich hoffe, ich konnte die Zwickmuehle verstaendlich darstellen.
Ich bin um jeden Wink mit dem Zaunpfahl dankbar.

Schoene Gruesse
Anatol

  1. Eigentlich ist es legitim für das Counten einen Extra SELECT auszuführen. Denn durch das Counten durchläuft er er wirklich alle Datensätze, wenn du nun beim Counten auch noch was dran hängst, durchläuft er alle Datensätze auch mit diesem Zusatz.

    D.h. generell ist es eh besser das Count() extra zu behandeln.

    Klar koennte ich auch einfach alle Zeilen ausgeben lassen und dann per PHP nachsehen

    Ich finde aber eine PHP-Lösung viel einfacher, und weniger Preformance-schluckend:

    $inhaltsmodule = mysql_query("SELECT id, position, type,
     FROM content_module
     WHERE content_id = '1'
     GROUP BY content_id
     ORDER BY position");

    $count_inhaltsmodule = mysql_affected_rows();

    if($count_inhaltsmodule >1)

    1. Hallo Anton,

      vielen Dank fuer die schnelle Antwort. Ja. Per PHP waer's vielleicht gar nicht so schlecht.

      Eigentlich ist es legitim für das Counten einen Extra SELECT auszuführen. Denn durch das Counten durchläuft er er wirklich alle Datensätze, wenn du nun beim Counten auch noch was dran hängst, durchläuft er alle Datensätze auch mit diesem Zusatz.

      D.h. generell ist es eh besser das Count() extra zu behandeln.

      Trotz PHP-Loesung: Ich hab jetzt noch eine SQL-Abfrage seperat fuer COUNT() gefunden, die auch funktioniert.

      query 1:
      "SELECT @more := CASE WHEN COUNT( content_id ) >1 THEN 1 ELSE 0 END
       FROM content_module
       WHERE content_id = '1'
       GROUP BY content_id"

      query 2:
      "SELECT id, content_id, position,
       type,
       @more AS more
       FROM content_module
       WHERE content_id = '1'
       ORDER BY position
       LIMIT 0 , 1"

      Vielen Dank nochmals! Schoene Gruesse!
      Anatol