Почему SQL заставляет меня повторять все неагрегированные поля из моего предложения SELECT в моем предложении GROUP BY?

Меня это беспокоило долгое время.

В 99% случаев предложение GROUP BY является точной копией предложения SELECT за вычетом агрегатных функций (MAX, SUM и т. Д.).
Это нарушает принцип «Не повторяйся».

Когда предложение GROUP BY не может содержать точную копию предложения SELECT за вычетом агрегатных функций?

редактировать

Я понимаю, что некоторые реализации позволяют вам иметь разные поля в GROUP BY, чем в SELECT (следовательно, 99%, а не 100%), но, конечно, это очень незначительное исключение?
Может ли кто-нибудь объяснить, что должно быть возвращено если использовать разные поля?

Спасибо.


person AJ.    schedule 06.01.2009    source источник


Ответы (10)


Я склонен с вами согласиться - это один из многих случаев, когда SQL должен иметь несколько более разумные значения по умолчанию, чтобы нам всем не нужно было печатать. Например, представьте, если бы это было законно:

Select ClientName, InvoiceAmount, Sum(PaymentAmount) Group By *

где «*» означает «все неагрегированные поля». Если бы все знали, как это работает, не было бы путаницы. Вы можете добавить подписку в определенный список полей, если хотите сделать что-то сложное, но знак означает «все из них» (что в данном контексте означает все возможные).

Конечно, "*" здесь означает нечто иное, чем в предложении SELECT, поэтому, возможно, другой символ будет работать лучше:

Select ClientName, InvoiceAmount, Sum(PaymentAmount) Group By !

Есть еще несколько подобных областей, в которых SQL не так красноречив, как мог бы быть. Но на данный момент это, вероятно, слишком укоренилось, чтобы вносить такие большие изменения.

person Ian Varley    schedule 06.01.2009
comment
да. Спасибо. такие вещи звучат разумно. Я предполагаю, что на самом деле ответа нет. ;) - person AJ.; 06.01.2009
comment
Однако сложно выбрать значащий символ или ключевое слово. Ключевое слово * или ALL семантически неверно, так как вы группируете не по ВСЕМ (вы группируете по всем, ЗА ИСКЛЮЧЕНИЕМ ...). Это неплохая идея, хотя я не понимаю, как это будет работать, не будучи семантическим кладжем. - person Binary Worrier; 12.01.2009
comment
Почему бы просто не использовать GROUP вместо GROUP BY ‹какой-нибудь подстановочный знак›? - person Martijn; 15.06.2010
comment
Конечно, это тоже сработает, но я подозреваю, что для нынешних программистов SQL это может быть менее интуитивно понятно. В этом отношении синтаксис также может заключаться в том, чтобы полностью исключить его, и синтаксический анализатор будет знать, что вы должны автоматически группировать по любым неагрегированным полям. Вероятно, именно так это должно было быть сделано в первую очередь, ИМО, но, возможно, это пытается быть настолько полезным, что в конечном итоге вы запутаете территорию. - person Ian Varley; 23.06.2010

Поскольку это две разные вещи, вы можете группировать их по элементам, которых нет в предложении select.

РЕДАКТИРОВАТЬ:

Кроме того, безопасно ли делать это предположение?

У меня есть инструкция SQL

Select ClientName, InvAmt, Sum(PayAmt) as PayTot

«Правильно» ли сервер предполагать, что я хочу группировать по ClientName И InvoiceAmount? Я лично предпочитаю (и считаю, что это безопаснее) иметь этот код

Select ClientName, InvAmt, Sum(PayAmt) as PayTot
Group By ClientName

выдает ошибку, предлагая изменить код на

Select ClientName, Sum(InvAmt) as InvTot, Sum(PayAmt) as PayTot
Group By ClientName
person Binary Worrier    schedule 06.01.2009
comment
Это правда, но зачем требовать столбцы в списке SELECT, если они обязательны? SELECT a, MAX(c) FROM t GROUP BY b может означать группировку по a, не так ли? Я думаю, это может быть просто проблема ясности. - person Mike Woodhouse; 06.01.2009
comment
Подразумеваемые операции - это проклятие отладки и тестирования. - person Robert C. Barth; 06.01.2009

Я надеюсь / ожидаю, что мы скоро увидим что-то более исчерпывающее; урок истории SQL по этой теме был бы полезен и информативен. Кто-нибудь? Кто-нибудь? Бьюллер?

Тем временем я могу наблюдать следующее:

