avg Anfrage funktioniert nicht wie ich mir das vorstelle

deggit

Benutzer
Beiträge
7
Hallo,
ich hoffe Ihr könnt mir weiterhelfen, da ich gerade ein wenig am verzweifeln bin.
Ich nutze xampp um ein paar simple SQL-Befehle auszuprobieren.

Ich habe folgende Tabelle
Tabelle.JPG

Meine Anfrage ist sehr simple, ich erstelle eine neue Spalte DGehalt (DurschnittsGehalt) und möchte mir alles ausgeben lassen

SELECT Vorname, Name, Gehalt, avg(Gehalt) AS DGehalt
From masseur

Leider gibt er mir jetzt nur den ersten Eintrag in der Tabelle aus
Ausgabe.JPG

Das macht doch keinen Sinn, oder? Er müsste mir doch beide Zeilen ausgeben. Übersehe ich etwas Elementares?

vielen lieben Dank für eure
Hilfe
Deggit
Sq9MhWYzYP3GWqKt1
 
Werbung:
Nein, das macht keinen Sinn. Keinen Sinn macht aber auch Deine Abfrage selbst. In Abfragen mit einer Aggregation (hier: avg) müssen alle Spalten im Resultat entweder aggregiert oder gruppiert sein. Und jetzt kommt das wirklich fatale an MySQL: anstatt wie alle anderen Datenbanken einen Syntaxfehler liefert MySQL ein falsches Ergebniss.

Code:
test=# create table masseur(vorname text, name text, gehalt numeric);
CREATE TABLE
test=*# select vorname, name, gehalt, avg(gehalt) as dgehalt from masseur ;
FEHLER:  Spalte »masseur.vorname« muss in der GROUP-BY-Klausel erscheinen oder in einer Aggregatfunktion verwendet werden
LINE 1: select vorname, name, gehalt, avg(gehalt) as dgehalt from ma...
  ^
test=*#

Gutgemeinter Vorschlag: wird MySQL in die Tonne.

PS.: auf was soll sich denn das dgehalt beziehen, auf alle Personen in der Tabelle?
 
PS.: vermutlich suchst Du sowas:

Code:
test=*# insert into masseur values ('Max','Mustermann', 10);
INSERT 0 1
test=*# insert into masseur values ('Susi','Sorglos', 50);
INSERT 0 1
test=*# select vorname, name, gehalt, avg(gehalt) over () as dgehalt from masseur;
 vorname |  name  | gehalt |  dgehalt   
---------+------------+--------+---------------------
 Max  | Mustermann |  10 | 30.0000000000000000
 Susi  | Sorglos  |  50 | 30.0000000000000000
(2 rows)

test=*#

Nun - Du brauchst es so nicht zu versuchen, das kann MySQL nicht.
 
Hallo,
vielen lieben Dank für deine schnelle Antwort. Genau so etwas wie in deinen zweiten Post wollte ich erreichen. Das MySQL das nicht kann finde ich schon sehr überraschend, hätte nicht gedacht, dass es daran liegen könnte. Du hast aber auch in deinen ersten Post geschrieben, dass meine Anfrage keinen Sinn ergibt. Kannst du mir das vielleicht noch etwas genauer erklären, wo liegt mein Fehler? Habe leider deine Antwort nicht so richtig verstanden.
Ich will doch nur eine neue Spalte mit dem DGehalt für alle erstellen.
Im nächsten Schritt könnte ich mir dann vorstellen nur die Masseure auszugeben, die weniger oder mehr verdienen

SELECT Vorname, Name, Gehalt, avg(Gehalt) AS DGehalt
From masseur
Where Gehalt > DGehalt

aber ich denke dies klappt auch nicht
 
so z.B. klappt das

SELECT Vorname, Name, Gehalt
From masseur
WHERE Gehalt > (
SELECT AVG(Gehalt)
FROM masseur)

aber warum nicht so

SELECT Vorname, Name, Gehalt, avg(Gehalt) AS DGehalt
From masseur
Where Gehalt > DGehalt
 
stelle dir mal vor, in der Tabelle wäre noch ein Datum, und die Leute hätten jeden Monat ein anderes gehalt (Boni z.B.). Welches Gehalt soll dann in der Gehaltsspalte angezeigt werden, und auf was soll sich das avg(gehalt) dann beziehen, auf das avg() je Mitarbeiter über alle Monate oder über alle Mitarbeiter und Monate?

Das sind Dinge, die mit MySQL nur mühsam zu erreichen sind. Gut, Dein Fall ist noch trivial:

