blog del equipo de tecnología de 11870.com

Groovy y los alias de columna en SQL

Groovy trae “de serie” soporte para interactuar con bases de datos SQL. Ese soporte descansa sobre las librerías java, y en este caso sobre JDBC. De esa manera consigues la fiabilidad y robustez de JDBC, o al menos de algunos drivers JDBC, y la expresividad y “user-friendliness” de groovy, consiguiendo cosas como ésta:

db.rows("select * from users").each {
  println it.name
}

Cada registro que devuelve groovy es de hecho un map, cuyas claves son los nombres de los campos de la query. Es un ejemplo estupendo del principio DRY: si ya has definido cómo se llaman tus columnas en la tabla, no vuelvas a especificarlo en el código que accede a la tabla.

Por desgracia casi nunca quieres la lista de nombres de la tabla usuario. Lo normal es que quieras cosas más complejas de calcular, es frecuente que quieras que tu select devuelva campos calculados:

SELECT avg(age), COUNT(id) FROM users

Y groovy ejecuta eso sin problemas, pero no te deja acceder a los resultados de tu query, de hecho lo que hace, de forma bastante torpe, es considerar que las columnas que devuelve tu select se llaman “” (cadena vacía). Para cada fila-map que devuelve tu query, groovy debe hacer algo parecido a:

m.put(columna, valor)

De forma que si todas las columnas se llaman igual, acabas con un map de un solo elemento. La solución más directa es usar alias:

SELECT avg(age) AS edad, COUNT(id) AS numero FROM users

Pero el resultado es el mismo. Un poquillo de Google y llegas a una issue del jira de groovy. Alguien se queja de esto y le responden que es comportamiento esperado de JDBC, pero parece que ellos hablan de los alias en las tablas, no en las columnas. Groovy proporciona otras formas de hacer queries más cercanas a JDBC, cosas como obtener un resultSet e iterarlo. Pero para los scripts encuentro particularmente útil la forma antes descrita.

Sin más preámbulo la cutre-solución: envuelve la query en una super-query, de esa forma “engañas” a groovy, haciéndole pensar que los nombres de tus columnas son los alias que le has pasado:

SELECT * FROM (SELECT avg(age) AS edad, COUNT(id) AS numero
    FROM users) AS q

En su contexto grooviero quedaría así:

db.rows("select * from (select avg(age) as edad, count(id) as numero 
    from users) as q").each {
  println it.edad
  println it.numero
}

Miel sobre hojuelas :)

Tags:

No hay comentarios

rssComments RSS transmitTrackBack Identifier URI

No comments. Be the first.

addDeja un comentario