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.1Dank 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 ErgebnisseTrotzdem 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 egalDanke
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 funztfä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.
-
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:
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.