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

Это долго меня раздражало.

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

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

изменить

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

Спасибо.

Ответ 1

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

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

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

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

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

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

Ответ 2

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

EDIT:

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

У меня есть оператор 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

Ответ 3

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

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

SQL предшествует принципу DRY, по крайней мере, насколько это было документировано в Pragmatic Programmer.

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

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

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

Ответ 4

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

Ответ 5

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

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

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

Ответ 6

Я согласен с 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. Я просто не знаю, как это работает.

Ответ 7

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

У меня нет ответа. Это, конечно, похоже на неловкий момент для языка.

Ответ 8

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

Ответ 9

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

Ответ 10

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