Code:
test=*# select vorname, name, gehalt, (select avg(gehalt) as dgehalt from masseur) from masseur ;
 vorname |  name  | gehalt |  dgehalt   
---------+------------+--------+---------------------
 Max  | Mustermann |  10 | 30.0000000000000000
 Susi  | Sorglos  |  50 | 30.0000000000000000
(2 rows)

Kommt da jetzt noch der Monat dazu, dann geht das eigentlich nur noch gescheit über Window-Funktionen (Syntax wäre avg(gehalt) over (partition by vorname, name), als Beispiel wenn es je Mitarbeiter wäre)
 
puhhh ok ich komme der Sache näher
"stelle dir mal vor, in der Tabelle wäre noch ein Datum, und die Leute hätten jeden Monat ein anderes gehalt (Boni z.B.). Welches Gehalt soll dann in der Gehaltsspalte angezeigt werden, und auf was soll sich das avg(gehalt) dann beziehen, auf das avg() je Mitarbeiter über alle Monate oder über alle Mitarbeiter und Monate?"

Wäre das Gehalt dann nicht eig. immer Gehalt + Boni. Also die Gehaltsspalte wäre je nach erreichen des Boni variabel. Liegt da das Problem? Da er Eintrag für Gehalt ja fix ist. Verstehe ich das gerade richtig?


"weil zum Zeitpunkt, wo die Where-Condition greift, das avg() noch gar nicht berechenbar ist. Erst muß das Where aufgelöst werden, um das avg() zu berechnen. Du suchst HAVING"

Verstehe ich das richtig, das er das DGehalt erst am Ende des SQL-Befehls erstellt und deswegen geht es nicht
So klappt es leider auch nicht

select vorname, name, gehalt, (
select avg(gehalt) as dgehalt from masseur)
from masseur
HAVING Gehalt > dgehalt;
 
Code:
test=*# select vorname, name, gehalt, (select avg(gehalt) as dgehalt from masseur) from masseur where gehalt > (select avg(gehalt) as dgehalt from masseur);
 vorname |  name  | gehalt |  dgehalt   
---------+---------+--------+---------------------
 Susi  | Sorglos |  50 | 30.0000000000000000
(1 row)

test=*# select vorname, name, gehalt, (select avg(gehalt) as dgehalt from masseur) from masseur where gehalt < (select avg(gehalt) as dgehalt from masseur);
 vorname |  name  | gehalt |  dgehalt   
---------+------------+--------+---------------------
 Max  | Mustermann |  10 | 30.0000000000000000
(1 row)
 
Danke dir für deine Geduld un Hilfe. Ich will es auch verstehen.

select vorname, name, gehalt, (select avg(gehalt) as dgehalt from masseur) from masseur where gehalt > (select avg(gehalt) as dgehalt from masseur);

Warum muss ich in hier:
where gehalt > (select avg(gehalt) as dgehalt from masseur
noch einmal das avg (Gehalt) neu berechnen?

habe ich dies nicht schon vorher gemacht:
select vorname, name, gehalt, (select avg(gehalt) as dgehalt from masseur) from masseur

warum ist der berechnete Wert von DGehalt also noch nicht bekannt? Kann ich mir das so wie in Java vorstellen, mit Klassen und Methoden Variablen?
 
Nein.

Zuerst wird das Where ausgeführt. Das ermittelt alle Datensätze, die der Where-Condition genügen. Du willst alle, die über dem avg() liegen, das filtert das Where aus. Mit diesen Datensätzen wird dann die Ergebnissliste zusammengestellt. Du darfst nicht den Fehler machen, die Abfrage von vorn nach hinten zu interpretieren.

Code:
test=*# explain select vorname, name, gehalt, (select avg(gehalt) as dgehalt from masseur) from masseur where gehalt > (select avg(gehalt) as dgehalt from masseur);
  QUERY PLAN   
-----------------------------------------------------------------------------------
 Seq Scan on masseur  (cost=36.28..54.40 rows=217 width=96)
  Filter: (gehalt > $1)
  InitPlan 1 (returns $0)
  ->  Aggregate  (cost=18.13..18.14 rows=1 width=32)
  ->  Seq Scan on masseur masseur_1  (cost=0.00..16.50 rows=650 width=32)
  InitPlan 2 (returns $1)
  ->  Aggregate  (cost=18.13..18.14 rows=1 width=32)
  ->  Seq Scan on masseur masseur_2  (cost=0.00..16.50 rows=650 width=32)
(8 rows)
 
Werbung:
Zurück
Oben