SQL Abfrageproblem

lalo

Aktives Mitglied
Hallo,

ich habe gerade eine Denkblockade und weiß nicht so recht weiter, vielleicht kann mir ja hier jemand einen Tipp geben ?! ;-)

Ich habe eine Tablle ratings und locations, in der Tabelle ratings befinden sich die Bewertung der jeweiligen locations, soweit so gut.

Die votings in der Tabelle ratings sind nach folgendem Muster abgelegt :

id, vote_value, vote_idlocation, etc.. (für jede Bewertung ein Datensatz)

Mit meiner Abfrage :

SELECT *, sum(vote_value) as gesamt, count(vote_value) as anzahl
FROM ratings, locations
WHERE id_location = vote_idlocation
GROUP BY vote_idlocation
ORDER BY gesamt DESC 5";

bekomme ich zwar die 5 mit den meisten Gesamtpunkten raus, was ich aber haben will, sind die mit den 5 besten Durchschnittsbewertungen.

Also gesamt / anzahl und danach halt sortiert, quasi ein .."ORDER BY Durchschnitt".

Geht das so überhaupt in einer Abfrage ? Ich komme da gerade irgendwie nicht weiter.. :-(
 
Ohne mal über den Ansatz und die Struktur zu diskutieren geht dass z.B. so:
CODE
SELECT *, sum(vote_value) as gesamt, avg(vote_value) as schnitt, count(vote_value) as anzahl
FROM ratings, locations
WHERE id_location = vote_idlocation
GROUP BY vote_idlocation
ORDER BY schnitt DESC, gesamt DESC 5";



Würde dann noch zusätzlich absichern dass nur ab einer bestimmten Anzahl Votings gezählt wird (Stichwort: Having). Sonst ist ein Element, dass nur ein einzelnes, maximales Voting erhalten hat automatisch vorne.

BTW; Wenn du oder dein Hoster mal die mySQL-Version anhebt wird das Query nicht mehr funktionieren so. Die art des Joins muss neu immer über inner/outer Join laufen.
 
Danke für die schnellen Antworten !

@Alonso genau das hat mir gefehlt ! Mit dem Having haste recht, habe ich gleich mit eingesetzt !

PS: Ab welcher Version soll das denn nicht mehr funktionieren ? Mit Mysql 5 geht es bis jetzt ohne Probleme?
 
So etwas

QUOTE SELECT *
...
GROUP BY vote_idlocation


zeigt, daß man mySql nicht als Sql-Datenbank bezeichnen sollte.

Group By heißt, daß viele Zeilen zu einer Zeile zusammengefaßt werden.

Wenn man aber nach der Identitätsspalte gruppiert, dann verliert die Gruppierung jeglichen Sinn, weil dann die Zahl der Ergebniszeilen (abgesehen von TOP-Einschränkungen) gleich der Zahl der Ausgangszeilen ist.
 
lalo

Sorry, hatte einen Denkfehler. Ist erst ab 3 Tabellen relevant.

QUOTE "[Prior to MySQL 5.0.12], the comma operator (,) and JOIN both had the
same precedence, so the join expression t1, t2 JOIN t3 was interpreted
as ((t1, t2) JOIN t3). Now JOIN has higher precedence, so the expression
is interpreted as (t1, (t2 JOIN t3)). This change affects statements
that use an ON clause, because that clause can refer only to columns in
the operands of the join, and the change in precedence changes
interpretation of what those operands are."

So this query:
SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);
should be rewritten as:
SELECT * FROM (t1, t2) JOIN t3 ON (t1.i1 = t3.i3);
or:
SELECT * FROM t1 JOIN t2 JOIN t3 ON (t1.i1 = t3.i3);
</tip>



Ich fahre grundsätzlich immer nach der dritten Variante (explizit über Joins).

jauer;
Teilweise einverstanden. Auch dein geliebter MSSQL-Server würde in diesem Fall die Aggregatsfunktionen pro Identitätsspalte (bzw Location) anwenden, und die Votings jeweils aggregieren, was ja auch gewünscht ist hier. Nur müsst eman halt dort die Elemente aus der Identitätstabelle (locations) noch explizit (und natürlich auch korrekterweise) in die Group by Klausel einbinden. mySQL ist dort halt etwas tolleranter und liefert den ersten Treffer zurück. Ist aber desswegen noch lange kein schlechtes Datenbanksystem.
 
Einen solchen Code

QUOTE (lalo @ Fr 11.07.2008, 13:32)SELECT *, sum(vote_value) as gesamt, count(vote_value) as anzahl
FROM ratings, locations
WHERE id_location = vote_idlocation
GROUP BY vote_idlocation
ORDER BY gesamt DESC 5";


versteht jemand, der Sql kann, überhaupt nicht - weil den das Datenbank-System (Oracle, MS-Sql, sicherlich auch Postgres) zurückweisen würde, man also schlecht über etwas syntaktisch fehlerhaftes diskutieren kann.

(1) Die Logik von Aggregatfunktionen heißt: Mache aus vielen Zellen in einer Spalte einen Wert.
(2) Die Logik eines zusätzlichen Group By heißt: Teile den Gesamtstapel von (2) zunächst entlang der in der Group By - Klausel genannten Spalten auf in Teilstapel, bilde zu jedem Teilstapel den (1)-Wert und gib damit zu jedem Teilstapel eine Zeile zurück.

