Por que SQL forçar-me a repetir todos os campos não agregados da minha cláusula SELECT no meu cláusula GROUP BY? [fechadas]

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Isso tem me incomodado por um longo tempo.

99% do tempo, a cláusula GROUP BY é uma cópia exata da cláusula SELECT, menos as funções de agregação (MAX, SUM, etc.).
Isso quebra o Do not Repeat Yourself princípio.

Quando pode a cláusula GROUP BY não contém uma cópia exata da cláusula SELECT menos as funções de agregação?

editar

Eu percebo que algumas implementações permitem que você tenha diferentes campos no GROUP BY do que no SELECT (daí 99%, não 100%), mas com certeza isso é uma exceção muito menor?
Alguém pode explicar o que é suposto ser devolvido se você usar campos diferentes?

Graças.

Foi útil?

Solução

Eu tendo a concordar com você - este é um dos muitos casos em que o SQL deve ter padrões ligeiramente mais inteligentes para salvar a todos nós a digitação. Por exemplo, imagine se isso fosse legal:

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

, onde "*" significa "todos os campos não-agregado". Se todo mundo sabia que é como ele trabalhou, então não haveria confusão. Você poderia sub de uma lista específica de campos se você queria fazer algo complicado, mas os meios splat "todos 'em" (que neste meio de contexto, todos os possíveis uns).

Com certeza, "*" significa algo diferente aqui do que na cláusula SELECT, então talvez um personagem diferente poderia funcionar melhor:

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

Existem algumas outras áreas como essa, onde SQL só não é tão eloqüente quanto poderia ser. Mas, neste ponto, é provavelmente muito enraizada a fazer muitas mudanças grandes assim.

Outras dicas

Porque são duas coisas diferentes, você pode agrupar por itens que não estão na cláusula select

EDIT:

Além disso, é seguro para fazer essa suposição?

Eu tenho uma instrução SQL

Select ClientName, InvAmt, Sum(PayAmt) as PayTot

É "correta" para o servidor para assumir Quero grupo por ClientName E InvoiceAmount? Eu pessoalmente prefiro (e acho que é mais seguro) para ter este código

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

lançar um erro, levando-me para alterar o código para

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

espero / esperar vamos ver algo em breve mais abrangente; uma lição de história SQL sobre o assunto seria útil e informativo. Qualquer um? Qualquer um? Bueller?

Entretanto, posso observar o seguinte:

SQL antecede o princípio do DRY, pelo menos na medida em que foi documentado em The Pragmatic Programmer .

Nem todos os bancos de dados exigem a lista completa: Sybase, por exemplo, terá todo o prazer executar consultas como

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

... que (pelo menos cada vez que eu acidentalmente correu um monstro) muitas vezes leva a tais enormes conjuntos de registros inadvertidas que os pedidos de pânico rapidamente se seguem, implorando aos DBAs para devolver o servidor. O resultado é um tipo de produto cartesiano parcial, mas eu acho que pode ser maioritariamente uma falha por parte da Sybase para implementar o padrão SQL corretamente.

Talvez tenhamos uma forma abreviada - chamá-lo GroupSelect

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

Desta forma, a necessidade analisador única lançar um erro se você deixar de fora uma função de agregação.

A boa razão para isso é que você deseja obter resultados incorretos na maioria das vezes, se você não especificar todas as colunas. Suponha que você tenha três colunas, col1, col2 e col3.

Suponha que a sua aparência de dados como este:

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
daria os seguintes resultados:

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

Como seria interpretar
select col1, col2, sum(col3) from mytable group by col1

Meu palpite seria

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

Estes são claramente maus resultados. É claro que quanto mais complexa a consulta e quanto mais se junta a menos provável seria que a consulta retornaria resultados corretos ou que o programador iria mesmo saber se eles estão incorretos.

Pessoalmente, eu estou contente que group by requer os campos.

Eu concordo com GROUP BY ALL, GROUP BY *, ou algo similar. Como mencionado no post original, em 99% (talvez mais) dos casos que pretende agrupar por todos os não-agregadas colunas / expressões.

Aqui, porém, um exemplo onde você precisaria GROUP BY colunas, por razões de compatibilidade com versões anteriores.

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>

Isso funciona em Oracle. Eu usá-lo para estimar a seletividade em colunas. O grupo é aplicada por para a função de agregação interno. Em seguida, é aplicado o agregado exterior.

Seria bom a apresentar uma sugestão para esta melhoria com o padrão SQL. Eu só não sei como isso funciona.

Na verdade, que não iria ser 100% do tempo? Existe um caso em que você pode ter uma coluna (não agregada) na escolha que não está no GROUP BY?

Eu não tenho uma resposta embora. Ele certamente parece ser um momento de constrangimento para o idioma.

Eu compartilho da opinião do op que a repetição é um pouco irritante, especialmente se os campos não-agregadas conter declarações elaboradas como ifs e funções e um monte de outras coisas. Seria bom se pudesse haver algum taquigrafia no grupo pela cláusula - pelo menos um alias de coluna. Referindo-se às colunas de número pode ser outra opção, embora um que provavelmente tem seus próprios problemas.

Pode haver uma situação que você necessário para extrair um ID de todas as linhas agrupadas, e soma das suas quantidades - por exemplo. Neste caso, você faria isto é agrupá-los por nome e deixar ids não agrupadas. SQLite parece funcionar desta forma.

Uma vez que grupo por resultado na tupla único para todo um grupo de tuplas assim outro grupo não por atributos deve ser utilizado apenas em função agregada. Se u adicionar non grupo por atributo no seleto então sql não pode decidir qual o valor a ser escolha desse grupo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top