SQL: uso de alias en Agrupar por

143

Solo curiosidad por la sintaxis SQL. Entonces si tengo

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY itemName, FirstLetter

Esto sería incorrecto porque

GROUP BY itemName, FirstLetter 

realmente debería ser

GROUP BY itemName, substring(itemName, 1,1)

Pero, ¿por qué no podemos simplemente usar el primero por conveniencia?

Haoest
fuente
13
eso está permitido en Postgresql
Michael Buen
77
MySQL también lo permite
Kip
1
¿De qué rdbms estás hablando?
Shiwangini

Respuestas:

292

SQL se implementa como si se ejecutara una consulta en el siguiente orden:

  1. Cláusula FROM
  2. Dónde cláusula
  3. Cláusula GROUP BY
  4. Que tiene cláusula
  5. Cláusula SELECT
  6. Cláusula ORDER BY

Para la mayoría de los sistemas de bases de datos relacionales, este orden explica qué nombres (columnas o alias) son válidos porque deben haberse introducido en un paso anterior.

Por lo tanto, en Oracle y SQL Server, no puede usar un término en la cláusula GROUP BY que defina en la cláusula SELECT porque GROUP BY se ejecuta antes que la cláusula SELECT.

Sin embargo, hay excepciones: MySQL y Postgres parecen tener una inteligencia adicional que lo permite.

Codo
fuente
3
Me gusta esta explicación Aunque no puedo especular qué tan difícil es agregarlo a un motor como azúcar sintáctico.
Haoest
11
¿Alguna idea de si el DB es lo suficientemente inteligente como para darse cuenta de que la misma expresión está en las cláusulas SELECT y GROUP BY sin reevaluar las expresiones? es decir, si lo hay GROUP BY substring(itemName, 1,1), ¿es la base de datos lo suficientemente inteligente como para no tomar el golpe de rendimiento de volver a calcular la subcadena en la cláusula SELECT?
Kip
10
En la cláusula SELECT de una consulta con agrupación, solo tiene acceso a las expresiones GROUP BY y los valores agregados. Entonces no se trata de ser inteligente; tiene que implementarse de esa manera para que la agrupación funcione. (Y es requerido por el estándar SQL). Pero incluso en casos más triviales (por ejemplo, la misma expresión en la cláusula WHERE y SELECT), los sistemas de base de datos de última generación ciertamente solo lo computarán una vez. Esta optimización se llama eliminación de subexpresión común .
Codo
66
¿Qué tiene que ver la orden de ejecución con la pregunta? No es como si el autor de la pregunta intentara GRUPAR POR en COUNT (). De hecho, la consulta según lo solicitado funciona bien en MySQL y probablemente en PostgreSQL como se señala en los comentarios.
1
Para mysql, sql_modesin incluir ONLY_FULL_GROUP_BY en la máscara de bits, el Optimizador tiene la oportunidad de ofrecer mejores resultados con un uso variado / diferente del alias en la HAVINGcláusula.
Dibujó el
28

Siempre puede usar una subconsulta para poder usar el alias; Por supuesto, verifique el rendimiento (es posible que el servidor db se ejecute de la misma manera, pero nunca está de más verificarlo):

SELECT ItemName, FirstLetter, COUNT(ItemName)
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter
    FROM table1
    ) ItemNames
GROUP BY ItemName, FirstLetter
Chris Shaffer
fuente
2
Deben evitarse las subconsultas siempre que sea posible debido al mal rendimiento. Usar una copia de la función es mucho mejor porque, por supuesto, el optimizador de la base de datos lo detecta y lo hace solo una vez.
Roland
1
@Roland pero no hay un plan de ejecución diferente en ese caso. ¿Hay alguna otra consideración de rendimiento?
Guido Mocha
@Roland, deben evitarse las subconsultas correlacionadas u otra sintaxis que conduzca a bucles o comportamiento fila por fila, y existe un límite sobre qué tan profundo debe ir con las subconsultas anidadas, pero generalmente no es cierto que las subconsultas conduzcan a mal desempeño. En este caso, como dijo Chris, puede verificar el plan de ejecución (también conocido como plan de consulta, explicar el plan) comparando con y sin la subconsulta, y ver si realmente hay alguna diferencia. Casi todos los motores de bases de datos volverán a escribir su consulta para que no tenga el control total de lo que se ejecuta. Ese es el punto de la sintaxis declarativa.
Davos
16

