Gruppen anhand eines Wertes einer nicht gruppierten Spalte auswählen

Gruppen anhand eines Wertes einer nicht gruppierten Spalte auswählen

am 26.01.2007 23:07:29 von Andreas Fischer

Hallo zusammen!

(Nur am Rande:
Wegen Instantrails verwende ich gezwungenermassen noch mysql 4.1.9)

Für folgende vereinfachte Tabelle t_1

t_1:
============
id A B C
------------
1 1 1 1
2 1 1 1
3 2 1 1
4 2 2 2
5 2 5 5
6 3 1 1
7 3 5 5
============

möchte ich bei einer Gruppierung nach Spalte A und B die Größe
(Anzahl an Zeilen) jeder einzelnen Gruppe herausfinden, die einen
bestimmten Wert in der Spalte C enthält.
Wenn der gesuchte Wert der Spalte C zufällig der Maximalwert dieser
Spalte ist, liefert folgender Query sehr schnell das Ergebnis:

SELECT A,B,COUNT(C)
FROM t_1
GROUP BY A,B
HAVING MAX(C)=5

Das Problem:
Konkret bräuchte ich eine Version in der man Gruppen anhand eines
beliebigen Wertes von C auswählen kann und die unter realen Bedingungen
genauso oder vergleichbar schnell ist wie die obige Variante.

Ich dachte und denke eigentlich nach wie vor, dass das einfach möglich sein
müsste, habe aber bisher weder im Internet noch selbst eine praktikable
Lösung gefunden. (gescheiterte Versuche siehe unten)

Ausserdem würde mich sehr interessieren ob es prinzipiell irgendeine
Möglichkeit mittels SQL gibt direkt auf die Werte der "nicht-Group-By"-
Spalten innerhalb einer Gruppierung zuzugreifen, also die Werte auf die
z.B. Aggregate-Functions Zugriff haben müssen.
Oder muss ich dafür zwangsweise auf user defined functions zurückgreifen?

Dem Manual nach zu urteilen vermute ich mal das letzteres der Fall
sein wird, habe aber weder dort noch sonstwo im Netz eine für mich 100%
eindeutige Antwort dazu gefunden.
http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-field s.html


Falls das für jemanden von Interesse ist beschreibe ich noch kurz was
bei mir bisher nicht geklappt hat:

In einer Vorstufe zu meinem entsprechenden realen Problem habe ich
ca. 20000 Datensätze die bei einer Gruppierung nach "A" und "B" in
ca. 1000 Gruppen aufgeteilt werden.

Dafür habe ich drei funktionsfähige Varianten.
(Die Laufzeiten sind bei 20000 Datensätzen a 1000 Gruppen)

1. eine analoge zur obigen Version die 3 Sekunden braucht
2. eine Variante mit einem inner join die knapp eine Minute braucht:
(für den speziellen C-Wert, die Spalten A,B,C selektieren und mit
Zeilen
gleicher A und B-spalte aus t_1 joinen)
3. Eine Abänderung der 1.Variante mit Group by .. Having (A,B) In SELECT
.....
-- die 4 Minuten braucht

zu 1.:
wegen MAX() zu speziell => Unbrauchbar

zu 2. und 3.:

Ich vermute mal das das Verhältnis der Laufzeiten von
(1.) zu (2. und 3.) irgendwo bei
linear(1.) zu quadratisch und oder schlimmer(2.,3.) liegt

Laufzeit für 2. und 3.ist jedenfalls zu hoch und wird bei realeren,
grösseren Datenmengen wohl völlig inakzeptabel werden.



Gruß,
Andreas

Re: Gruppen anhand eines Wertes einer nicht gruppierten Spalte auswählen

am 27.01.2007 08:46:46 von dnoeth

Andreas Fischer wrote:

> t_1:
> ============
> id A B C
> ------------
> 1 1 1 1
> 2 1 1 1
> 3 2 1 1
> 4 2 2 2
> 5 2 5 5
> 6 3 1 1
> 7 3 5 5
> ============
>
> möchte ich bei einer Gruppierung nach Spalte A und B die Größe
> (Anzahl an Zeilen) jeder einzelnen Gruppe herausfinden, die einen
> bestimmten Wert in der Spalte C enthält.
> Wenn der gesuchte Wert der Spalte C zufällig der Maximalwert dieser
> Spalte ist, liefert folgender Query sehr schnell das Ergebnis:

SELECT A,B,COUNT(C)
FROM t_1
GROUP BY A,B
HAVING count(case when C = gesuchter_wert then C end) >= 1

Dieter

Re: Gruppen anhand eines Wertes einer nicht gruppierten Spalte auswählen

am 27.01.2007 20:05:47 von Andreas Fischer

Dieter Noeth wrote:
> SELECT A,B,COUNT(C)
> FROM t_1
> GROUP BY A,B
> HAVING count(case when C = gesuchter_wert then C end) >= 1

Super, vielen Dank,
wäre ich wahrscheinlich in 100 Jahren nicht drauf gekommen.

Gruß,
Andreas