SQL-używanie aliasów w grupie przez

Jestem ciekaw składni SQL. Więc jeśli mam

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

To byłoby niepoprawne, ponieważ

GROUP BY itemName, FirstLetter 

Naprawdę powinno być

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

Ale dlaczego nie możemy po prostu użyć tego pierwszego dla wygody?

Author: Haoest, 2010-10-01

9 answers

SQL jest zaimplementowany tak, jakby zapytanie zostało wykonane w następującej kolejności:

  1. z klauzuli
  2. Gdzie
  3. GROUP BY clause
  4. mając klauzulę
  5. SELECT clause
  6. ORDER BY clause

Dla większości relacyjnych systemów baz danych kolejność ta wyjaśnia, które nazwy (kolumny lub aliasy) są ważne, ponieważ musiały być wprowadzone w poprzednim kroku.

Więc w Oracle i SQL Server nie można użyć wyrażenia w klauzuli GROUP BY, które zdefiniowano w klauzuli SELECT, ponieważ grupa BY jest wykonywana przed klauzulą SELECT.

Są jednak wyjątki: MySQL i Postgres wydają się mieć dodatkową inteligencję, która na to pozwala.

 197
Author: Codo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-30 14:34:56

Zawsze możesz użyć subquery, więc możesz użyć aliasu; oczywiście sprawdź wydajność (możliwe, że serwer db będzie działał tak samo, ale nigdy nie zaszkodzi zweryfikować):

SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
    FROM table1
    ) ItemNames
GROUP BY ItemName, FirstLetter
 22
Author: Chris Shaffer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-01 16:55:05

Przynajmniej w PostgreSQL możesz użyć numeru kolumny w resultset w swojej grupie by klauzula:

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

Oczywiście zaczyna to być ból, jeśli robisz to interaktywnie i edytujesz zapytanie, aby zmienić liczbę lub kolejność kolumn w wyniku. Ale jednak.

 14
Author: Bill Gribble,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-01 16:49:25

SQL Server nie pozwala odwoływać się do aliasu w klauzuli GROUP BY ze względu na logiczną kolejność przetwarzania. Klauzula GROUP BY jest przetwarzana przed klauzulą SELECT, więc alias nie jest znany podczas oceny klauzuli GROUP BY. Wyjaśnia to również, dlaczego możesz użyć aliasu w klauzuli ORDER BY.

Oto Jedno źródło informacji na temat faz przetwarzania logicznego SQL Server.

 10
Author: bobs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-01 17:10:04

Należy pamiętać, że użycie aliasu w grupie By (dla usług, które go obsługują, takich jak postgres) może mieć niezamierzone wyniki. Na przykład, jeśli utworzysz alias, który już istnieje w instrukcji wewnętrznej, Grupa By wybierze wewnętrzną nazwę pola.

-- 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;
 3
Author: Shannon S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-23 13:13:29

Niektóre DBMSs pozwalają używać aliasu zamiast powtarzać całe wyrażenie.
Teradata jest jednym z takich przykładów.

Unikam Porządkowej notacji pozycji zalecanej przez Billa z powodów udokumentowanych w to pytanie .

Łatwą i solidną alternatywą jest zawsze powtarzanie wyrażenia w klauzuli GROUP BY.
DRY nie ma zastosowania do SQL.

 2
Author: bernie,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:01

Uważaj na używanie aliasów podczas grupowania wyników z widoku w SQLite. Nieoczekiwane wyniki uzyskasz, jeśli nazwa aliasu jest taka sama ,jak nazwa kolumny wszystkich bazowych tabel (do widoków.)

 1
Author: GGGforce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-28 15:29:20

Kiedyś odkryłem, że RDB, dawny produkt DEC obsługiwany teraz przez Oracle, pozwalał na użycie aliasu kolumn w grupie BY. Oracle w wersji 11 nie pozwala na użycie aliasu kolumn w grupie BY. Nie wiem, co Postgresql, SQL Server, MySQL, itp.pozwoli lub nie pozwoli. YMMV.

 0
Author: Bob Jarvis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-01 16:56:40

NIE ODPOWIADAM, dlaczego tak jest, ale chciałem tylko pokazać sposób na obejście tego ograniczenia w SQL Server za pomocą CROSS APPLY do utworzenia aliasu. Następnie używasz go w klauzuli GROUP BY, w następujący sposób:

SELECT 
 itemName as ItemName,
 FirstLetter,
 Count(itemName)
FROM table1
CROSS APPLY (SELECT substring(itemName, 1,1) as FirstLetter) Alias
GROUP BY itemName, FirstLetter
 0
Author: Ricardo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-12-13 18:59:48