Willkommen bei Entwickler-Forum.
Ergebnis 1 bis 2 von 2
  1. #1
    Forenheld
    Registriert seit
    26.02.2003
    Ort
    Sachsen-Anhalt
    Beiträge
    5.180

    Standard Bei "doppelten" Datensätzen nur einen anzeigen

    Da sich das Thema allgemeiner Beliebtheit erfreut, hier der ultimative Beitrag zum Thema "Wie gelingt es mir mit SQL, aus einer Menge gleicher Daten, nur den Jüngsten auszuwählen?"

    Gegeben sei folgende Tabelle:
    Code SQL:
    CREATE TABLE doppeltest (
      id       INTEGER(8)  NOT NULL   AUTO_INCREMENT,
      name     VARCHAR(64) NOT NULL,
      last_use datetime    NOT NULL,
      CONSTRAINT PRIMARY KEY (id)
    );
    mit folgenden Daten:
    Code SQL:
    INSERT INTO doppeltest (name, last_use) VALUES
    ('Otto', '2010-07-01 20:30:24'),
    ('Kurt', '2010-07-01 21:42:54'),
    ('Karl', '2010-07-01 18:21:31'),
    ('Otto', '2010-07-01 19:24:29'),
    ('Kurt', '2010-07-01 10:33:22'),
    ('Max', '2010-07-01 09:36:54'),
    ('Otto', '2010-07-01 21:40:27');

    Es sollen alle Datensätze mit "id", "name" und "last_use" aufgelistet werden, jedoch für jeden "name" nur der mit dem jüngsten "last_use". Da ausdrücklich auch eine Auflistung von "id" gefordert ist, scheidet eine einfache Gruppierung und Verwendung der Aggregatfunktion MAX() für "last_use" aus.
    Die Lösung liegt in der Abfrage mittels Subselect. Jedes "last_use" wird dabei mit dem jüngsten "date" jeder mittels "name" gebildeten Gruppe verglichen.

    Code SQL:
    SELECT a.id, a.name, a.last_use
    FROM doppeltest a
    WHERE a.last_use = (
      SELECT MAX(b.last_use)
      FROM doppeltest b
      WHERE b.name = a.name
    )
    Ergebnis:
    Code:
    id 	name 	last_use
    2 	Kurt 	2010-07-01 21:42:54
    3 	Karl 	2010-07-01 18:21:31
    6 	Max 	2010-07-01 09:36:54
    7 	Otto 	2010-07-01 21:40:27
    Problematisch wird es jetzt, wenn zu einem "name" zwei (oder mehr) Datensätze mit identischem "last_use" existieren. (Davon muß man ggfs. immer ausgehen, wenn die Anderweitigkeit nicht durch einen entsprechenden Constraint sichergestellt ist).

    Code SQL:
    INSERT INTO doppeltest (name, last_use) VALUES
    ('Max', '2010-07-01 09:36:54');

    Die o.g. Lösung liefert uns jetzt wieder doppelte Werte für "name".
    Code:
    id 	name 	last_use
    2 	Kurt 	2010-07-01 21:42:54
    3 	Karl 	2010-07-01 18:21:31
    6 	Max 	2010-07-01 09:36:54
    7 	Otto 	2010-07-01 21:40:27
    8 	Max 	2010-07-01 09:36:54
    Da zwischen den jetzt vorhanden Dopplungen nur anhand der "id" unterschieden werden kann, muß einfach entschieden werden, welche "id" in einem solchen Fall verwendet werden soll. Wir entscheiden uns für die Größte und damit genügt eine zusätzliche Gruppierung des Ergebnisses.

    Code SQL:
    SELECT MAX(a.id) id, a.name, last_use
    FROM doppeltest a
    WHERE a.last_use = (
      SELECT MAX(b.last_use)
      FROM doppeltest b
      WHERE b.name = a.name
    )
    GROUP BY a.name, last_use

    Ergebnis:
    Code:
    id 	name 	last_use
    3 	Karl 	2010-07-01 18:21:31
    2 	Kurt 	2010-07-01 21:42:54
    8 	Max 	2010-07-01 09:36:54
    7 	Otto 	2010-07-01 21:40:27
    Anmerkung: Durch die Verwendung der Aggregatfunktion MIN() kann man diesen Lösungsansatz einfach für die Frage nach dem Ältesten Datensatz anpassen.

    Gruß Falk
    Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

    Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

  2. #2
    Forenheld
    Registriert seit
    26.02.2003
    Ort
    Sachsen-Anhalt
    Beiträge
    5.180

    Standard

    Neben der "klassischen" Variante gibt es auch noch eine Lösung, die gänzlich ohne Subselect auskommt. Dank einer ebenso cleveren wie trivialen Idee von frauwue kann ich die hier auch mit vorstellen.
    Code SQL:
    SELECT a.id, a.name, a.last_use
    FROM doppeltest a
    LEFT OUTER JOIN doppeltest b ON b.name = a.name
                                AND b.last_use > a.last_use
    WHERE b.last_use IS NULL
    Dieser Join macht sich den (eigentlich logischen) Umstand zunutze, dass es zu einem höchsten (bzw. niedrigstem) Datum kein noch höheres (bzw. noch niedrigeres) geben kann, und damit nur jeweils ein DS übrigbleibt, der die JOIN-Bedingung NICHT erfüllt.

    Die Problematik bei zwei (oder mehr) Datensätze mit identischem "last_use" steht hierbei jedoch genauso wie bei der Variante mittels Subselect und lässt sich ebenso lösen.

    Anmerkung:
    Für dieses konkrete Beispiel spielt es zwar keine Rolle, da alle Felder als NOT NULL angelegt sind, dennoch möchte ich daraufhinweisen das die JOIN-Lösung "Schwächen" hat, wenn in "last_use" NULL-Werte enthalten sind. Diese werden mit selektiert, da sie die JOIN-Bedingung ebenfalls NICHT erfüllen.
    Wenn du denkst du hast alle Bugs gefunden, dann ist das ein Bug in deiner Denksoftware.

    Quellcode ohne ein Mindestmaß an Formatierung sehe ich mir nicht an! Ich leiste keinen Privatsupport per Mail oder PN!

 

 

Stichworte

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •