SQL - Verwenden des Alias ​​in Group By

143

Nur neugierig auf SQL-Syntax. Also wenn ich habe

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY itemName, FirstLetter

Das wäre falsch, weil

GROUP BY itemName, FirstLetter 

sollte wirklich sein

GROUP BY itemName, substring(itemName, 1,1)

Aber warum können wir erstere nicht einfach der Einfachheit halber verwenden?

Haoest
quelle
13
das ist in Postgresql erlaubt
Michael Buen
7
MySQL erlaubt es auch
Kip
1
Über welche RDBMS sprechen Sie?
Shiwangini

Antworten:

292

SQL wird so implementiert, als ob eine Abfrage in der folgenden Reihenfolge ausgeführt wurde:

  1. FROM-Klausel
  2. WHERE-Klausel
  3. GROUP BY-Klausel
  4. HAVING-Klausel
  5. SELECT-Klausel
  6. ORDER BY-Klausel

Für die meisten relationalen Datenbanksysteme wird in dieser Reihenfolge erläutert, welche Namen (Spalten oder Aliase) gültig sind, da sie in einem vorherigen Schritt eingeführt worden sein müssen.

In Oracle und SQL Server können Sie daher keinen Begriff in der GROUP BY-Klausel verwenden, die Sie in der SELECT-Klausel definieren, da GROUP BY vor der SELECT-Klausel ausgeführt wird.

Es gibt jedoch Ausnahmen: MySQL und Postgres scheinen eine zusätzliche Intelligenz zu haben, die dies ermöglicht.

Codo
quelle
3
Ich mag diese Erklärung. Obwohl ich nicht spekulieren kann, wie schwierig es ist, es als syntaktischen Zucker zu einer Engine hinzuzufügen.
Haoest
11
Gibt es eine Idee, ob die Datenbank intelligent genug ist, um denselben Ausdruck in den Klauseln SELECT und GROUP BY zu realisieren, ohne die Ausdrücke neu zu bewerten? Wenn dies GROUP BY substring(itemName, 1,1)der Fall ist , ist die Datenbank intelligent genug, um den Leistungseinbruch bei der Neuberechnung des Teilstrings in der SELECT-Klausel nicht zu erleiden?
Kip
10
In der SELECT-Klausel einer Abfrage mit Gruppierung haben Sie nur Zugriff auf die GROUP BY-Ausdrücke und aggregierten Werte. Es geht also nicht darum, klug zu sein. Es muss so implementiert werden, damit die Gruppierung funktioniert. (Und es wird vom SQL-Standard verlangt). Aber selbst in trivialeren Fällen (z. B. der gleiche Ausdruck in der WHERE- und der SELECT-Klausel) werden hochmoderne Datenbanksysteme diese sicherlich nur einmal berechnen. Diese Optimierung wird als gemeinsame Eliminierung von Unterausdrücken bezeichnet .
Codo
6
Was hat die Ausführungsreihenfolge mit der Frage zu tun? Es ist nicht so, als hätte der Fragesteller versucht, auf dem COUNT () nach GROUP BY zu suchen. Tatsächlich funktioniert die angeforderte Abfrage in MySQL und wahrscheinlich in PostgreSQL einwandfrei, wie in den Kommentaren angegeben.
1
Für mysql, sql_modeohne ONLY_FULL_GROUP_BY in der Bitmaske hat der Optimizer eine Chance zu liefern bessere Ergebnisse mit einer variierten / unterschiedlichen Verwendung der Alias in der HAVINGKlausel.
Drew
28

Sie können jederzeit eine Unterabfrage verwenden, um den Alias ​​zu verwenden. Überprüfen Sie natürlich die Leistung (Möglicherweise wird der Datenbankserver beide gleich ausgeführt, es tut jedoch nie weh, dies zu überprüfen):

SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
    FROM table1
    ) ItemNames
GROUP BY ItemName, FirstLetter
Chris Shaffer
quelle
2
Unterabfragen sollten nach Möglichkeit aufgrund schlechter Leistung vermieden werden. Die Verwendung einer Kopie der Funktion ist viel besser, da sie natürlich vom Datenbankoptimierer erkannt und nur einmal ausgeführt wird.
Roland
1
@ Roland, aber es gibt keinen Unterschied im Ausführungsplan in diesem Fall. Gibt es andere Leistungsaspekte?
Guido Mocha
@Roland, Korrelierte Unterabfragen oder andere Syntax, die zu Schleifen oder zeilenweisem Verhalten führen, sollten vermieden werden. Es gibt eine Grenze für die Tiefe verschachtelter Unterabfragen, aber es ist im Allgemeinen nicht wahr, dass Unterabfragen führen zu schlechter Leistung. In diesem Fall können Sie, wie Chris gesagt hat, den Ausführungsplan (AKA-Abfrageplan, Erklärungsplan) überprüfen, indem Sie ihn mit und ohne Unterabfrage vergleichen und feststellen, ob es wirklich einen Unterschied gibt. Nahezu jedes Datenbankmodul schreibt Ihre Abfrage neu, sodass Sie nicht die vollständige Kontrolle darüber haben, was ausgeführt wird. Das ist der Punkt der deklarativen Syntax.
Davos
16

