¿Por qué SQL me obliga a repetir todos los campos no agregados de mi cláusula SELECT en mi cláusula GROUP BY? [cerrado]

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

  •  03-07-2019
  •  | 
  •  

Pregunta

Esto me ha molestado por mucho tiempo.

El 99% del tiempo, la cláusula GROUP BY es una copia exacta de la cláusula SELECT, menos las funciones agregadas (MAX, SUM, etc.).
Esto rompe el principio de no repetirse.

¿Cuándo puede la cláusula GROUP BY no contener una copia exacta de la cláusula SELECT menos las funciones agregadas?

editar

Me doy cuenta de que algunas implementaciones te permiten tener diferentes campos en GROUP BY que en SELECT (por lo tanto, 99%, no 100%), ¿pero es una excepción muy pequeña? ¿Alguien puede explicar qué se supone que debe devolverse si usa campos diferentes?

Gracias.

¿Fue útil?

Solución

Tiendo a estar de acuerdo con usted: este es uno de los muchos casos en que SQL debería tener valores predeterminados un poco más inteligentes para ahorrarnos algo de escritura. Por ejemplo, imagina si esto fuera legal:

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

donde " * " significaba " todos los campos no agregados " ;. Si todos supieran que así funcionaba, no habría confusión. Si desea hacer algo complicado, puede colocar una lista específica de campos, pero splat significa "todos" " (lo que en este contexto significa, todos los posibles ).

Concedido, " * " significa algo diferente aquí que en la cláusula SELECT, así que tal vez un personaje diferente funcionaría mejor:

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

Hay algunas otras áreas como esa donde SQL simplemente no es tan elocuente como podría ser. Pero en este punto, probablemente esté demasiado arraigado para hacer muchos cambios grandes como ese.

Otros consejos

Debido a que son dos cosas diferentes, puede agrupar por elementos que no están en la cláusula select

EDITAR:

Además, ¿es seguro hacer esa suposición?

Tengo una declaración SQL

Select ClientName, InvAmt, Sum(PayAmt) as PayTot

¿Es correcto? para que el servidor asuma que deseo agrupar por ClientName AND InvoiceAmount? Personalmente prefiero (y creo que es más seguro) tener este código

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

arroja un error, solicitándome que cambie el código a

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

Espero / espero que veamos algo más completo pronto; una lección de historia de SQL sobre el tema sería útil e informativa. ¿Nadie? ¿Nadie? Bueller?

Mientras tanto, puedo observar lo siguiente:

SQL es anterior al principio DRY, al menos en la medida en que se documentó en El programador pragmático .

No todas las bases de datos requieren la lista completa: Sybase, por ejemplo, ejecutará consultas como

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

... que (al menos cada vez que corrí accidentalmente un monstruo) a menudo lleva a conjuntos de registros inadvertidos tan enormes que rápidamente surgen solicitudes de pánico, suplicando a los DBA que devuelvan el servidor. El resultado es una especie de producto cartesiano parcial, pero creo que en su mayoría puede ser un error por parte de Sybase para implementar el estándar SQL correctamente.

Quizás necesitemos un formulario abreviado: llámelo GroupSelect

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

De esta forma, el analizador solo necesita lanzar un error si omite una función agregada.

La buena razón para ello es que obtendría resultados incorrectos más a menudo que no si no especificara todas las columnas. Suponga que tiene tres columnas, col1 , col2 y col3 .

Supongamos que sus datos se parecen a esto:

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

seleccione col1, col2, sum (col3) de mytable group by col1, col2
daría los siguientes resultados:

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

¿Cómo se interpretaría? seleccione col1, col2, sum (col3) de mytable group by col1

Mi conjetura sería

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

Estos son resultados claramente malos. Por supuesto, cuanto más compleja sea la consulta y más se una, menos probable será que la consulta arroje resultados correctos o que el programador sepa incluso si son incorrectos.

Personalmente me alegro de que group by requiera los campos.

Estoy de acuerdo con GROUP BY ALL, GROUP BY * o algo similar. Como se mencionó en la publicación original, en el 99% (quizás más) de los casos que desea agrupar por todas las columnas / expresiones no agregadas.

Sin embargo, aquí hay un ejemplo en el que necesitaría columnas GROUP BY, por razones de compatibilidad con versiones 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>

Esto funciona en Oracle. Lo uso para estimar la selectividad en columnas. El grupo by se aplica a la función agregada interna. Luego, se aplica el agregado externo.

Sería bueno presentar una sugerencia para esta mejora al estándar SQL. Simplemente no sé cómo funciona.

En realidad, ¿no sería eso el 100% del tiempo? ¿Hay algún caso en el que pueda tener una columna (no agregada) en la selección que no esté en GROUP BY?

Sin embargo, no tengo una respuesta. Ciertamente, parece un momento incómodo para el idioma.

Comparto la opinión del operador de que repetir es un poco molesto, especialmente si los campos no agregados contienen declaraciones elaboradas como ifs y funciones y muchas otras cosas. Sería bueno si hubiera alguna taquigrafía en el grupo por cláusula, al menos un alias de columna. Hacer referencia a las columnas por número puede ser otra opción, aunque probablemente tenga sus propios problemas.

Podría haber una situación en la que necesitara extraer una identificación de todas las filas agrupadas y la suma de sus cantidades, por ejemplo. En este caso, es decir, agruparlos por nombre y dejar los identificadores no agrupados. SQLite parece funcionar de esta manera.

Desde grupo por resultado en una sola tupla para un grupo completo de tuplas, por lo que otros atributos no agrupados por deben usarse solo en función agregada. Si u agrega un atributo no de grupo en select, entonces sql no puede decidir qué valor seleccionar de ese grupo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top