¿Por qué MySQL permite que HAVING use alias SELECT?

14

En SQL, que yo sepa, el orden de procesamiento de consultas lógicas, que es el orden de interpretación conceptual, comienza con FROM de la siguiente manera:

  1. DESDE
  2. DÓNDE
  3. AGRUPAR POR
  4. TENIENDO
  5. SELECCIONE
  6. ORDENAR POR

Siguiendo esta lista, es fácil ver por qué no puede tener alias SELECT en una cláusula WHERE, porque el alias aún no se ha creado. T-SQL (SQL Server) sigue esto estrictamente y no puede usar alias SELECT hasta que haya pasado SELECT.

Pero en MySQL es posible usar alias SELECT en la cláusula HAVING aunque debería (lógicamente) procesarse antes de la cláusula SELECT. como puede ser esto posible?

Para dar un ejemplo:

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;

La declaración no es válida en T-SQL (porque HAVING se refiere al alias SELECT Amount) ...

Msg 207, Level 16, State 1, Line 5
Invalid column name 'Amount'.

... pero funciona bien en MySQL.

Basado en esto, me pregunto:

  • ¿MySQL está tomando un atajo en las reglas de SQL para ayudar al usuario? ¿Quizás usando algún tipo de preanálisis?
  • ¿O MySQL está usando un orden de interpretación conceptual diferente al que yo creía que seguían todos los RDBMS?
Ohlin
fuente
1
Supongo que es tu segundo punto.
a_horse_with_no_name
3
Bueno, supongo que no causa ambigüedad ni confusión hasta que admiten funciones de clasificación. Entonces SELECT C, ROW_NUMBER() OVER (ORDER BY X) AS RN FROM T GROUP BY C HAVING RN = 1será problemático ya que las ROW_NUMBERcarreras después delHAVING
Martin Smith
No estoy seguro de qué funciones de clasificación son compatibles con MySQL. Si desea que el número de fila que hay que crear de esta manera: SELECT @rownum:=@rownum + 1 as row .... Tal vez la razón por la que admiten alias SELECT simplemente es porque pueden hacerlo, debido al hecho de que no admiten cosas que lo harían imposible ... ¿quién sabe? :)
Ohlin
Como explica @MartinSmith, siempre que no haya funciones de ventana / clasificación, el orden lógico de ejecución HAVINGy la SELECTcláusula pueden intercambiarse. Por lo tanto, no hay ambigüedad al hacer esto y puede simplificar la apariencia del código cuando hay expresiones monstruosas SELECT.
ypercubeᵀᴹ
Espero que esto sea algo sobre el tema para decir que respondí una pregunta aquí que está disfrutando de resultados más rápidos (con distincts) ... a Alias in the Havingpesar de la misma Explainsalida. Entonces, está ocurriendo alguna variación con el Optimizador.
Dibujó el

Respuestas:

13

Bueno, cuando tiene una pregunta de este tipo, la mejor fuente de información en mi humilde opinión es la documentación de MySQL. Ahora al grano. Este es el comportamiento de la extensión MySql GROUP BYque está habilitada de forma predeterminada.

Extensiones de MySQL a GROUP BY
MySQL extiende este comportamiento para permitir el uso de un alias en la cláusula HAVING para la columna agregada

Si desea un comportamiento estándar, puede deshabilitar esta extensión con sql_mode ONLY_FULL_GROUP_BY

SET [SESSION | GLOBAL] sql_mode = ONLY_FULL_GROUP_BY;

Si intenta ejecutar la consulta mencionada anteriormente en ONLY_FULL_GROUP_BYsql_mode, recibirá el siguiente mensaje de error:

El campo 'Cantidad' no agrupada se usa en la cláusula HAVING: SELECCIONE AÑO (fecha de pedido), COUNT (*) como Cantidad DE ÓRDENES GRUPO POR AÑO (fecha de pedido) QUE TIENE Cantidad> 1

Aquí está la demostración SQLFiddle

Por lo tanto, depende de usted cómo configurar y usar su instancia de MySQL.

peterm
fuente
Tienes toda la razón sobre la documentación. Nunca pensé que podría estar tan claramente escrito como lo citó anteriormente :) Gracias por encontrarlo ...
Ohlin
Esta respuesta no responde "¿MySQL está haciendo un análisis previo o está usando una interpretación conceptual diferente?".
Pacerier
2
@Pacerier MySQL está "haciendo un análisis previo", por supuesto, porque el optimizador de consultas considera todas las facetas de la consulta mientras elige lo que cree que será el mejor plan de consulta. La noción de una "interpretación conceptual diferente" revela un malentendido del hecho de que el servidor es libre de implementar el modelo conceptual de cualquier manera que produzca un resultado válido. ORDER BY, por ejemplo, podría manejarse mucho antes de lo que teóricamente es, si el optimizador encuentra que las filas pueden leerse inicialmente en orden desde un índice que ya está en el orden deseado.
Michael - sqlbot
4

Buena pregunta.

Creo que deberías ejecutar estas consultas

EXPLAIN SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING Amount>1;
SHOW WARNINGS;

y verifique cómo se reescribe la consulta. Estoy bastante seguro de que el optimizador de consultas reemplaza Amount con COUNT (*)

SELECT YEAR(orderdate), COUNT(*) as Amount
FROM Sales.Orders
GROUP BY YEAR(orderdate) 
HAVING COUNT(*)>1;

Como lo hace con

select 
 *
from 
 test
where 
 id = 5 - 3

después del optimizador de consultas es algo como esto.

select 
 test.id as 'id'
from 
 test
where 
 test.id = 2
Raymond Nijland
fuente