# JTable mit GROUP BY



## Dreamdancer (25. Mrz 2010)

Ist es möglich, die Sortierung einer JTable (mit den RowSortern) mit einem Group By (wie bei SQL) zu erweitern?
Also die Sorter sind die table.setAutoCreateRowSorter(true); Die machen genau das, was ich möchte (mehrere Sortierungen nach Reihenfolge der Auswahl priorisieren). Nun hätte ich aber gerne, dass unabhängig von der Sortierung, eine Gruppierung in der x.ten Spalte stattfindet.

Beispiel: Es soll nach Spalte 3 gruppiert werden. Ich sortiere nach der 0. Spalte. Die 0. Reihe besteht nun aus dem ersten Ergebnis der Sortierung. Die Reihe 1 aus der Reihe, die in Spalte 3 den gleichen Wert besitzt wie Reihe 0, ansonsten das zweite Ergebnis der Sortierung. Etc. und so fort.

Ich bin gerade dabei, mir eine eigene Klasse zu schreiben, die mir das macht, wollte aber wissen, ob es sowas vielleicht einfacher geht? Meine Recherche im Netz hat nichts einfacheres ergeben.

Viele Dank und Grüße


----------



## Michael... (25. Mrz 2010)

Dreamdancer hat gesagt.:


> Beispiel: Es soll nach Spalte 3 gruppiert werden. Ich sortiere nach der 0. Spalte. Die 0. Reihe besteht nun aus dem ersten Ergebnis der Sortierung. Die Reihe 1 aus der Reihe, die in Spalte 3 den gleichen Wert besitzt wie Reihe 0, ansonsten das zweite Ergebnis der Sortierung. Etc. und so fort.


???? Verstehst Du selbst was Du da willst? ;-)

Also ich deute das eher so, dass Du nicht Gruppieren willst, sondern, nach Spalte 3 sortieren und innerhalb dieser Sortierung soll nach Spalte 1 sortiert werden?!?


----------



## Dreamdancer (25. Mrz 2010)

Nein ich möchte keine Sortierungen verschachteln, ich möchte Gruppieren, also alle Zeilen, die in einer bestimmten Spalte den gleichen Wert haben, sollen untereinanderstehen (nicht zwangweise sortiert nach dieser Spalte).


----------



## Michael... (25. Mrz 2010)

Dreamdancer hat gesagt.:


> Nein ich möchte keine Sortierungen verschachteln, ich möchte Gruppieren, also alle Zeilen, die in einer bestimmten Spalte den gleichen Wert haben, sollen untereinanderstehen (nicht zwangweise sortiert nach dieser Spalte).


Aber das ist doch eine Sortierung. Eine Gruppierung ist ja ein Zusammenfassen mehrerer Zeilen in Verbindung mit einer Aggregatfunktion (z.B. Summe, Mittelwert...)


----------



## Dreamdancer (25. Mrz 2010)

Mh, sehe ich nicht so. Eine Sortierung ist eine Anordnung nach einem Vergleich (compareTo, <, >, etc.)

Beispiel:

2, m
2, k
1, l
1, n

Ich möchte nach der 0. Spalte gruppieren (stets) und nach der 1. sortieren (nach Click).
Click:
2, k
2, m
1, l
1, n

Also die Gruppierung in der 0. Spalte bleibt bestehen und ist wichtiger als die Sortierung in der 1. Spalte. Hier sieht man auch, dass es eine GRUPPIERUNG ist und keine Sortierung, weil die 2 vor der 1 kommt, einfach weil das k vor dem l kommt


----------



## Dreamdancer (25. Mrz 2010)

Natürlich könnte man nun auch nach der Gruppierung sortieren, wodurch die Sortierung nach der Gruppierung die erste Priorität bekommt und das ganze so aussieht:

1, l
1, n
2, k
2, m

1. Priorität: Sortierung nach Gruppierung (0. Spalte)
2. Priorität: Sortierung nach Buchstabe (1. Spalte), was ja vorher geclickt wurde (wie üblich)


----------



## Michael... (25. Mrz 2010)

Dreamdancer hat gesagt.:


> Ich möchte nach der 0. Spalte gruppieren (stets) und nach der 1. sortieren (nach Click).
> Click:
> 2, k
> 2, m
> ...


Das ist eine aufsteigende Sortierung nach Spalte 2 mit anschliessend absteigender Sortierung nach Spalte 1


