Vinzenz Mai: korrelierte Subselects - ein kleiner Ausblick

Beitrag lesen

Hallo Struppi,

Ich habe eine Datenbank mit Tabellen die etwa so sind. A hat mehrere Status. Es soll immer der neuste Angezeigt werden. Nur DER neuste (Also einer). Wenn jetzt aber einer der Status eine Information ist, soll nicht dieser neuste, sondern der Zweitneuste (Halt einfach der, der keine Information ist) angezeigt werden.

Du meinst sowas?
SELECT * FROM A WHERE status != 'information' ORDER BY datum DESC LIMIT 1

diese Anweisung setzt voraus, dass die Ergebnismenge aus genau einem Datensatz bestehen soll und dazu die Werte in der Spalte datum eindeutig sein müssen. Im Falle der Nichteindeutigkeit könntest Du ja zwei Datensätze mit dem gleichen Datumswert haben und somit durch Deine LIMIT-Klausel ein richtiges Ergebnis verwerfen. Darauf hat übrigens Ilja in diesem Thread bereits hingewiesen.

Das von mir kritisierte Posting läßt jedoch darauf schließen, dass die Ergebnismenge aus mehr als einem Datensatz bestehen kann, dass es verschiedene Einträge gibt, deren neuester Status, der nicht eine Information ist, zurückgeliefert werden soll.

Ob diese meine Interpretation richtig ist, das weiß ich nicht. Meine und Iljas Bemühungen, Beispieldaten zu erhalten, sind ja im Nichts verpufft. Wer weiß, vielleicht hat ja mein strenger Ton in meinem zweiten Posting dazu beigetragen. Das wäre schlecht :-(

Um jetzt fortzufahren. Stimmt meine Vermutung, so wäre dies ein klassischer Fall für eine korrelierte Unterabfrage, worauf Ilja und ich beide in diesem Thread bereits hingewiesen haben.

Ein Beispiel zur Problematik mit Erläuterungen

Beispieldaten (eine Tabelle)

id  name      thema            zeit
-------------------------------------------------
  1  Max       PHP              12.06.2006 14:30
  2  Moritz    Datenbanken      12.06.2006 14.32
  3  Max       HTML             13.06.2006 08:40
  4  Wilhelm   HTML             14.06.2006 22:00
  5  Bolte     Perl             14.06.2006 22:00
  6  Moritz    HTML             15.06.2006 12:05
  7  Moritz    Datenbanken      15.06.2006 14:47
  8  Max       Javascript       16.06.2006 09:17
  9  Wilhelm   Javascript       17.06.2006 11:26
 10  Max       HTML             17.06.2006 11:58

Aufgabenstellung:

Benötigt wird genau ein Datensatz zu einem bestimmten Kriterium, zum Beispiel der neueste Beitrag pro Autor. Mit GROUP BY und den Aggregatsfunktionen wie min() oder max() lassen sich zwar zwei dieser Spalten bequem ermitteln, aber nicht die dazugehörenden Werte der Spalten id und thema.

Standardlösung mit korreliertem Subselect

SELECT  
  id,  
  name,  
  thema,  
  zeit  
FROM nachrichten n1  
WHERE zeit = (  
    SELECT MAX(n2.zeit)  
 FROM nachrichten n2  
 WHERE n1.name = n2.name  
)

liefert das gewünschte Ergebnis

id  name      thema            zeit
-------------------------------------------------
  5  Bolte     Perl             14.06.2006 22:00
  7  Moritz    Datenbanken      15.06.2006 14:47
  9  Wilhelm   Javascript       17.06.2006 11:26
 10  Max       HTML             17.06.2006 11:58

Möchte man jedoch keine Beiträge zum Thema HTML, so ergänzt man diese Bedingung in der WHERE-Klausel des Subselects:

SELECT  
  id,  
  name,  
  thema,  
  zeit  
FROM nachrichten n1  
WHERE zeit = (  
    SELECT MAX(n2.zeit)  
 FROM nachrichten n2  
 WHERE n1.name = n2.name  
            AND n2.thema != 'HTML'  
)

Ergebnis (wie gefordert):

id  name      thema            zeit
-------------------------------------------------
  5  Bolte     Perl             14.06.2006 22:00
  7  Moritz    Datenbanken      15.06.2006 14:47
  8  Max       Javascript       16.06.2006 09:17
  9  Wilhelm   Javascript       17.06.2006 11:26

Subselects unterstützt MySQL jedoch erst ab Version 4.1, wie ich in diesem Thread bereits anmerkte.

Wie der OP sein Problem angehen könnte, das hängt von seiner MySQL-Version, seinen Tabellen und deren Beziehungen untereinander ab. Deswegen haben wir hier im Thread bereits mehrfach nachgefragt.

Meine Erfahrung hier im Forum zu Mengen von PHP-Code gemischt mit einigen SQL-Statements ist übrigens die, dass mit PHP versucht wird, Funktionalität nachzubauen, die in einem Datenbankmanagementsystem bereits vorhanden ist. Allerdings muss dies, wenn man keine einzige Zeile Code gesehen hat, im konkreten Einzelfall noch lange nicht so sein. Ich gebe jedoch gerne zu, dass ich dies im Falle des OP durchaus befürchte.

Freundliche Grüße

Vinzenz