SQL предшествует принципу DRY, по крайней мере, в той мере, в какой он был задокументирован в Прагматичный программист.

Не всем БД требуется полный список: например, Sybase с радостью выполнит такие запросы, как

SELECT a, b, COUNT(*)
FROM some_table
GROUP BY a

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

person Mike Woodhouse    schedule 06.01.2009

Возможно, нам понадобится сокращенная форма - назовите ее GroupSelect

GroupSelect Field1, Field2, sum(Field3) From SomeTable Where (X = "3")

Таким образом, синтаксическому анализатору потребуется только выдать ошибку, если вы не укажете агрегатную функцию.

person Peter T. LaComb Jr.    schedule 06.01.2009

Хорошая причина для этого в том, что вы чаще всего получали бы неверные результаты, если бы не указали все столбцы. Предположим, у вас есть три столбца: col1, col2 и col3.

Предположим, ваши данные выглядят так:

Col1  Col2 Col3
a      b    1
a      c    1
b      b    2
a      b    3

select col1, col2, sum(col3) from mytable group by col1, col2
даст следующие результаты:

Col1  Col2 Col3
a      b    4
a      c    1
b      b    2

Как бы он интерпретировал
select col1, col2, sum(col3) from mytable group by col1

Я предполагаю, что

Col1  Col2 Col3
a      b    5
a      c    5
b      b    2

Это явно плохие результаты. Конечно, чем сложнее запрос и чем больше объединений, тем меньше вероятность того, что запрос вернет правильные результаты или что программист даже узнает, были ли они неправильными.

Лично я рад, что group by требует полей.

person HLGEM    schedule 06.01.2009
comment
MySQL - как пример поддерживающего это синтаксиса SQL - не дает никаких гарантий относительно того, что будет возвращено в этом случае. Фактически, это может быть любое случайное значение из набора результатов. Хотя я никогда не видел, чтобы это происходило, оно могло даже возвращать атрибуты отношения из разных строк одного и того же отношения. - person rich remer; 12.07.2016

Я согласен с GROUP BY ALL, GROUP BY * или чем-то подобным. Как упоминалось в исходном сообщении, в 99% (возможно, больше) случаев вы хотите сгруппировать по всем неагрегированным столбцам / выражениям.

Однако вот один пример, в котором вам понадобятся столбцы GROUP BY по причинам обратной совместимости.

SELECT 
  MIN(COUNT(*)) min_same_combination_cnt, 
  MAX(COUNT(*)) max_same_comb_cnt, 
  AVG(COUNT(*)) avg_same_comb_cnt, 
  SUM(COUNT(*)) total_records,
  COUNT(COUNT(*)) distinct_combinations_cnt
FROM <some table>
GROUP BY <list of columns>

Это работает в Oracle. Я использую его для оценки избирательности по столбцам. Группа по применяется к внутренней агрегатной функции. Затем наносится внешний заполнитель.

Было бы неплохо выдвинуть предложение по этому усовершенствованию стандарта SQL. Я просто не знаю, как это работает.

person Milan    schedule 16.07.2012

На самом деле, разве это не было бы в 100% случаев? Есть ли случай, когда у вас может быть (неагрегированный) столбец в выбранном элементе, которого нет в GROUP BY?

Но у меня нет ответа. Это определенно кажется неудобным моментом для языка.

person Mark Bostleman    schedule 06.01.2009

Я разделяю мнение оператора о том, что повторение немного раздражает, особенно если неагрегированные поля содержат сложные инструкции, такие как if, функции и многое другое. Было бы неплохо, если бы в предложении group by было какое-то сокращение - хотя бы псевдоним столбца. Обращение к столбцам по номеру может быть другим вариантом, хотя, вероятно, имеет свои собственные проблемы.

person Thorsten    schedule 06.01.2009
comment
хороший момент о длинных выражениях. это добавляет боли. - person AJ.; 07.01.2009

Может возникнуть ситуация, когда вам нужно извлечь один идентификатор из всех сгруппированных строк и сумму их количества - например. В этом случае вы должны сгруппировать их по имени и оставить идентификаторы не сгруппированными. SQLite, похоже, работает именно так.

person Yar    schedule 11.02.2012

Так как группировка по приводит к одному кортежу для всей группы кортежей, поэтому другие атрибуты, не связанные с группировкой по, должны использоваться только в агрегатной функции. Если вы добавляете атрибут без группы по атрибуту в select, тогда sql не может решить, какое значение выбрать из этой группы.

person user2133312    schedule 04.03.2013