Zumindest in PostgreSQL können Sie die Spaltennummer in der Ergebnismenge in Ihrer GROUP BY-Klausel verwenden:

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY 1, 2

Natürlich wird dies zu einem Problem, wenn Sie dies interaktiv tun und die Abfrage bearbeiten, um die Anzahl oder Reihenfolge der Spalten im Ergebnis zu ändern. Aber dennoch.

Bill Gribble
quelle
GROUP BY FirstLetterist in Postgresql erlaubt. Versuchen Sie dies in Postgresql: Wählen Sie Teilzeichenfolge (Tabellenname, 1,2) als tname aus der Gruppe information_schema.tables nach tname
Michael Buen
1
@ MichaelBuen Scheint mir möglicherweise problematisch. Nach einem Schnelltest sieht es so aus, als ob es einen Alias ​​und eine Basistabellenspalte mit demselben Namen gibt, die letztere Priorität erhalten? SQL Fiddle . Wenn Sie sich also auf diese Gruppe als Alias ​​verlassen, kann eine spätere Schemaänderung Ihre Abfrage unbemerkt unterbrechen und die Semantik ändern.
Martin Smith
@MartinSmith wusste erst jetzt, dass es sich um eine Gotcha handelt, ich werde darauf verzichten, danke. Da PostgreSQL diese Verknüpfung zulässt, sollten sie dem Alias ​​eine Priorität geben, andernfalls sollten sie diese Verknüpfung überhaupt nicht zulassen.
Michael Buen
Dies war eine schreckliche Idee der PostgreSQL-Designer. Es ist verwirrend, sobald Sie versuchen, GROUP BYeinen Ausdruck zu finden, der Aggregatfunktionen oder Fensterfunktionen enthält, was "offensichtlich" nicht funktioniert.
Lukas Eder
13

In SQL Server können Sie aufgrund der logischen Reihenfolge der Verarbeitung nicht auf den Alias ​​in der GROUP BY-Klausel verweisen. Die GROUP BY-Klausel wird vor der SELECT-Klausel verarbeitet, sodass der Alias ​​bei der Auswertung der GROUP BY-Klausel nicht bekannt ist. Dies erklärt auch, warum Sie den Alias ​​in der ORDER BY-Klausel verwenden können.

Hier finden Sie eine Informationsquelle zu den logischen Verarbeitungsphasen von SQL Server .

Bobs
quelle
8

Ich antworte nicht, warum dies so ist, sondern wollte nur einen Weg zeigen, um diese Einschränkung in SQL Server CROSS APPLYzu umgehen, indem ich den Alias ​​verwende. Sie verwenden es dann in der GROUP BYKlausel wie folgt:

SELECT 
 itemName as ItemName,
 FirstLetter,
 Count(itemName)
FROM table1
CROSS APPLY (SELECT substring(itemName, 1,1) as FirstLetter) Alias
GROUP BY itemName, FirstLetter
Ricardo
quelle
4

Beachten Sie, dass die Verwendung von Alias ​​in Group By (für Dienste, die dies unterstützen, wie z. B. Postgres) zu unbeabsichtigten Ergebnissen führen kann. Wenn Sie beispielsweise einen Alias ​​erstellen, der bereits in der inneren Anweisung vorhanden ist, wählt die Gruppe nach den Namen des inneren Felds.

-- Working example in postgres
select col1 as col1_1, avg(col3) as col2_1
from
    (select gender as col1, maritalstatus as col2, 
    yearlyincome as col3 from customer) as layer_1
group by col1_1;

-- Failing example in postgres
select col2 as col1, avg(col3)
from
    (select gender as col1, maritalstatus as col2,
    yearlyincome as col3 from customer) as layer_1
group by col1;
Shannon S.
quelle
3

Bei einigen DBMS können Sie einen Alias ​​verwenden, anstatt den gesamten Ausdruck wiederholen zu müssen.
Teradata ist ein solches Beispiel.

Ich vermeide die von Bill empfohlene ordinale Positionsnotation aus Gründen, die in dieser SO-Frage dokumentiert sind .

Die einfache und robuste Alternative besteht darin, den Ausdruck in der GROUP BY-Klausel immer zu wiederholen.
DRY gilt NICHT für SQL.

mechanisches Fleisch
quelle
1

Achten Sie beim Gruppieren der Ergebnisse aus einer Ansicht in SQLite auf die Verwendung von Aliasen. Sie erhalten unerwartete Ergebnisse, wenn der Aliasname mit dem Spaltennamen aller zugrunde liegenden Tabellen (für die Ansichten) übereinstimmt.

GGGforce
quelle
0

Damals stellte ich fest, dass Rdb, das frühere DEC-Produkt, das jetzt von Oracle unterstützt wird, die Verwendung des Spaltenalias in GROUP BY ermöglichte. Mainstream Oracle bis Version 11 erlaubt nicht, dass der Spaltenalias in GROUP BY verwendet wird. Ich bin nicht sicher, was Postgresql, SQL Server, MySQL usw. zulassen oder nicht zulassen. YMMV.

Bob Jarvis - Monica wieder einsetzen
quelle