MySQL Erst sortieren dann gruppieren

TheJavaKid

Top Contributor
Hallo!

Ich scheitere gerade etwas an einem alt-bekannten Problem:

Ich haben einen Query, in dem soll zuerst sortiert werden (order by ... desc) und dann gruppiert werden. Die Universallösung dafür laut Stackoverflow ist ein Subquery der in etwa so aussieht:

Code:
select * from
(select * from a order by column1 desc) as table
group by table.column2

Aber auch ohne dem group by funktioniert allein schon das sortieren im Subquery nicht (zumindest wird desc ignoriert). Ich habe mir jetzt mit einem where einem in(subquery) und max() geholfen... ist aber sehr unschön. (Distinct hilft übrigens auch nicht, weil es mehrere Spalten gibt, die selected werden.)

Gibt es für diese Sache nicht irgendeine elegantere Lösung? Im Grunde soll ja nur zuerst sortiert und dann gruppiert werden.
 

Thallius

Top Contributor
Also was du da machen willst ist eigentlich ein NoGo und funktioniert auch nur mit MySQL weil das toleranter ist als alle anderen Datenbanken. Das solltest du auf jeden Fall im Hinterkopf behalten wenn du denn tatsächlich den Weg weiter gehen willst. Ich denke eine Umstrukturierung der DB wäre der sauberere weg, wenn dir die augenblickliche Struktur nicht erlaubt eine Abfrage zu machen wie du sie brauchst.

Ich verstehe ehrlich gesagt nich warum distinct nicht funktionieren sollte. Du must halt ein distinct auf Column1 machen

Gruß

Claus
 

TheJavaKid

Top Contributor
Habe distinct schon versucht, da tut sich überhaupt nichts.

Wie sollte ich das anders machen?
Ich brauche den neusten Eintrag aus einer Tabelle, und neben der eigenen ID (a) gibt es noch eine weitere ID (b), die mit einer anderen Tabelle verknüpft ist, dabei dabei darf es aber nur einen Eintrag von dieser ID (b) geben, die auch mehrfach vorkommen kann. Was wäre die alternative Lösung?
 

Meniskusschaden

Top Contributor
Wahrscheinlich habe ich gerade ein Brett vor'm Kopf, aber ich habe deine beiden Postings in diesem Thread jetzt ein paar Mal gelesen und trotzdem nicht verstanden, was du überhaupt erreichen willst.
 

Thallius

Top Contributor
Also das klingt immer mehr nach einer schlechten DB Struktur aber ich kann im Moment noch nicht nachvollziehen was eigentlich das Problem ist. Zeig uns doch mal konkret deine Datenbank Struktur und was du mit dem quere erreichen willst. Dann können wir sicher helfen
 

TheJavaKid

Top Contributor
table1:
ID | Table2-ID | Datum
1 | 1 | 2017-10-11
2 | 1 | 2017-11-11
3 | 2 | 2017-8-9

table2:
ID | Name
1 | Name 1
2 | Name 2


Ich will bei meiner Abfrage, dass aus table1 die neusten Einträge angezeigt werden aber Table2-ID nur EINMAL vorkommt.

In diesem Fall wäre das:
2 | 1 | 2017-11-11 | Name 1
3 | 2 | 2017-8-9 | Name 2

Sehe da keinen Fehler an meiner Struktur.
 

Meniskusschaden

Top Contributor
So etwas in der Art könnte vielleicht funktionieren:
Code:
select table1.ID, max(Datum), table2.Name
from table1
join table2
on table1.Table2-ID = table2.ID
group by table1.ID
 

TheJavaKid

Top Contributor
Die einzige Möglichkeit, wie es bisher funktioniert ist die:

Code:
select * from
table1
where datum = (select max(datum) from table1 group by table2id)
order by
datum desc

Aber das kanns doch nicht sein, dass es im Jahr 2017 für so eine einfache Aufgabe keine bessere Lösung gibt als so eine hässliche.
 

