registros - ¿Por qué SQL me obliga a repetir todos los campos no agregados de mi cláusula SELECT en mi cláusula GROUP BY?
sql contar registros agrupados (10)
Debido a que son dos cosas diferentes, puede agrupar por elementos que no están en la cláusula de selección
EDITAR:
Además, ¿es seguro hacer esa suposición?
Tengo una declaración de SQL
Select ClientName, InvAmt, Sum(PayAmt) as PayTot
¿Es "correcto" que el servidor suponga que quiero 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
arrojar un error, lo que me llevó a cambiar el código a
Select ClientName, Sum(InvAmt) as InvTot, Sum(PayAmt) as PayTot
Group By ClientName
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 repetir usted mismo.
¿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 le permiten tener diferentes campos en el GROUP BY que en el SELECT (de ahí el 99%, no el 100%), pero seguramente esa es una excepción muy leve.
¿Puede alguien explicar lo que se supone que debe devolverse si usa campos diferentes?
Gracias.
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?
Aunque no tengo una respuesta. Ciertamente, parece un momento incómodo para el lenguaje.
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 estaba documentado en The Pragmatic Programmer .
No todos los DB requieren la lista completa: Sybase, por ejemplo, ejecutará con gusto consultas como
SELECT a, b, COUNT(*)
FROM some_table
GROUP BY a
... que (al menos cada vez que ejecuté accidentalmente un monstruo como ese) a menudo conduce a tan enormes conjuntos de registros inadvertidos que rápidamente surgen solicitudes de pánico, pidiendo a los DBA que reboten en 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 implementar correctamente el estándar SQL.
Tal vez necesitamos una forma abreviada, llámalo GroupSelect
GroupSelect Field1, Field2, sum(Field3) From SomeTable Where (X = "3")
De esta forma, el analizador solo arrojará un error si omite una función agregada.
Tiendo a estar de acuerdo con usted: este es uno de los muchos casos en los que SQL debería tener valores predeterminados ligeramente más inteligentes para que todos nos tipeamos. Por ejemplo, imagine si esto fuera legal:
Select ClientName, InvoiceAmount, Sum(PaymentAmount) Group By *
donde "*" significaba "todos los campos no agregados". Si todos supieran que así es como funcionaba, entonces no habría confusión. Podría sub en una lista específica de campos si quisiera hacer algo complicado, pero el símbolo significa "todos ellos" (que en este contexto significa, todos los posibles ).
De acuerdo, "*" significa algo diferente aquí que en la cláusula SELECT, por lo 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 atrincherado para hacer muchos cambios grandes como ese.
La buena razón es que obtendría resultados incorrectos con más frecuencia si no especificara todas las columnas. Supongamos que tiene tres columnas, col1
, col2
y col2
.
Supongamos que sus datos se ven así:
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
daría los siguientes resultados:
Col1 Col2 Col3
a b 4
a c 1
b b 2
¿Cómo lo interpretaría?
select col1, col2, sum(col3) from mytable group by col1
Mi conjetura sería
Col1 Col2 Col3
a b 5
a c 5
b b 2
Estos son claramente malos resultados. Por supuesto, cuanto más compleja sea la consulta y más unidas, menos probable será que la consulta arroje resultados correctos o que el programador sepa si son incorrectas.
Personalmente, me alegro de que el group by
requiera los campos.
Puede haber una situación en la que necesite 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.
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 las columnas. El grupo by se aplica a la función de agregado interno. 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 eso.
Como grupo por resultado, una sola tupla para un grupo completo de tuplas, por lo que los demás atributos no agrupados por atributos se deben usar solo en la función agregada. Si agrega no grupo por atributo en seleccionar, entonces sql no puede decidir qué valor seleccionar de ese grupo.
Comparto la opinión de la OP de que repetir es un poco molesto, especialmente si los campos no agregados contienen enunciados elaborados como ifs y funciones y un montón de otras cosas. Sería bueno si hubiera una taquigrafía en la cláusula group by - 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.