SQL - использование псевдонима в Group By


143

Просто любопытно о синтаксисе SQL. Так что если у меня есть

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

Это было бы неправильно, потому что

GROUP BY itemName, FirstLetter 

действительно должно быть

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

Но почему мы не можем просто использовать первое для удобства?


13
это разрешено в Postgresql
Майкл Буэн

7
MySQL также позволяет это
делать

1
о каких rdbms вы говорите?
Shiwangini

Ответы:


292

SQL реализован так, как если бы запрос был выполнен в следующем порядке:

  1. ОТ условия
  2. ГДЕ оговорка
  3. Предложение GROUP BY
  4. HAVING пункт
  5. Предложение SELECT
  6. Предложение ORDER BY

Для большинства систем реляционных баз данных этот порядок объясняет, какие имена (столбцы или псевдонимы) являются действительными, поскольку они должны быть введены на предыдущем шаге.

Таким образом, в Oracle и SQL Server нельзя использовать термин в предложении GROUP BY, который вы определяете в предложении SELECT, поскольку GROUP BY выполняется перед предложением SELECT.

Хотя есть исключения: MySQL и Postgres, кажется, обладают дополнительным умом, который позволяет это.


3
Мне нравится это объяснение. Хотя я не могу предположить, насколько сложно добавить его в движок как синтаксический сахар.
Haoest

11
Любая идея, если БД достаточно умен, чтобы реализовать одно и то же выражение, в предложениях SELECT и GROUP BY без переоценки выражений? т. е. достаточно ли GROUP BY substring(itemName, 1,1)умна база данных, чтобы не снизить производительность при повторной обработке подстроки в предложении SELECT?
Кип

10
В предложении SELECT запроса с группировкой у вас есть доступ только к выражениям GROUP BY и агрегированным значениям. Так что дело не в том, чтобы быть умным; это должно быть реализовано таким образом, чтобы группировка работала. (И это требуется стандартом SQL). Но даже в более тривиальных случаях (например, одно и то же выражение в выражении WHERE и в предложении SELECT) современные системы баз данных, безусловно, рассчитают его только один раз. Эта оптимизация называется устранением общих подвыражений .
Кодо

6
Какое отношение имеет порядок выполнения к вопросу? Это не то, что спрашивающий пытался GROUP BY на COUNT (). На самом деле, запрос в соответствии с запросом прекрасно работает в MySQL и, вероятно, в PostgreSQL, как указано в комментариях.

1
Для mysql, sql_modeне считая ONLY_FULL_GROUP_BY в битовой маске , Оптимизатор имеет шанс получить лучшие результаты при различном / различном использовании псевдонима в HAVINGпредложении.
Дрю

28

Вы всегда можете использовать подзапрос, чтобы вы могли использовать псевдоним; Конечно, проверьте производительность (возможно, сервер БД будет работать одинаково, но никогда не повредит):

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

2
По возможности следует избегать подзапросов из-за плохой производительности. Использование копии функции намного лучше, потому что она, конечно, обнаруживается оптимизатором базы данных и выполняется только один раз.
Роланд

1
@Roland, но в этом случае план выполнения не отличается. Есть ли другие соображения по поводу производительности?
Гвидо Мокко

@Roland, следует избегать коррелированных подзапросов или другого синтаксиса, который приводит к циклам или построчному поведению, и существует ограничение на то, насколько глубоко вы должны идти с вложенными подзапросами, но, как правило, неверно, что подзапросы приводят к плохой производительности. В этом случае, как сказал Крис, вы можете проверить план выполнения (план запроса AKA, план объяснения), сравнивая как с подзапросом, так и без него, и посмотреть, действительно ли есть какая-то разница. Практически каждый механизм базы данных будет переписывать ваш запрос, поэтому вы не будете полностью контролировать, что будет выполнено. В этом смысл декларативного синтаксиса.
Давос,

16

По крайней мере, в PostgreSQL вы можете использовать номер столбца в наборе результатов в предложении GROUP BY:

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

Конечно, это становится проблемой, если вы делаете это в интерактивном режиме и редактируете запрос, чтобы изменить количество или порядок столбцов в результате. Но все равно.


GROUP BY FirstLetterразрешено в Postgresql. Для этого попробуйте запустить это в Postgresql: выберите подстроку (table_name, 1,2) в качестве tname из группы information_schema.tables по tname
Майкл Буэн,

1
@MichaelBuen кажется мне потенциально проблематичным. Из быстрого теста выглядит так, как будто есть псевдоним и столбец базовой таблицы с тем же именем, которому последний получает приоритет? SQL Fiddle . Так что если вы полагаетесь на эту группу по псевдониму, более позднее изменение схемы может молча нарушить ваш запрос и изменить семантику.
Мартин Смит

@MartinSmith теперь только знал, что это гоча, воздержится от этого, спасибо. Учитывая, что PostgreSQL допускает такой ярлык, они должны дать псевдониму приоритет, иначе они вообще не должны разрешать этот ярлык.
Майкл Буэн

Это была ужасная идея дизайнеров PostgreSQL. Это сбивает с толку, как только вы пытаетесь использовать GROUP BYлюбое выражение, содержащее агрегатные функции или оконные функции, которые «очевидно» не работают.
Лукас Эдер

13

SQL Server не позволяет ссылаться на псевдоним в предложении GROUP BY из-за логического порядка обработки. Предложение GROUP BY обрабатывается перед предложением SELECT, поэтому псевдоним неизвестен при оценке предложения GROUP BY. Это также объясняет, почему вы можете использовать псевдоним в предложении ORDER BY.

Вот один из источников информации о этапах логической обработки SQL Server .


8

Я не отвечаю, почему это так, но хотел показать способ обойти это ограничение в SQL Server, используя CROSS APPLYдля создания псевдоним. Затем вы используете его в GROUP BYпредложении, например, так:

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

4

Внимание: использование псевдонима в Group By (для служб, которые его поддерживают, например, postgres) может привести к непредвиденным результатам. Например, если вы создаете псевдоним, который уже существует во внутреннем операторе, Group By выберет имя внутреннего поля.

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

Некоторые СУБД позволяют использовать псевдоним вместо повторения всего выражения.
Teradata является одним из таких примеров.

Я избегаю обозначения порядкового номера, как это рекомендовано Биллом, по причинам, задокументированным в этом вопросе SO .

Простая и надежная альтернатива - всегда повторять выражение в предложении GROUP BY.
DRY НЕ применяется к SQL.


1

Остерегайтесь использования псевдонимов при группировке результатов из представления в SQLite. Вы получите неожиданные результаты, если псевдоним совпадает с именем столбца любых базовых таблиц (для представлений).


0

В тот день я обнаружил, что Rdb, прежний продукт DEC, теперь поддерживаемый Oracle, позволяет использовать псевдоним столбца в GROUP BY. Основная версия Oracle до версии 11 не позволяет использовать псевдоним столбца в GROUP BY. Не уверен, что Postgresql, SQL Server, MySQL и т. Д. Будут или не будут позволять. YMMV.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.