----------



## Dreamdancer (25. Mrz 2010)

Nein, das ist Zufall. Vertausche 1 und 2 und es wird trotzdem das gleiche rauskommen (bzgl. der 1. Spalte). Das ist nur eine Sortierung nach der 1. Spalte und eine Gruppierung nach der 0. Spalte.
Wenn Du GROUP BY von SQL kennst, weißt Du was ich meine.


----------



## Michael... (25. Mrz 2010)

Wie soll denn dieses Statement ausschauen?


----------



## Dreamdancer (25. Mrz 2010)

Ich verwende JTables, es gibt kein Statement. Zumindest abstrahiere ich davon. Es geht alleine um die Funktion des GROUP BY, die ich suche und nicht finde :autsch:


----------



## Dreamdancer (25. Mrz 2010)

Ok ich habe es nun implementiert, trotzdem danke ;-)

Ich sortiere die Tabelle nun mit den Standard-RowSortern und danach gehe ich sie von oben bis unten durch und grabsche mir die Reihen nach oben, wenn sie in der Spalte, die gruppiert werden soll, doppelte Werte hat.

Mich würde trotzdem interessieren, ob es auch feiner geht ...


----------



## faetzminator (25. Mrz 2010)

In welcher Reihenfolge soll das "Group By" geschehen? Alphabetisch oder numerisch schon Mal nicht. Nach der Anzahl der Elemente mit aktuellem "Gruppenwert"? Nach einer vordefinierten Liste?


----------



## Dreamdancer (25. Mrz 2010)

Das Group By geschieht nach der Reihenfolge des Wertes, welches sortiert wird. Also ich sortiere die Tabelle ganz normal und der erste Wert, der in der Tabelle steht, gibt die erste Gruppierung vor.

Die Gruppierungen sind dann in sich wieder in der Reihenfolge der Sortierung geordnet.


----------



## faetzminator (25. Mrz 2010)

und wieso schreibst du dir da nicht einen eigenen Comparator?


----------



## Dreamdancer (26. Mrz 2010)

Nun auf die Idee bin ich nicht gekommen, da ich ja nicht zwei Elemente vergleiche, sondern zwei Elemete in zwei Zeilen vergleiche und danach sortiere (das ist ja schon korrekt implementiert in Java) und dazu noch gruppieren möchte.
Mir fehlt der Ansatz, wie ich einen Comparator dafür einsetzen könnte.


----------



## 0x7F800000 (26. Mrz 2010)

Ähm... Könnte natürlich sein, dass mein SQL inzwischen wieder ein bisschen hinkt, aber GROUP BY hatte dort afair nichts mit der sortierung zu tun, sondern es diente der unterteilung der Einträge in Äquivalenzklassen, und anschließender Anwendung einer *Aggregatfunktion* auf die jeweilige Äquivalenzklasse. 

Beispiel:

```
SELECT first_col,AVG(second_col) 
FROM {(x,0),(y,1),(x,2),(x,3),(x,3),(y,2)}
GROUP BY first_col
```
würde bedeuten, dass man zwei Äquivalenzklassen (eine für [c]x[/c] und eine für [c]y[/c]) kriegt, für die dann jeweils die Durschnittswerte ausgerechnet werden, etwa [c]{(x,2),(y,1.5)}[/c].

Was du die ganze Zeit meintest, war aber was ganz anderes, nämlich Sortierung mit einer Lexographischen Ordnung.

Wie wärs mit sowas?

