Erich: Jeweils bestimmten Wert finden für Spalte

Wie lautet eine Abfrage in SQL, wenn man aus diesen Daten

id datum
1 2013-01-01
1 2013-02-04
1 2013-06-15
2 2011-08-05
2 2012-12-12
3 2013-01-15
3 2013-05-08
3 2013-08-10

für jede ID jeweils das letzte Datum vor dem 01.03.13 finden will?

  1. Tach!

    Wie lautet eine Abfrage in SQL, wenn man aus diesen Daten

    id datum
    1 2013-01-01
    1 2013-02-04
    1 2013-06-15
    2 2011-08-05
    2 2012-12-12
    3 2013-01-15
    3 2013-05-08
    3 2013-08-10

    für jede ID jeweils das letzte Datum vor dem 01.03.13 finden will?

    Da du nicht gesagt hast, welchen SQL-Dialekt du meinst, antworte ich mal, wie ich das für MySQL versuchen würde. Selektiere als ersten Wert eindeutige IDs (distinct). Als zweiter kommt eine korrelierte Subquery zum Einsatz. Die findet eingeschränkt auf die ID aus der Hauptquery alle Datensätze, die kleiner sind als dein Datum. Absteigend sortiert und limitiert auf 1 hast du dein Davor-Datum.

    dedlfix.

    1. Selektiere als ersten Wert eindeutige IDs (distinct). Als zweiter kommt eine korrelierte Subquery zum Einsatz. Die findet eingeschränkt auf die ID aus der Hauptquery alle Datensätze, die kleiner sind als dein Datum. Absteigend sortiert und limitiert auf 1 hast du dein Davor-Datum.

      Danke.

      Etwa so?

      select datum from x
      where id in
      (
      select distinct id from x
      )
      order by datum desc
      limit 1,1

      1. Tach!

        Selektiere als ersten Wert eindeutige IDs (distinct). Als zweiter kommt eine korrelierte Subquery zum Einsatz. Die findet eingeschränkt auf die ID aus der Hauptquery alle Datensätze, die kleiner sind als dein Datum. Absteigend sortiert und limitiert auf 1 hast du dein Davor-Datum.

        Etwa so?

        select datum from x
        where id in
        (
        select distinct id from x
        )
        order by datum desc
        limit 1,1

        Nein, andersrum. Die äußere selektiert nur die eindeutigen ID, die Subquery sucht dazu das Datum (und bei Limit reicht eine 1).

        dedlfix.

        1. Nein, andersrum. Die äußere selektiert nur die eindeutigen ID, die Subquery sucht dazu das Datum (und bei Limit reicht eine 1).

          Dem kann ich wohl nicht folgen, kannst Du es mal zeigen?

          Ich denke, das geht aber auch?

          select id, max(datum) from test where datum < "2013-03-01"
          group by id

          1. Tach!

            Ich denke, das geht aber auch?

            select id, max(datum) from test where datum < "2013-03-01"
            group by id

            Bringt es das gewünschte Ergebnis? Wenn ja, dann nimm das, und ich hab zu kompliziert gedacht.

            dedlfix.

            1. Bringt es das gewünschte Ergebnis? Wenn ja, dann nimm das, und ich hab zu kompliziert gedacht.

              Es scheint so. Die Beispieldaten hier sind realiter die Daten einer Abfrage aus zwei Tabellen (id und Datum sind nicht aus derselben Tabelle, hinzu kommen noch weitere Daten, die, da unnötig, hier nicht aufgeführt wurden). Darauf angewandt, scheint es ebenfalls zu funktionieren, es sind aber noch nicht genug Testdaten in den Tabellen, um es zweifelsfrei zu verifizieren.

              Allgemein stellt sich mir die Frage, wie man bei Problemstellungen wie dieser vorgeht. Ich stelle mich da immer wieder an und erfinde quasi das Rad jeweils neu. Gibt es ein gewisses Schema, das man anwenden kann? Die gefundene Lösung(?) ist so trivial, darauf zu kommen, hat mich zwei Stunden gekostet.

              1. Tach!

                Die Beispieldaten hier sind realiter die Daten einer Abfrage aus zwei Tabellen (id und Datum sind nicht aus derselben Tabelle, hinzu kommen noch weitere Daten, die, da unnötig, hier nicht aufgeführt wurden).

                Wenn du in eine Abfrage mit GROUP BY noch Felder abfragst, die nicht in der GROUP-BY-Klausel enthalten sind und auch nicht über eine Aggregatfunktion (MAX(), SUM(), etc) zusammengefasst wurden, so ist das eigentlich ein Fehler. MySQL ist hier so gnädig und nimmt dann irgendwelche Daten aus der Gruppe in das Ergebnis. Das kann funktionieren, muss aber nicht. In dem Fall brauchts dann doch die Subquery-Geschichte.

                Allgemein stellt sich mir die Frage, wie man bei Problemstellungen wie dieser vorgeht. Ich stelle mich da immer wieder an und erfinde quasi das Rad jeweils neu. Gibt es ein gewisses Schema, das man anwenden kann? Die gefundene Lösung(?) ist so trivial, darauf zu kommen, hat mich zwei Stunden gekostet.

                Vielleicht ist sie zu trivial. Ansonsten hilft da nur die Erfahrung, welche Sprachelemente der verwendete SQL-Dialekt bietet und ein gewisser Grundschatz an Mustern.

                dedlfix.

    2. Hi,

      Wie lautet eine Abfrage in SQL, wenn man aus diesen Daten
      id datum
      für jede ID jeweils das letzte Datum vor dem 01.03.13 finden will?

      Selektiere als ersten Wert eindeutige IDs (distinct). Als zweiter kommt eine korrelierte Subquery zum Einsatz. Die findet eingeschränkt auf die ID aus der Hauptquery alle Datensätze, die kleiner sind als dein Datum. Absteigend sortiert und limitiert auf 1 hast du dein Davor-Datum.

      Vielleicht verstehe ich es falsch... aber ich würde den Datensatz zunächst auf alle Zeilen eingrenzen, deren Datum vor dem 01.03.13 ist, und dann nach id gruppieren und den Datumseintrag wählen, das am größten ist.

        
      SELECT id, MAX(datum)  
      FROM mytable  
      WHERE datum < '2013-03-01'  
      GROUP BY id  
      
      

      Halte _ich_ für einfacher, als hier mit korrelierten Unterabfragen zu arbeiten.

      Bis die Tage,
      Matti

      1. Tach!

        Selektiere als ersten Wert eindeutige IDs (distinct). Als zweiter kommt eine korrelierte Subquery zum Einsatz. Die findet eingeschränkt auf die ID aus der Hauptquery alle Datensätze, die kleiner sind als dein Datum. Absteigend sortiert und limitiert auf 1 hast du dein Davor-Datum.
        Vielleicht verstehe ich es falsch... aber ich würde den Datensatz zunächst auf alle Zeilen eingrenzen, deren Datum vor dem 01.03.13 ist, und dann nach id gruppieren und den Datumseintrag wählen, das am größten ist.

        Das ist ja genau die Lösung, die Erich bereits selbst gefunden hat. Und sie sieht auf den ersten Blick zielführend und einfacher als mein Gedankengang aus.

        Halte _ich_ für einfacher, als hier mit korrelierten Unterabfragen zu arbeiten.

        Es kann aber sein, dass er im weiteren Verlauf diese zumindest zusätzlich verwenden muss. Er hat ja angedeutet, dass dieser Teil nur einer von mehreren einer größeren Aufgabe ist. Im großen Maßstab betrachtet kann diese einfache Lösung aber auch hinderlich wirken und ein anderer Lösungsweg als geeigneter erscheinen.

        GROUP BY hat ja den Nachteil, dass es unter MySQL nicht unbedingt eine saubere Lösung ist und unter anderen DBMSen gar nicht erst gestattet ist, weitere Felder in die Abfrage mit aufzunehmen. Dann kann die Ermittlung des Datumswertes in eine Subquery ausgelagert werden, ohne dass man in eine "Gefahrenzone" gerät.

        SELECT id, irgendwelche felder, (SELECT MAX(datum) FROM t2 WHERE datum < '2013-03-01' AND t2.id = t1.id) maxdatum FROM t1 ...

        dedlfix.