2016-11-24 4 views
2

Ich möchte wissen, ob es möglich ist, eine andere Spalte zu einer select-Anweisung hinzufügen, die eine Aggregatfunktion wie min enthalten, max ...SQL-min-Funktion und andere Spalte

Beispiel:

SELECT user_id, MAX(salary) FROM users; 

ist diese Aussage korrekt im SQL-Standard (in MySQL ist ihre Arbeit); seine Arbeit in mysql, aber ich denke, ich irgendwo gelesen, dass, wenn ich eine Aggregatfunktion in der Select-Klausel, kann ich nichts als eine Aggregatfunktion setzen oder wenn es eine Gruppe von, kann die gruppierte Spalte in der Auswahl sein Klausel (in mysql)


EDIT:

User(user_id, name, last_name, salary) 

i die user_id, name, (maximum salary column) aus der User Tabelle auswählen möchten; ist es möglich, es ohne Unterabfrage zu tun?

Benutzertabelle

User_id, Name, Salary 

| 1 | user1 | last1 | 500 | | 
|---|-------|-------|------|---| 
| 2 | user2 | last2 | 1000 | | 
| 3 | user3 | last3 | 750 | | 
| |  |  |  | | 

der Ausgang der user_id, username, lastname, and salary of the user who have the max salary sein muss, so dass hier der Ausgang sein muss:

2 user2 last2 1000 

+0

davon abhängen, was Sie tun möchten, , mysql folgt nicht dem ansi-Standard bezüglich aggregierter Funktionen und group by, so dass Sie einige Abkürzungen ausführen können, die in anderen db nicht erlaubt sind. –

+0

@scaisEdge es ich benutze Gruppe von, es wird die Max (Gehalt) für jedes Tupel user_id, Name, die die gleiche wie die Verwendung von 'SELECT user_id, Name, Gehalt' ist zurück – karim

+1

BTW sollten Sie zeigen uns Beispieldaten und erwartete Ausgabe. Diese Frage kann je nach Bedarf sehr unterschiedlich sein. –

Antwort

1

Told Sie gibt es verschiedene Lösungen je nachdem, was Sie wollen ....

keine Gruppe durch, ohne Unterabfrage, Easy Kuchen

select * 
from users 
ORDER BY salary DESC 
LIMIT 1 
1

auf ein Beispiel Werfen wir einen Blick:

mysql> select * from users; 
+---------+----------+ 
| user_id | salary | 
+---------+----------+ 
|  1 | 42000.00 | 
|  2 | 39000.00 | 
|  3 | 50000.00 | 
+---------+----------+ 

mysql> SELECT user_id, MAX(salary) FROM users; 
+---------+-------------+ 
| user_id | MAX(salary) | 
+---------+-------------+ 
|  1 | 50000.00 | 
+---------+-------------+ 

Was ist damit? Benutzer 1 ist nicht der Benutzer mit einem Gehalt von 50000,00.

mysql> SELECT user_id, MAX(salary), MIN(SALARY) FROM users; 
+---------+-------------+-------------+ 
| user_id | MAX(salary) | MIN(SALARY) | 
+---------+-------------+-------------+ 
|  1 | 50000.00 | 39000.00 | 
+---------+-------------+-------------+ 

Benutzer 1 ist auch nicht der mit 39000.00. Das wird fischig, oder?

Wenn Sie Aggregatfunktionen verwenden, gelten sie nur für die Spalte, in der Sie die Funktion verwenden. Die Spalte user_id weiß nicht, aus welcher Zeile der maximale Wert stammt, und zeigt die entsprechende user_id an.

In diesem Beispiel, ich abfragen sowohl die MAX und MIN Gehalt. Aber diese gehören verschiedenen Benutzern! Welche user_id sollte angezeigt werden, selbst wenn die user_id automatisch aus der Zeile kommen könnte, aus der der aggregierte Wert stammt?

Und was ist, wenn zwei Benutzer das gleiche Gehalt haben, die für das maximale Gehalt gebunden sind? Welche user_id sollte angezeigt werden?

Und was, wenn Sie eine Aggregatfunktion verwenden, die keinen Wert zurückgibt, der in einer einzelnen Zeile vorhanden ist?

Hier ist die Erklärung: Eine Aggregatfunktion bewirkt, dass das Ergebnis nach dem Lesen der gesamten Zeilengruppe auf eine einzige Zeile reduziert wird. Eine Spalte, die sich nicht innerhalb einer Aggregatfunktion befindet (wie hier user_id), nimmt ihren Wert aus einer beliebigen Zeile in der Gruppe von Zeilen. Beliebig bedeutet nicht zufällig - in der Praxis ist es die erste gelesene MySQL-Zeile in der Gruppe. Aber es gibt keine Garantie, dass das immer so sein wird.

Wie nützlich ist das? Nicht sehr. In anderen Datenbanken ist es keine gültige Abfrage, und es wird buchstäblich einen Fehler generieren.

Tatsächlich hat MySQL 5.7 das Verhalten geändert, indem eine Regel durchgesetzt wurde, die mehrdeutige Abfragen nicht zulässt. Wenn Sie versuchen, die Abfrage oben auf MySQL 5.7 laufen, wird es zu einem Fehler:

ERROR 1140 (42000): In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'test.users.user_id'; this is incompatible with sql_mode=only_full_group_by

Es ist eine Option, um es wie frühere Versionen von MySQL zu machen zu handeln. Weitere Informationen hierzu finden Sie unter: https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html

Als eine Kleinigkeit ist SQLite eine andere Datenbank, die diese Art von beliebigem Ergebnis ermöglicht. Nur in SQLite würde der Wert von user_id aus der letzten Zeile stammen, die in der Gruppe gelesen wurde. Stelle dir das vor.

+1

Vielen Dank für diese wertvolle Antwort, aber können Sie mir eine Lösung für dieses Problem geben? – karim

+1

Ich mag diese Erklärung sehr. Das Missverständnis der nicht aggregierten user_id in der Abfrage kann möglicherweise nicht offensichtlicher gemacht werden. –

+0

@ Karim, Juan Carlos gibt die einfachste Lösung. –

2

Zu Beginn: Nein,

SELECT user_id, MAX(salary) FROM users; 

ist nicht standardkonform. Sie verwenden eine Aggregatfunktion (MAX) ohne eine GROUP BY-Klausel. Auf diese Weise weisen Sie das DBMS an, alle Datensätze in einer einzigen Ergebniszeile zu aggregieren. Nun, was sagst du dem DBMS in dieser Ergebniszeile? Das Höchstgehalt in der Tabelle gefunden (MAX(salary)) und dieuser_id. Es gibt jedoch keine dieuser_id; Es gibt möglicherweise viele verschiedene user_id in der Tabelle. Dies verstößt gegen den SQL-Standard. MySQL erlaubt die Interpretation der nicht aggregierten user_id als beliebiguser_id (willkürlich ausgewählt).

Also obwohl die Abfrage ausgeführt wird, ist das Ergebnis normalerweise nicht das gewünschte.

Diese Abfrage:

SELECT user_id, name, MAX(salary) FROM users GROUP BY user_id; 

auf der anderen Seite ist Standard-konform. Lassen Sie uns noch einmal sehen, was diese Abfrage bewirkt: Dieses Mal gibt es eine GROUP BY Klausel, die dem DBMS mitteilt, dass Sie eine Ergebniszeile pro user_id wollen. Für jede user_id, die Sie anzeigen möchten: dieuser_id, diename und die maximale salary. All das sind gültige Ausdrücke; dieuser_id die user_id selbst ist, die Name ist derjenige mit dem Benutzernamen user_id zugeordnet ist, und die maximale salary ist der maximale Gehalt des Benutzers. Die nicht aggregierte Spalte name ist erlaubt, da sie funktional von der Gruppierung nach user_id abhängig ist. Viele DBMS unterstützen dies jedoch nicht, da es sehr kompliziert werden kann, festzustellen, ob ein Ausdruck funktional von der Gruppe abhängig ist oder nicht.

Um den Benutzerdatensatz mit dem maximalen Gehalt anzuzeigen, benötigen Sie eine Begrenzungsklausel. MySQL bietet dafür LIMIT, was Ihnen die ersten n Zeilen bringen kann. Es geht jedoch nicht um Bindungen.

SELECT * FROM users ORDER BY salary DESC LIMIT 1; 

ist

SELECT * FROM users ORDER BY salary FETCH FIRST ROW ONLY; 

in Standard-SQL.

Um mit Verbindungen zu behandeln, aber, wie in

SELECT * FROM users ORDER BY salary FETCH FIRST ROW WITH TIES; 

benötigen Sie eine Unterabfrage in MySQL, weil LIMIT dies nicht unterstützt:

SELECT * FROM users WHERE salary = (SELECT MAX(salary) FROM users); 
Verwandte Themen