```
import java.util.*;

//lexographische Ordnung, zusammengebaut aus vielen einzelnen ordnungen
class Lex<X> implements Comparator<X>{
	
	private List<Comparator<X>> comparators;
	
	public Lex(Comparator<X>... comps){
		comparators = Arrays.asList(comps);
	}
	
	@Override
	public int compare(X a, X b) {
		for(Comparator<X> c:comparators){
			int res=c.compare(a,b);
			if(res!=0){
				return res;
			}
		}
		return 0;
	}
}

//das soll die zu sortierenden Objekte symbolisieren
class Entry{
	public int id;
	public String name;
	public int $;
	
	private static int idCnt = 0;
	
	public Entry(String n, int dollarz){
		id = idCnt++;
		name=n;
		$=dollarz;
	}
	
	@Override public String toString(){return id+"\t"+name+"\t"+$;}
}

//beispiel
public class LexOrderExample{
	@SuppressWarnings("unchecked")
	public static void main(String..._){
		Entry[] entries = {
				new Entry("Peter",100),
				new Entry("Manfred",200),
				new Entry("Manuel",100),
				new Entry("Karl",100),
				new Entry("Peter",100),
				new Entry("Karl",100),
				new Entry("Manfred",50),
				new Entry("Manuel",50),
				new Entry("Peter",200),
				new Entry("Karl",200),
		};
		
		//zuerst nach kohle absteigend, dann nach namen aufsteigend sortieren
		Comparator<Entry> lex = new Lex<Entry>(
			new Comparator<Entry>(){
				@Override public int compare(Entry a, Entry b){return b.$-a.$;}
			},
			new Comparator<Entry>(){
				@Override public int compare(Entry a, Entry b){return a.name.compareTo(b.name);}
			}
		);
		
		Arrays.sort(entries,lex);
		
		for(Entry e:entries){
			System.out.println(e);
		}
		
	}
}
```

Ergebnis:

```
9	Karl	200
1	Manfred	200
8	Peter	200
3	Karl	100
5	Karl	100
2	Manuel	100
0	Peter	100
4	Peter	100
6	Manfred	50
7	Manuel	50
```
Meintest du das?


----------



## Dreamdancer (26. Mrz 2010)

Das sieht gut aus, aber sowas hatte ein Vorhelfer schon vorgeschlagen. Das ist nicht das, was ich meine, weil jetzt zwangsweise eine Sortierung nach Geld stattfindet, die nicht gewollt ist. Ich nehme mal das gleiche Beispiel...

Ich sortiere nach Namen und es KANN folgendes rauskommen:

9	Karl	200
1	Manfred	200
8	Peter	200

3	Karl	100
5	Karl	100
2	Manuel	100
0	Peter	100
4	Peter	100

6	Manfred	50
7	Manuel	50

Es könnte aber auch folgendes rauskommen (je nach Sortierung und dessen Priorisierung der anderen 20 Spalten):

3	Karl	100
5	Karl	100
2	Manuel	100
0	Peter	100
4	Peter	100

9	Karl	200
1	Manfred	200
8	Peter	200

6	Manfred	50
7	Manuel	50

,da ID 3 und 9 beide Karl heißen. Wichtig ist nur, dass die Gruppierung in sich geschlossen dargestellt wird. Wenn man sich jetzt ein Beispiel mit 20 Spalten vorstellt, wo mehrere Sortierungen priorisiert werden können, kann man sich denken, dass es immer unwahrscheinlicher wird, dass zufällig die Spalte mit der Grupperiung sortiert dargestellt wird.
Natürlich KANN man auch nach den Gruppierungen sortieren, es soll aber nicht standardmässig im Algorithmus stattfinden, sondern extra durch Click auf den Spaltenheader.

Eine weitere Crux an der Sache ist, dass eine Unterteilung in Teilmengen (Gruppen) nicht effizient ist, da eine Gruppe aus maximal 4 Einträgen besteht.


----------



## Roxa (26. Mrz 2010)

Also auch wenn du es nicht hören willst aber 0x7F800000 hat Recht.

Seine Lösung mag zwar nicht das Ergebnis bringen, dass du haben willst aber GROUP BY steht in SQL nicht dafür, dass man bestimmte Spalten mit gleichen Inhalt untereinander darstellt. Viel mehr blendet der GROUP BY ggf. sogar Zeilen aus. 

Beispiel:

Tabelleninhalt:

AA    BB    CC
----- ----- -----
aaaaa bbbbb ccccc
aaaaa bbbbb ccccc
aaaaa bbbbb ccccc
aaaaa bbbbb ccccc
a1a1a b1b1b c1c1c
a1a1a b1b1b c1c1c
a1a1a b1b1b c1c1c
a1a1a b1b1b c1c1c
a1a1a b1b1b c1c1c
a1a1a b1b1b c1c1c

select aa,bb,cc from tabxx group by aa,bb,cc;

AA    BB    CC
----- ----- -----
a1a1a b1b1b c1c1c
aaaaa bbbbb ccccc

Und bei Oracle ist es sogar so dass ich im group by hier auch alle Spalten aus dem SELECT anzeigen muss.


----------



## 0x7F800000 (26. Mrz 2010)

Dreamdancer hat gesagt.:


> Es könnte aber auch folgendes rauskommen (je nach Sortierung und dessen Priorisierung der anderen 20 Spalten)



