sql-Abfrage mit Gruppierung und zusätzlicher Spalte



  • Hallo,

    hab diese Tabelle:

    +----+---------------------+---------------------+----------+
    | id | lagerOrt            | datum               | paNummer |
    +----+---------------------+---------------------+----------+
    |  1 | LF 8                | 2004-02-10 00:00:00 | Ü 1      |
    |  2 | LF 8                | 2004-03-03 00:00:00 | Ü 1      |
    |  3 | Atemschutzwerkstadt | 2004-08-15 00:00:00 | Ü 1      |
    |  4 | LF 8                | 2004-02-10 00:00:00 | Ü 2      |
    |  5 | LF 16               | 2004-04-03 00:00:00 | Ü 2      |
    |  6 | LF 16               | 2004-05-15 00:00:00 | Ü 2      |
    |  7 | Atemschutzwerkstadt | 2004-02-11 00:00:00 | Ü 3      |
    |  8 | LF 8                | 2004-03-03 00:00:00 | Ü 3      |
    |  9 | LF 16               | 2004-07-15 00:00:00 | Ü 3      |
    +----+---------------------+---------------------+----------+
    

    jetzt bräuchte ich gruppiert nach 'paNummer'
    jeweils die Zeile mit dem neuesten Datum.
    (also die Zeilen mit id 3, 6 und 9, wobei es momentan Zufall ist,
    dass gerade der letzte jeder Gruppe der Gesuchte ist.)

    soweit bin ich bis jetzt:

    select paNummer, max(datum)
    from myTable
    group by paNummer.
    

    Was noch fehlt ist der zugehörige Lagerort.
    Steh ich da jetzt aufm Schlauch, oder ist das wirklich so
    kompliziert?

    Achja:
    ich verwend MySQL 4.1

    Dank schon mal im Voraus an den SQL-Gott, der hier eine Antwort weiss 🙂
    Martin



  • Ich bin absolut kein SQL Gott aber wenn du doch die Spalte Lagerort willst dann nimm sie doch mit in dein Select!

    select paNummer, max(datum), Lagerort
    from myTable
    group by paNummer.
    

    glaub ich zumindest! Wenn du es nicht wählst kann es auch nicht erscheinen! 😃



  • das Problem dabei ist,
    dass im 'SELECT' nur die Spalten stehen können,
    die auch im 'GROUP BY' auftauchen.
    (ausser man läßt diverse Funktionen wie max, sum, avg drauf los)

    MySql spukt zwar keine Fehlermeldung aus (Oracle z. B. glaub ich schon),
    liefert allerdings falsche Ergebnisse 😞

    Trotzdem danke

    mfg
    Martin



  • na dann mach halt:

    select paNummer, max(datum), Lagerort 
    from myTable 
    group by paNummer, Lagerort
    

    Brauchst denn unbedingt group by? tut es dir nicht auch order by? Willst du sie sortieren oder willst du die Anzahl einer Gruppe zurück haben?



  • hab's jetzt mit mehreren Anfragen gemacht:

    -- erst mal ermitteln, was es überhaupt gibt
    select paNummer
    from myTable
    group by paNummer;
    
    -- und jetzt für XXX jeweils einen Eintrag von oben einsetzten
    select paNummer, lagerort
    from myTable
    where paNummer = 'XXX' and datum = 
    (
    select max(datum) from lagerort_pa where paNummer = 'XXX'
    );
    

    Wäre halt schön gewesen, wenn das in einer Anfrage gegangen wäre...
    aber egal

    Danke
    Martin



  • So funktioniert es mit einem Select.

    select id, lagerort, datum, paNummer
      from lager
    where (panummer,datum) in ( select paNummer, max(datum) datum
                                  from lager
                                 group by paNummer);
    


  • ich glaub, du bist da chef 🙂
    vor allem weil ich gemerkt hab, dass mein Zeug von oben auch ned so 100%ig funzt 😞

    fättes mercy



  • Nein das kann doch gar nich gehen.
    du musst doch erst die group by-klausel aufrufen



  • Lagerort dürfte laut 3. MF nur als Key drin sein, dann wär das alles kein Problem 🙂

    MfG SideWinder



  • @peter ka
    Warum probierst du es nicht erst mal aus??

    @SideWinder
    Wo ist der Unterschied ob dort nun ein String oder eine Nummer enthalten ist? Kann doch eh nur ein Foreing Key sein.



  • Ist doch alles nicht so schwer... :

    SELECT paNummer, datum, lagerOrt
    FROM myTable mt
    WHERE NOT EXISTS (
    	SELECT mt2.id
    	FROM myTable mt2
    	WHERE mt2.datum > mt.datum
    	AND mt2.paNummer = mt.paNummer 
    )
    


  • @finten
    es sagt ja auch keiner das es schwer ist 😉 und natürlich funktioniert deine Lösung. Ich habe aber meine und deine Lösung getestet um zu zeigen, das deine Lösung mittels Join für die Datenbank ein extremes Problem darstellen kann. Performenz!!!
    Die Tabelle beinhaltet 9216 Datensätze (nicht grade viele)

    SQL> select count(*) from lager;
    
      COUNT(*)
    ----------
          9216
    

    Hier deine Lösung

    SQL> start 2
    SQL> -- SELECT id,paNummer, datum, lagerOrt
    SQL> select count(*)
      2  FROM lager mt
      3  WHERE NOT EXISTS (
      4      SELECT mt2.id
      5      FROM lager mt2
      6      WHERE mt2.datum > mt.datum
      7      AND mt2.paNummer = mt.paNummer
      8  );
    
      COUNT(*)
    ----------
            10
    
    Elapsed: 00:00:37.35
    

    und hier meine

    SQL> select count(*)
      2    from lager
      3  where (panummer,datum) in ( select paNummer, max(datum) datum
      4                                from lager
      5                               group by paNummer)
      6  /
    
      COUNT(*)
    ----------
            10
    
    Elapsed: 00:00:00.06
    

    Diese Ausgabe ist jedoch nur für Oracle Datenbanken gültig. Über andere Datenbanken kann ich keine Aussage machen, denke jedoch das sich alle "richtigen" Datenbanken so verhalten werden. Die Zeitangaben sind "Elapsed: Stunden:Minuten:Sekunden:Sekunden/100.



  • @Nikolaus

    Bist du sicher, dass sich der IN-Operator auf mehrere Werte beziehen kann (außer bei Oracle)? Ich kenns vom SQL-Server nur mit einem Wert. Auch wird beim SQL-Server geraten, bei Unterabfragen EXISTS statt IN zu verwenden, da dies performanter sei. Ok, meine ist korreliert, deine nicht, wird wohl den Unterschied ausmachen :).

    Kann natürlich sein, dass ich mich täusche.



  • Finten schrieb:

    @Nikolaus

    Bist du sicher, dass sich der IN-Operator auf mehrere Werte beziehen kann (außer bei Oracle)? Ich kenns vom SQL-Server nur mit einem Wert. Auch wird beim SQL-Server geraten, bei Unterabfragen EXISTS statt IN zu verwenden, da dies performanter sei. Ok, meine ist korreliert, deine nicht, wird wohl den Unterschied ausmachen :).

    Kann natürlich sein, dass ich mich täusche.

    dass sich der IN-Operator auf mehrere Werte beziehen kann

    Meine natürlich, dass es mir neu wäre (beim SQL-Server), dass links vom IN-Operator mehrere Spalten stehen können.

    Eine Frage noch, wieviele unterschiedliche "paNummer" sind in der Tabelle? Ich vermute es sind nur wenige unterschiedliche Werte. Bei vielen unterschiedlichen "paNummer" (also nur wenige mit gleichen Wert), sollte meine Version nicht so schlecht abschneiden. Vertausche doch auch mal, falls du nochmal testest, bei meiner Unterabfrage die Bedingungen, also:

    SELECT paNummer, datum, lagerOrt
    FROM myTable mt
    WHERE NOT EXISTS (
        SELECT mt2.id
        FROM myTable mt2
        WHERE mt2.paNummer = mt.paNummer 
        AND   AND mt2.datum > mt.datum
    )
    

    Bei vielen unterschiedlichen "paNummer" sollte diese Version performanter sein.



  • Beim Sql-Server (MSDE 2000) funktioniert deine Version nicht -> offenbar Oracle-spezifischer Syntax beim IN-Operator.

    Meine Version läuft in geschätzt <0,1s. Mein Tool (DbaMgr2k) zeigt leider keine Zeiten an.


Anmelden zum Antworten