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

StackOverflow https://stackoverflow.com/questions/416625

  •  03-07-2019
  •  | 
  •  

Вопрос

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

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

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

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

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

Спасибо.

Это было полезно?

Решение

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

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

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

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

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

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

Другие советы

Поскольку это две разные вещи, вы можете группировать их по элементам, которых нет в предложении 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

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

Пока же могу отметить следующее:

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

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

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

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

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

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

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

Веская причина в том, что вы чаще будете получать неправильные результаты, если не укажете все столбцы.Предположим, у вас есть три столбца, 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 требуются поля.

Я согласен с 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.Я использую его для оценки избирательности по столбцам.Группа by применяется к внутренней агрегатной функции.Затем наносится внешний заполнитель.

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

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

Хотя у меня нет ответа.Это действительно кажется неловким моментом для языка.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top