2010-10-01 3 views
88

Nur neugierig auf SQL-Syntax. Also, wenn ichSQL - Verwenden von Alias ​​in Group Von

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

Dies wäre falsch, weil

GROUP BY itemName, FirstLetter 

wirklich

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

Aber warum wir einfach nicht die ehemalige Einfachheit halber verwenden sollte?

+5

, die in Postgresql –

+3

MySQL erlaubt ist erlaubt es auch – Kip

+0

SQLite es –

Antwort

161

SQL 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 erklärt diese Reihenfolge, 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 Ausdruck 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 zusätzliche Intelligenz, die es erlaubt.

+0

Ich mag diese Erklärung. Obwohl ich nicht spekulieren kann, wie schwierig es ist, es als syntaktischen Zucker zu einer Maschine hinzuzufügen. – Haoest

+8

Eine Idee, wenn die DB intelligent genug ist, um den gleichen Ausdruck zu realisieren, ist in den SELECT- und GROUP BY-Klauseln, ohne die Ausdrücke neu zu bewerten? d. h. wenn es eine GROUP BY-Teilzeichenfolge (itemName, 1,1) gibt, ist die Datenbank intelligent genug, um den Leistungstreffer der Neuberechnung der Teilzeichenfolge in der SELECT-Klausel nicht zu übernehmen? – Kip

+8

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, schlau zu sein. es muss so implementiert werden, dass die Gruppierung funktioniert. (Und es ist durch den SQL-Standard erforderlich). Aber selbst in trivialeren Fällen (z. B. der gleiche Ausdruck in der WHERE- und der SELECT-Klausel) werden Datenbanksysteme nach dem Stand der Technik diese nur einmal berechnen. Diese Optimierung wird als * allgemeine Unterdrückung von Unterausdrücken * bezeichnet. – Codo

11

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

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

Natürlich ist dies beginnt ein Schmerz zu sein, wenn Sie diese interaktiv tun, und Sie bearbeiten die Abfrage Ändern Sie die Anzahl oder Reihenfolge der Spalten im Ergebnis. Aber dennoch.

+0

'GROUP BY FirstLetter' erlaubt ist in Postgresql erlaubt. Versuchen Sie, dies in Postgresql auszuführen: Wählen Sie Teilzeichenfolge (Tabellenname, 1,2) als Name von information_schema.tables Gruppe von tname –

+1

@MichaelBuen Scheint potentiell problematisch für mich. Aus einem schnellen Test sieht es so aus, als ob es einen Alias ​​und eine Basistabellenspalte mit dem gleichen Namen gibt, der letztere Priorität bekommt? [SQL Geige] (http://sqlfiddle.com/#!15/d41d8/1920). Wenn Sie sich also auf diese Gruppe per Alias ​​verlassen, könnte eine spätere Änderung des Schemas Ihre Abfrage automatisch unterbrechen und die Semantik ändern. –

+0

@MartinSmith wusste nur jetzt, das ist ein Gotcha, wird davon ablassen, das zu verwenden, 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. –

2

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

Ich vermeide die Ordinalpositionsnotation wie von Bill aus Gründen empfohlen, die in this SO question dokumentiert sind.

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

22

Sie können immer eine Unterabfrage verwenden, damit Sie den Alias ​​verwenden können; Natürlich die Leistung überprüfen (Possible des DB-Server das gleiche läuft beide, aber schadet nie, um zu überprüfen):

SELECT ItemName, FirstLetter, COUNT(ItemName) 
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter 
    FROM table1 
    ) ItemNames 
GROUP BY ItemName, FirstLetter 
+0

danke, gute Idee! – digz6666

0

Zurück in dem Tag fand ich, dass Rdb, jetzt das ehemalige Dezember Produkt von Oracle dem erlaubten unterstützt Spaltenalias, der in GROUP BY verwendet werden soll. Mainstream Oracle bis Version 11 lässt nicht zu, dass der Spaltenalias in GROUP BY verwendet wird. Nicht sicher, was Postgresql, SQL Server, MySQL, etc wird oder nicht zulassen wird. YMMV.

8

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

Hier finden Sie eine Quelle für Informationen zum SQL Server logical processing phases.

1

Achten Sie darauf, beim Gruppieren der Ergebnisse aus einer Ansicht in SQLite Aliase zu verwenden. Sie erhalten unerwartete Ergebnisse, wenn der Aliasname mit dem Spaltennamen aller zugrunde liegenden Tabellen identisch ist.

3

Vorsicht, dass Alias ​​in der Gruppe von (für Dienste, die es unterstützen, wie Postgres) verwendet werden kann unbeabsichtigte Ergebnisse haben. Wenn Sie beispielsweise einen Alias ​​erstellen, der bereits in der inneren Anweisung vorhanden ist, wählt die Gruppe nach den Namen des inneren Feldes aus.

-- 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; 
0

Ich antworte nicht, warum es so ist, aber wollte nur um diese Einschränkung in SQL Server, einen Weg zeigen, indem sie CROSS APPLY mit dem Alias ​​zu erstellen. Sie verwenden es dann in der GROUP BY Klausel, etwa so:

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