Meniskusschaden

Top Contributor
Ich glaube, da waren noch IDs verdreht. Versuch mal folgendes:
Code:
select table2.ID, max(Datum), Name
from table1
join table2
on table1.Table2-ID = table2.ID
group by table2.ID

EDIT: Ich meine mit den verdrehten IDs mein vorheriges Posting. Hat sich überschnitten.
 

thecain

Top Contributor
Code:
select table2.ID, t1.Datum, table2.Name
from table1 t1
left join table1 t2
on  t1.datum > t2.datum AND t1.ID =t2.ID
LEFT JOIN table2 on t1.Table2-ID = table2.ID
WHERE t2.datum IS NULL

Sowas müsste gehen mMn... sonst mach mal ein JSFiddle Beispiel, das ist ein bisschen SQL ins blaue so
 

Meniskusschaden

Top Contributor
Ich habe es jetzt mal mit den Beispieldaten aus Posting #6 nachgebaut. Mein Vorschlag aus Posting #12 und der von @thecain aus Posting #15 funktionieren meines Erachtens beide prinzipiell richtig (bei letzterem musste ich im ersten Join nur noch die IDs durch die table2-IDs ersetzen).

Wenn das Folgende wirklich funktioniert, reden wir vermutlich aneinander vorbei (bei mir funktioniert es so jedenfalls noch nicht):
Die einzige Möglichkeit, wie es bisher funktioniert ist die:
Code:
select * from
table1
where datum = (select max(datum) from table1 group by table2id)
order by
datum desc
 

TheJavaKid

Top Contributor
Es hat bisher nichts funktioniert... (Übrigens auch meine bisherige Lösung hatte Fehler)
Ich hab jetzt eine weitere Tabelle als Hilfe erstellt, mit der es jetzt funktioniert. Es ärgert mich nur, dass ich diese extra brauche, nur weil ich zuerst sortieren und erst dann gruppieren will... Ich meine, das ist wirklich nicht zu viel was ich von einer Datenbank erwarte...
 

Meniskusschaden

Top Contributor
Es hat bisher nichts funktioniert...
Tja, was soll man dazu noch sagen? Es gibt hier bereits funktionierende Vorschläge, die die Anforderungen aus Posting #6 erfüllen. Du hast sie entweder falsch umgesetzt oder deine Anforderung falsch beschrieben. Solange man nichts Konkreteres als "funktioniert nicht" hört, wird man kaum klären können, wo dein Fehler liegt.
Ich meine, das ist wirklich nicht zu viel was ich von einer Datenbank erwarte...
Nein, aber vielleicht doch etwas zu wenig, was du von dir selbst verlangst.;)
 

Tobse

Top Contributor
Ich hatte dieses Problem auch schon. Und ich meine, dass das Datenbankdesign nicht schlecht war, denn es hat für einen haufen anderer komplzierter Anforderungen wunderbar funktioniert.

Das Problem ist, dass GROUP BY immer vor ORDER ausgeführt wird. Auch Subqueries und Views helfen da nichts. Die einzige Möglichkeit ist, dass die Datensätze bereits sortiert aus der Datenquelle gelesen werden. Das kann man mit einer eigenen Tabelle erreichen (wie der OP es gemacht hat) oder mit einem Sortierten Index, welcher das Order By ersetzt. Beides ist ein ziemlich ekliger Hack - aber ohne umstrukturierung der DB die einzige Lösung.
 

Meniskusschaden

Top Contributor
Ich glaube, @stg hat mit seinem Verweis auf das XY-Problem den Nagel auf den Kopf getroffen. Warum wollt ihr denn unbedingt sortieren? Wenn man die Anforderung aus #6 übersetzt, besagt sie doch nur, dass jeder Zeile aus table2 die passende Zeile aus table1 zugeordnet werden soll, wobei "passend" bedeutet, dass die ID übereinstimmen und das Datum maximal sein muß. Also sagt man das der Datenbank einfach. Die kann doch selbst sehen, wie sie das hinkriegt. Es ist doch gerade das Bequeme an SQL, dass man nur beschreiben muß, WAS man haben möchte und nicht, WIE das beschafft werden muß.
 