Al menos en PostgreSQL puede usar el número de columna en el conjunto de resultados en su cláusula GROUP BY:

SELECT 
 itemName as ItemName,
 substring(itemName, 1,1) as FirstLetter,
 Count(itemName)
FROM table1
GROUP BY 1, 2

Por supuesto, esto comienza a ser complicado si lo hace de forma interactiva y edita la consulta para cambiar el número o el orden de las columnas en el resultado. Pero aún.

Bill Gribble
fuente
GROUP BY FirstLetterestá permitido en Postgresql. A saber, intente ejecutar esto en Postgresql: seleccione substring (table_name, 1,2) como tname del grupo information_schema.tables por tname
Michael Buen
1
@MichaelBuen Me parece potencialmente problemático. En una prueba rápida, ¿parece que hay un alias y una columna de tabla base con el mismo nombre que este último tiene prioridad? SQL Fiddle . Entonces, si confía en este grupo por alias, un cambio de esquema posterior podría interrumpir silenciosamente su consulta y cambiar la semántica.
Martin Smith
@MartinSmith solo sabía que ahora es un problema, se abstendrá de usar eso, gracias. Dado que PostgreSQL permite ese acceso directo, deberían dar prioridad al alias, de lo contrario no deberían permitir ese acceso directo en absoluto.
Michael Buen
Esta fue una idea terrible de los diseñadores de PostgreSQL. Es confuso tan pronto como intenta GROUP BYcualquier expresión que contenga funciones agregadas o funciones de ventana, que "obviamente" no funciona.
Lukas Eder el
13

SQL Server no le permite hacer referencia al alias en la cláusula GROUP BY debido al orden lógico de procesamiento. La cláusula GROUP BY se procesa antes que la cláusula SELECT, por lo que el alias no se conoce cuando se evalúa la cláusula GROUP BY. Esto también explica por qué puede usar el alias en la cláusula ORDER BY.

Aquí hay una fuente de información sobre las fases de procesamiento lógico de SQL Server .

bobs
fuente
8

No estoy respondiendo por qué es así, pero solo quería mostrar una forma de evitar esa limitación en SQL Server utilizando CROSS APPLYpara crear el alias. Luego lo usa en la GROUP BYcláusula, así:

SELECT 
 itemName as ItemName,
 FirstLetter,
 Count(itemName)
FROM table1
CROSS APPLY (SELECT substring(itemName, 1,1) as FirstLetter) Alias
GROUP BY itemName, FirstLetter
Ricardo
fuente
4

Tenga en cuenta que el uso de alias en Group By (para servicios que lo admiten, como postgres) puede tener resultados no deseados. Por ejemplo, si crea un alias que ya existe en la declaración interna, Group By elegirá el nombre del campo interno.

-- Working example in postgres
select col1 as col1_1, avg(col3) as col2_1
from
    (select gender as col1, maritalstatus as col2, 
    yearlyincome as col3 from customer) as layer_1
group by col1_1;

-- Failing example in postgres
select col2 as col1, avg(col3)
from
    (select gender as col1, maritalstatus as col2,
    yearlyincome as col3 from customer) as layer_1
group by col1;
Shannon S
fuente
3

Algunos DBMS le permitirán usar un alias en lugar de tener que repetir toda la expresión.
Teradata es uno de esos ejemplos.

Evito la notación de posición ordinal según lo recomendado por Bill por razones documentadas en esta pregunta SO .

La alternativa fácil y robusta es repetir siempre la expresión en la cláusula GROUP BY.
DRY NO se aplica a SQL.

carne_mecánica
fuente
1

Tenga cuidado con el uso de alias al agrupar los resultados de una vista en SQLite. Obtendrá resultados inesperados si el nombre del alias es el mismo que el nombre de la columna de las tablas subyacentes (para las vistas).

GGGforce
fuente
0

En el pasado descubrí que Rdb, el antiguo producto DEC ahora compatible con Oracle, permitía usar el alias de columna en GROUP BY. Oracle convencional a través de la versión 11 no permite que el alias de columna se use en GROUP BY. No estoy seguro de qué permitirá o no permitirá Postgresql, SQL Server, MySQL, etc. YMMV.

Bob Jarvis - Restablece a Monica
fuente