Zu dieser Logik (deren Stärke gerade in der Firmenunabhängigkeit liegt) paßt es nicht, wenn per '*' zusätzlich irgendwelche Daten irgendeiner Zeile ausgeliefert werden. Die Reihenfolge der Zeilen ist immer zufällig. Das sind dann die Fälle, die bei wenigen Datensätzen die richtigen Ergebnisse liefern, bei mehr Datensätzen oder bei irgendwelchen veränderten Randbedingungen (Wechsel einer Lizenzform - das ist kein Witz) kommt plötzlich etwas ganz anderes raus. Und dann klingelt bei mir das Telefon: 'Wir haben hier eine Anwendung, die ...'. Letzteres ist glücklicherweise noch nicht passiert, passiert aber analog mit allgemeinen, 'verhunzten Webanwendungen' immer wieder. Ich will da einfach keine Zeit investieren, mir so einen Code angucken zu müssen.

Zum Lernen einer Programmiersprache halte ich 'scharfe Systeme' immer besser als 'sehr freundliche', weil man gezwungen ist, die Logik genauer zu erfassen. Oder man scheitert eben kräftiger.
 
Eine "strikte" Script macht noch lange keine gute Software aus. Wer bei "labilen" Scriptsprachen solche Fehler macht, wird auch bei strikten Umgebungen scheitern, weil das ganze dann so hingebogen/gebastelt wird dass der Parser/Compiler das ganze frisst. Das ganze hängt plattformunabhängig von der Motivation und vom Knowhow der jeweiligen Entwickler ab. Die wenigsten "Projekte" sind schlussendlich an der gewählten Technologie gescheitert - sondern am Konzept oder spätestens in der Realisierung.

Dass das SQL-Statement aus dem aktuellen Topic nicht sehr glücklich ist sicherlich unbestritten. mySQL wird in diesem Fall dennoch genau das machen was ihm befohlen wird. Es aggregiert nach den vorhandenen Group by Elementen. Jede vote_location wird genau 1x zurückgeliefert. Die Elemente die nicht in einer Aggregatsfunktion oder in einer Group by Klausel stehen sind dann in der Tat irrelelevant und sollten mit Sicherheit nicht weiterverwendet werden.

Wenn der pfiffige Coder jetzt auf einem strikten System arbeitet, werden dann schnell mal alle benötigten Felder in die Group by Bedingung genommen, das Query wird gefressen, und man kriegt genauso ein Szenario wie von dir Beschrieben. Solche Beispiele kenne ich leider auch zur genüge..
 
Hi,

könnt Ihr mir bitte sagen, was an der SQL Abfrage so komplett falsch ist ?
Falls es um das "SELECT *" geht, das ist im endgültigen Code durch die Felder ersetzt die ich wirklich brauche.

...oder was ist daran jetzt so falsch, wie es hier rüberkommt ? Bin ja gerne bereit zu lernen.
 
QUOTE (lalo @ Mo 14.07.2008, 08:07)könnt Ihr mir bitte sagen, was an der SQL Abfrage so komplett falsch ist ?

Wenn Du einen Code der Form (Tabelle habe mehr als eine Spalte)


CODE Select *
From Tabelle
Group By ErsteSpalteDerTabelle


auf einem System auszuführen versuchst, das den Sql-Standard soweit berücksichtigt, dann wird es für jede Spalte eine Fehlermeldung geben, die in etwa so lautet:


CODE Column 'Tabelle.Spaltenname' is invalid in the select list because it is not contained in either an aggregate function or the GROUP BY clause.


Bei der Verwendung von Group By müssen die Ausgabespalten entweder aggregiert werden oder im Group-By - Abschnitt in der gewünschten Reihenfolge genannt werden.

Zum Weiterlesen: Group By zum Aggregieren und Auswerten von Daten

Wenn man nach 'Group By' googelt, dann findet man witzigerweise gleich unter meiner Seite das mySql-Handbuch mit genau diesem Hinweis - daß die 'Group By' gegenüber dem Sql-Standard erweitert sei.

Wenn man allerdings das


CODE Verwenden Sie diese Funktion nicht, wenn die Spalten, die Sie im GROUP BY-Anteil weglassen, in der Gruppe nicht eindeutig sind! Sie erhalten ansonsten nicht vorhersehbare Ergebnisse.


schon dort als Warnung dazuschreibt (worin genau auch mein grundsätzlicher Einwand besteht), dann verstehe ich nicht, warum man so etwas überhaupt implementiert hat.

PS: Es ist nicht der '*', sondern die Tatsache, daß Spalten ausgegeben werden, die weder aggregiert noch in der GroupBy-Liste aufgeführt werden.
 
Ah also ist es wirklich das * was euch sauer aufstößt ja ?

Wie ich schon schrieb, habe ich das zum testen im phpmyadmin genutzt um die Abfrage generell zu testen, ob meine gewünschten Ergebnisse rauskommen.

Im Code selber stehen dort nur die Felder drin die ich wirklich benötige, das ist dann also korrekt ja ?

..oder falsch verstanden ?
 
Zurück
Oben