Meniskusschaden

Top Contributor
Ich habe hier mal das Beispiel aus #6 um eine vierte Zeile für table1 ergänzt. Daran müsste man es sehen:
Code:
table1:
ID | Table2-ID | Datum
1 | 1 | 2017-10-11
2 | 1 | 2017-11-11
3 | 2 | 2017-8-9
4 | 1 | 2017-8-9

table2:
ID | Name
1 | Name 1
2 | Name 2
 

Thallius

Top Contributor
Ich habe hier mal das Beispiel aus #6 um eine vierte Zeile für table1 ergänzt. Daran müsste man es sehen:
Code:
table1:
ID | Table2-ID | Datum
1 | 1 | 2017-10-11
2 | 1 | 2017-11-11
3 | 2 | 2017-8-9
4 | 1 | 2017-8-9

table2:
ID | Name
1 | Name 1
2 | Name 2

Hättest du dir die Mühe gemacht das im Fiddle zu testen hättest du gesehen das das immer noch geht ;)
 

Meniskusschaden

Top Contributor
Hättest du dir die Mühe gemacht das im Fiddle zu testen hättest du gesehen das das immer noch geht ;)
Ich hatte es sogar getestet, habe dabei aber offenbar auf einen falschen TAB geklickt und stattdessen ein altes Statement von mir erwischt.:oops: Mein Posting #23 ist demzufolge völliger Unsinn.

Deinen Vorschlag aus #21 habe ich inzwischen auch ausprobiert und er funktioniert ebenfalls einwandfrei. Nach meiner Zählung haben wir damit bereits drei Lösungen, die ohne Zusatztabelle auskommen.
 

TheJavaKid

Top Contributor
Folgendes funktioniert auf jeden Fall

SELECT t2.name, t1.date
FROM t2
LEFT JOIN t1 ON t1.id = (SELECT t1.id FROM t1 WHERE t1.t2id = t2.id ORDER BY t1.date DESC LIMIT 1);

http://sqlfiddle.com/#!9/9ea8a5/22

Da brauchste zwar immer noch einen subquery aber dafür kein MAX und keine weitere Tabelle.

Gruß

Claus
Ja das sieht gut aus. Wieso ich nicht dran gedacht hab order by im Subquery zu verwenden statt max(date) und die IDs zu prüfen ist mir gerade auch schleierhaft. Ich werd das ganze Mal einbauen und schauen, ob es so allen Umständen standhält.

Btw: Die zusätzliche Tabelle ist eigentlich Optional, da ich eigentlich nur eine weitere Spalte brauche und die könnte ich in table2 einbauen. Aber das gefällt mir nicht, das hat persönliche Gründe. Deswegen die extra-Tabelle; eigentlich gehts nur um eine extra Spalte.

Und nein, das XY-Problem trifft hier nicht zu. Es ist genau so beschrieben, wie ich es brauche und Thallius hat die richtige Lösung dazu geliefert. Das ist alles. ^^
 

TheJavaKid

Top Contributor
Eine kleine Ergänzung zu Thallius Query, die noch gefehlt hat: Am Ende gehörte noch ein Order By t1.date desc hin, dann läuft es genauso wie ich es wollte. Danke!
 

Meniskusschaden

Top Contributor
Und nein, das XY-Problem trifft hier nicht zu. Es ist genau so beschrieben, wie ich es brauche und Thallius hat die richtige Lösung dazu geliefert. Das ist alles. ^^
Na ja, immerhin erschienen dir die anderen Lösungen offenbar als so abwegig, dass du nicht mehr als ein "funktioniert nicht" dafür übrig hattest. Sieht ja schon nach irgendeiner Art von Blockade aus.;)