Ich kapier nicht, was du willst. Wenn du zB $ in blöcke unterteilen willst, und diese unterteilung die erste priorität hat, dann ist die sortierung nach irgendeinem anderen kriterium dahin.

Wenn du alles nach irgendeiner Spalte sortieren willst, dann ist diese block-struktur bei $ dahin.

Beides gleichzeitig geht nicht. Beispiel:

x $
1 1
2 0
3 1

Klar: sortiert man nach x, sind die Einsen getrennt, unterteilt man in Blöcke, ist die Sortierung nach x dahin. Beides kann man einfach nicht haben. Was willst du also? :autsch:


----------



## Dreamdancer (26. Mrz 2010)

Also Du hast recht, in SQL ist das GROUP BY nicht das, was ich meine, war mein Fehler.

Geht nicht gibts nicht. Ich habe es ja wie gesagt schon implementiert. Ich wollte nur wissen, ob es einen elegantenteren Weg gibt, vielleicht ist das ja schon in einem Sorter implementiert oder ähnliches.

Ich habe es so gemacht: 
-0- Zuerst nach der gewählten Sortierwünschen die Tabelle sortiert. 
-1- Fange bei der 0. Zeile an
-a- markiere Zeile, lese den Gruppierungswert und durchsuche die Tabelle abwärts bis zum Ende nach diesen Wert​- WENN (Wert nochmal gefunden) THEN (verschiebe Reihe unter der letzten markierten Zeile, markiere diese verschobene Zeile)​-2- markiere die nächsten Zeile unter der letzte markierten Zeile und fahre mit -1- fort




0x7F800000 hat gesagt.:


> Ich kapier nicht, was du willst. Wenn du zB $ in blöcke unterteilen willst, und diese unterteilung die erste priorität hat, dann ist die sortierung nach irgendeinem anderen kriterium dahin.



Wieso? Man kann doch mehrere Sortierungen priorisieren? Ist doch Standard bei JTables.



0x7F800000 hat gesagt.:


> Wenn du alles nach irgendeiner Spalte sortieren willst, dann ist diese block-struktur bei $ dahin.



Nein, wie in meinem Beispiel gezeigt. Die Block-Struktur hat oberste Priorität, aber die Priorisierung der Sortierung auf der Block-Struktur wird standard-mäßig behandelt.


----------



## 0x7F800000 (26. Mrz 2010)

Dreamdancer hat gesagt.:


> Geht nicht gibts nicht.


Dann find' mal eine Zahl, die gleichzeitig gerade und ungerade ist?
Für mich sieht's nämlich so aus, als ob du entweder etwas unmögliches willst, oder es zu verwirrend erklärst...



> Ich habe es so gemacht:
> -0- Zuerst nach der gewählten Sortierwünschen die Tabelle sortiert.
> -1- Fange bei der 0. Zeile an
> -a- markiere Zeile, lese den Gruppierungswert und durchsuche die Tabelle abwärts bis zum Ende nach diesen Wert​- WENN (Wert nochmal gefunden) THEN (verschiebe Reihe unter der letzten markierten Zeile, markiere diese verschobene Zeile)​-2- markiere die nächsten Zeile unter der letzte markierten Zeile und fahre mit -1- fort


Also hast du einfach nach dem "ersten Index des Auftretens des Gruppierungswertes" sortiert, oder was?... Wozu? Hat diese "Ordnung" in freier Wildbahn irgendeine sinnvolle Funktion oder wenigstens irgendeinen ästhetischen Wert? So werden die Blöcke doch nur durcheinandergeworfen?

obwohl.. Naja, wenn man sich so eine Schlange an der Kasse vorstellt, wo sich leute zu ihren Bekannten vordrängeln, dann benehmen sie sich tatsächlich so, wie du das beschrieben hast. 

Nur fällt mir spontan nicht ein wohin mit sowas^^

Also, für das was du willst, könntest du den ersten angegebenen Comparator beim zweiten Sortier-Durchlauf verwenden. Man muss da zwei durchläufe machen, da das Verhalten des "Block-Comparators" ja vom Verhalten des "Ersten-Sortier-Comparators" abhängt... 

Naja, seltsames Problem verwirrend beschrieben :bahnhof:


----------



## Dreamdancer (26. Mrz 2010)

0x7F800000 hat gesagt.:


> Dann find' mal eine Zahl, die gleichzeitig gerade und ungerade ist?



Erzählst Du das auch Deinen Kunden, wenn sie mit einen Auftrag an Dich herantreten, den Du auf den ersten Blick schwierig findest? Immerhin habe ich es an einem Tag programmiert, ich wollte nur wissen, ob es auch besser geht.



0x7F800000 hat gesagt.:


> Also hast du einfach nach dem "ersten Index des Auftretens des Gruppierungswertes" sortiert, oder was?... Wozu? Hat diese "Ordnung" in freier Wildbahn irgendeine sinnvolle Funktion oder wenigstens irgendeinen ästhetischen Wert? So werden die Blöcke doch nur durcheinandergeworfen?



Sie hat einen Sinn, sonst würde ich mich nicht damit beschäftigen. Stell Dir vor, Du disponierst Züge und in einer Tabelle stehen alle Züge, mit denen Du zu tun hast. Aber noch mehr: In einer Tabelle stehen alle Wagons, mit denen Du zu tun hast. Dann gibt es eine Spalte die heißt "Zugverband" und alle Wagons, die zu einer Linie gehören, haben eine gleiche Bezeichnung in dieser Spalte.
Wenn ich jetzt zum Beispiel nach den Vornahmen des Fahrers sortiere, der seinen Dienst auf einem Zug tut, ist klar, dass er nur im Triebfahrzeug steht, die anderen Wagons haben keinen Fahrer. Trotzdem möchte ich, dass die Wagons unter dem Triebfahrzeug stehen, weil das nunmal in der Zugdisposition seit Jahrzehnten so gehandhabt wird und schon mehrfach von verschiedenen Firmen in Programmen implementiert wurde.
Das ist der Hintergrund.




0x7F800000 hat gesagt.:


> obwohl.. Naja, wenn man sich so eine Schlange an der Kasse vorstellt, wo sich leute zu ihren Bekannten vordrängeln, dann benehmen sie sich tatsächlich so, wie du das beschrieben hast.



Zum Beispiel.



0x7F800000 hat gesagt.:


> Nur fällt mir spontan nicht ein wohin mit sowas^^



Macht ja nichts.



0x7F800000 hat gesagt.:


> Also, für das was du willst, könntest du den ersten angegebenen Comparator beim zweiten Sortier-Durchlauf verwenden. Man muss da zwei durchläufe machen, da das Verhalten des "Block-Comparators" ja vom Verhalten des "Ersten-Sortier-Comparators" abhängt...



Jetzt verwirrst Du mich.
Solange ich nicht auf den Header mit dem Gruppierungswert, soll nicht nach der Gruppierung sortiert werden. Das ist das Problem. Wenn ich einfach zwei Sortiervorgänge starte, wird die Gruppierung stets mitsortiert.

Auf den konkreten Fall bezogen:

Wenn ich zuerst nach dem Liniennamen sortiere (gruppiere), und dann nach dem Fahrernamen sortiere, wird mir meine Gruppierung zerstört, weil nur Triebfahrzeuge Fahrer haben und diese oben stehen und die Wagons stehen unten in der Tabelle.
Wenn ich zuerst nach Fahrer sortiere und dann nach dem Liniennamen (gruppiere), dann wird nach dem Namen der Linie sortiert, also Linie A kommt vor Linie B kommt vor Linie C etc., was aber nicht gewünscht ist, weil ich nach Fahrernamen sortieren möchte.


----------



## Michael... (26. Mrz 2010)

Deine Anforderungen entsprechen ja keiner Standardsortierung oder Gruppierung. Sowas muss man dann selbst implementieren, was Du - wenn ich das richtig verstanden habe - auch gemacht hast.

Alternativ könnte man sich auch überlegen, ob man nicht eine Sicht auf die Daten generieren kann, auf die man solche Standardalgorithmen anwenden kann. Dazu müsste man sich aber mit einem konkreten Fall auseinander setzen.


----------



## Dreamdancer (26. Mrz 2010)

Eine weitere Idee von mir ist gewesen, einen Zugverband als ein Objekt zu handhaben. Wird es in die JTable geschrieben und hat zum Beispiel 3 Wagons inne, gibt die JTable drei Zeilen für das Objekt wieder (Analogie .toString() -> .toJTable() ).

Aber die Lösung war schneller, nachbessern kann ich immernoch, wenns muss 

Trotzdem Danke an alle.


----------

