miércoles, 3 de mayo de 2023

Oracle 23c - GROUP BY y HAVING Usando Alias


La sintaxis de las cláusulas GROUP BY y HAVING hasta la versión 23c de Oracle Database requieren que se especifique la expresión completa que define una columna (tal cual se expresa en la cláusula SELECT) en las cláusulas GROUP BY o HAVING, como vemos a continuación:

SELECT INITCAP(owner) || '-' || INITCAP(segment_type) AS Tipo,
       COUNT(*) AS Cantidad, ROUND(SUM(BYTES / 1024 / 1024)) AS MBs FROM dba_segments GROUP BY INITCAP(owner) || '-' || INITCAP(segment_type) HAVING COUNT(*) > 100 OR ROUND(SUM(BYTES / 1024 / 1024)) > 40

En este caso, si bien las expresiones no son complejas, debemos tener cuidado de repetirlas en forma exacta.

El resultado de la consulta anterior ejecutado en una base de datos Oracle 23c Developer Edition recién creada es el siguiente:


Uso de Alias en GROUP BY y HAVING en Oracle 23c

Oracle 23c permite el uso de alias tanto en las cláusulas GROUP BY como HAVING, como podemos ver a continuación:

SELECT INITCAP(owner) || '-' || INITCAP(segment_type) AS Tipo,
       COUNT(*) AS Cantidad, ROUND(SUM(BYTES / 1024 / 1024)) AS MBs FROM dba_segments GROUP BY Tipo HAVING Cantidad> 100 OR MBs > 40;

Esta mejora nos evita tener que repetir la expresión, y lo que es más importante, en caso de tener que modificarla evita tener que hacer la modificación en dos lugares distintos, a la vez que hace más corta y legible la sentencia.


Elección de Alias

Al usar alias en GROUP BY, debemos tener mucho cuidado con la elección del mismo. Analicemos la siguiente sentencia SQL:

SELECT SUBSTR(segment_type,1,5) AS segment_type, COUNT(*) AS Cantidad FROM dba_segments GROUP BY segment_type ORDER BY 1;

Y ahora veamos el resultado de ejecutar la misma:


Rápidamente nos damos cuenta que tenemos dos grupos de resultados con el valor INDEX y dos grupos con el valor TABLE. Esto se debe a que GROUP BY utiliza la columna segment_type de la tabla en vez del alias creado por nosotros.

Si reemplazamos el alias con un nombre que no que no exista en las tablas o vistas utilizadas en nuestra consulta, podemos solucionar el problema:

SELECT SUBSTR(segment_type,1,5) AS Segmento, COUNT(*) AS Cantidad FROM dba_segments GROUP BY Segmento ORDER BY 1;


El resultado de ejecutar esta sentencia es el que realmente queríamos, como podemos ver a continuación:



Uso de Notación Posicional en GROUP BY en Oracle 23c

Así como podemos usar el alias de una columna, podemos usar la notación posicional de la misma en la cláusula GROUP BY. Previo a ello es necesario habilitar esta funcionalidad, ya sea nivel de sesión o a nivel de sistema, mediante el nuevo parámetro GROUP_BY_POSITION_ENABLED, como mostramos a continuación:

ALTER SESSION SET GROUP_BY_POSITION_ENABLED = TRUE;


Una vez habilitada esta opción, podemos usar la misma notación posicional (disponible desde hace muchísimo tiempo para la cláusula ORDER BY) también en la cláusula GROUP BY, como mostramos a continuación:

SELECT INITCAP(owner) || '-' || INITCAP(segment_type) AS Tipo,
       COUNT(*) AS Cantidad, ROUND(SUM(BYTES / 1024 / 1024)) AS MBs FROM dba_segments GROUP BY 1 HAVING Cantidad> 100 OR MBs > 40;

Nota: No podemos usar la notación posicional en la cláusula HAVING ya que no tendría forma de distinguir el valor posicional (en nuestro ejemplo 2 o 3) de los valores a comparar (en nuestro ejemplo 100 o 40).


Conclusión

El uso de alias o notación posicional nos evita tener que repetir expresiones completas en dos lugares distintos de nuestras consultas, haciendo más fácil tanto la escritura como el mantenimiento posterior del código SQL generado.


Si desean conocer más sobre Oracle 23c, es recomendable que vean estos artículos en este blog como punto de partida:

Adicionalmente, pueden consultar todos los artículos relacionados a Oracle Database 23c agrupados en en el tag Database 23c.


No hay comentarios.:

Publicar un comentario