2010-10-01 9 views
88

Simplemente curiosidad sobre la sintaxis de SQL. Así que si tengoSQL - alias en el grupo por

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 estar

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

Pero por qué no podemos simplemente utilizar la antigua por conveniencia?

+5

que está permitido en PostgreSQL –

+3

MySQL permite también – Kip

+0

SQLite permite que –

Respuesta

161

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

  1. cláusula FROM
  2. cláusula WHERE
  3. cláusula GROUP BY
  4. HAVING
  5. cláusula SELECT
  6. ORDEN BY cláusula

Para la mayoría de los sistemas de bases de datos relacionales, esta 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 de la cláusula SELECT.

Aunque hay excepciones: MySQL y Postgres parecen tener mayor inteligencia que lo permite.

+0

Me gusta esta explicación. Aunque no puedo especular sobre lo difícil que es agregarlo a un motor como azúcar sintáctico. – Haoest

+8

¿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 volver a evaluar las expresiones? es decir, si hay una subcadena 'GROUP BY '(itemName, 1,1)', ¿la base de datos es lo suficientemente inteligente como para no tomar el golpe de rendimiento de volver a calcular la subcadena en la cláusula SELECT? – Kip

+8

En la cláusula SELECT de una consulta con agrupamiento, solo tiene acceso a las expresiones GROUP BY y a 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 WHERE y en la cláusula SELECT), los sistemas de bases de datos de última generación solo lo computarán una vez. Esta optimización se llama * eliminación de sub-expresión común *. – Codo

11

Al menos en PostgreSQL puede utilizar el número de columna del 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 empieza a ser un problema si usted está haciendo esto de forma interactiva y editar la consulta a cambie el número o el orden de las columnas en el resultado. Pero aún.

+0

'GROUP BY FirstLetter' está permitido en PostgreSQL. A saber, intente ejecutar esto en Postgresql: seleccione una subcadena (table_name, 1,2) como tname de information_schema.tables group by tname –

+1

@MichaelBuen Me parece potencialmente problemático. A partir de una prueba rápida, parece que si hay un alias y una columna de la tabla base con el mismo nombre, esta última tiene prioridad. [SQL Fiddle] (http://sqlfiddle.com/#!15/d41d8/1920). Por lo tanto, si confía en este grupo por alias, un cambio de esquema posterior podría interrumpir silenciosamente su consulta y cambiar la semántica. –

+0

@MartinSmith solo sabía ahora que es un gotcha, 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. –

2

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 recomendada por Bill por motivos documentados en this SO question.

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

22

Siempre puede usar una subconsulta para que pueda usar el alias; Por supuesto, comprobar el rendimiento (Posible el servidor db se ejecutará tanto en el mismo, pero nunca está de más comprobar):

SELECT ItemName, FirstLetter, COUNT(ItemName) 
FROM (
    SELECT ItemName, SUBSTRING(ItemName, 1, 1) AS FirstLetter 
    FROM table1 
    ) ItemNames 
GROUP BY ItemName, FirstLetter 
+0

gracias, ¡buena idea! – digz6666

0

vuelta en el día me encontré con que Rdb, el producto anterior diciembre ahora con el apoyo de Oracle permite que la alias de columna que se utilizará en GROUP BY. Mainstream Oracle a través de la versión 11 no permite que el alias de columna se use en GROUP BY. No estoy seguro de lo que Postgresql, SQL Server, MySQL, etc. permitirá o no. YMMV.

8

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 de la cláusula SELECT, por lo que no se conoce el alias 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 el SQL Server logical processing phases.

1

Tenga cuidado con el uso de alias al agrupar los resultados de una vista en SQLite. Obtendrá resultados inesperados si el nombre de alias es el mismo que el nombre de columna de cualquier tabla subyacente (a las vistas).

3

Tenga cuidado de no utilizar alias en el grupo por (para los servicios que lo soportan, como postgres) tener resultados no deseados Por ejemplo, si crea un alias que ya existe en la instrucción interna, Group By seleccionará 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; 
0

No voy a responder por qué es así, pero sólo quería mostrar una forma de evitar que la limitación en SQL Server mediante el uso de CROSS APPLY para crear el alias. A continuación se usa en la cláusula GROUP BY, así:

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