Jetzt würde mich aber doch interessieren, bei welcher Datenkonstellation du für diese Abfrage:
Code:
SELECT t2.name, max(t1.date)
FROM t1
JOIN t2 ON t1.t2id = t2.id
GROUP BY t2.id
ORDER BY t1.date DESC;
ein anderes Ergebnis erhältst als für diese:
Code:
SELECT t2.name, t1.date
FROM t2
LEFT JOIN t1 ON t1.id = (SELECT t1.id FROM t1 WHERE t1.t2id = t2.id ORDER BY t1.date DESC LIMIT 1)
ORDER BY t1.date DESC;
Das kann doch eigentlich nur bedeuten, dass du auch für die t2-Zeilen, die keinen passenden t1-Satz haben, eine Ergebniszeile haben willst (mit Datum NULL). Das ging zwar aus deiner ursprünglichen Anforderung nicht hervor, lässt sich aber im ersten Query ebenso leicht einbauen wie es sich aus dem zweiten Query ausbauen lässt, falls es doch unerwünscht sein sollte. Oder gibt es noch andere Unterschiede?
 

TheJavaKid

Top Contributor
Es sollte ganz einfach aus t2 die Zeile zuerst hervorkommen, die, verknüpft mit der t1 Tabelle, laut der Datumsangabe der t1 Tabelle, der neuste Eintrag ist. Und es sollte darauf geachtet werden, dass von einer Zeile in t2 nur eine Zeile gleicher ID hervorkommt. Einfach nur max(date) hat nicht geholfen; ich hab das wie gesagt schon probiert. Die Ergebnisse kommen in der falschen Reihenfolge raus.Warum das so ist kann ich dir nicht erklären; vielleicht lags auch an mir und ich hab irgendwo einen Bock geschossen beim Übertragen; wie man sich denken kann heißen die betreffenden Tabellen natürlich nicht t1 und t2, ich hab das ganze Konstrukt vereinfacht für die Problembeschreibung hier. Aber es ist mir mit dem Subselect lieber als eine Max-Funktion. Noch lieber wärs mir natürlich wenn ich sagen könnte: order by date group by table2id aber das ist wohl noch zu hohe Technik für mysql :D
 

Meniskusschaden

Top Contributor
Die Ergebnisse kommen in der falschen Reihenfolge raus.Warum das so ist kann ich dir nicht erklären;
Dass die Ergebnisse auch nach dem Datum sortiert sein sollen, hast du erst ganz zum Schluss erwähnt (ich glaube in #29). Da hättest du vermutlich auch einfach ein ORDER BY an das Query deines Eröffnungspostings hängen können (wie bei allen anderen Lösungen auch).
ORDER BY bezieht sich immer auf die Datenmenge des korrespondierenden SELECT auf derselben Ebene. Hier gibt es also zwei Aufgaben dafür: die Ergebnismenge des äußeren SELECT zu sortieren und dafür zu sorgen, dass die jeweils richtige Zeile innerhalb des inneren SELECT zuerst kommt. Dementsprechend ist es auch nötig und sinnvoll, ORDER BY zwei Mal anzugeben. Es könnte ja ebenso gut sein, dass die Ergebnisse z.B. nach Name oder ID sortiert sein sollen und dass trotzdem das neueste Datum maßgeblich ist.
 

TheJavaKid

Top Contributor
Das weiß ich alles und ja, das war mein Fehler, dass ich davon ausgegangen bin das seie eh logisch, wie ich das meine. Also wie gesagt es sollten natürlich auch die Endergebnisse sortiert werden. Jetzt kennen wir das Problem, wo wir aneinander vorbeigeredet haben ^^ Das Sortieren des Subqueries ist im Prinzip ja nur ein unvermeidbarer Nebeneffekt, um die neusten Einträge zu bekommen anhand derer dann die Ergebnisse aus t2 kommen. Worum es mir aber immer die ganze Zeit gegangen ist war auch und vor allem die Endergebnisse zu sortieren
 

Ähnliche Java Themen


Oben