lunes, 27 de febrero de 2012

MySQL y ONLY_FULL_GROUP_BY

Una de "arreglo una cosa y estropeo otra". MySQL, históricamente, se toma varias licencias frente a los estándares de SQL que pueden venir bien o no tan bien. Uno que particularmente no me gusta nada es la relajación de las columnas obligatorias en el GROUP BY.

Si no tocas nada de la configuración del servidor, cosas como esta se pueden hacer:

drop table if exists TT;
create table TT(a varchar(2), b varchar(1), c int, primary key (a));

insert into TT values ('a1','a',1),('a2','a',2),('a3','b',10);

select a,b,sum(c)
from TT
group by b;



absum(c)
a1a3
a3b10

Desde el estándar SQL, group by debería contener todas las columnas no calculadas que aparecen en select, es decir, group by a,b, independientemente de que esto tenga sentido o no. En realidad, todavía no entiendo qué se gana permitiendo esta sintáxis. Sí tendría algún sentido, por aquello de ahorrarnos algo de trabajo, si la columna "b" dependiera funcionalmente de la columna "a", de hecho algo de eso hay en el estándar SQL99, pero sigo sin verle mucha gracia.

De todas formas, como se trata de enseñar SQL y no las triquiñuelas de MySQL, a nuestros alumnos les obligamos a que no hagan estas cosas, es decir, la compilación de esta orden debería dar un error similar a "TT.a no está en GROUP BY". Para que se comporte así, MySQL permite configurar una variable global, sql_mode, en la que se puede establecer, entre otras cosas, ONLY_FULL_GROUP_BY, esto es, "compórtate como te dice el estándar"; y como hacen otros como Oracle o SQL Server, dicho sea de paso.

set session sql_mode='ONLY_FULL_GROUP_BY';

Esto obliga a cambiar la orden durante la sesión que tengamos abierta en MySQL. Si seguimos queriendo que el group by se haga por las dos columnas anteriores:

select a,b,sum(c)
from TT
group by a,b;


absum(c)
a1a1
a2a2
a3b10

Bueno, seguramente es que tampoco queríamos esto sino

select b,sum(c)
from TT
group by b;


bsum(c)
a3
b10

Que es en realidad para lo que vale el group by.

Resulta que lo pones todo contento, el sql_mode mencionado, y va y otras consultas que antes funcionaban ahora dejan de hacerlo.

select b
from TT
where c >= ALL (select c from TT);

La consulta anterior, estando sql_mode='ONLY_FULL_GROUP_BY', genera un error cuando no debería hacerlo. Di tú que la suerte es que para la mayoría de las cosas que preguntamos en clase hay una alternativa y además intuitiva:

select b
from TT
where c = (select max(c) from TT);


Pero no deja de ser molesto. Es un bug más o menos documentado que, hasta donde yo sé, se arrastra al menos hasta las versiones 5.1.x de MySQL. En las 5.5.x he comprobado que ya no. 

-----
Actualización: nos han actualizado a la versión 5.1.61 y ha desaparecido el bug.

miércoles, 22 de febrero de 2012

Botón imprimir en Google Sites

A raiz de un problemilla de un alumno con la impresión de una de nuestras páginas de FBDdocs, me he puesto a buscar una solución. El caso es que, si quieres imprimir una página, las barras laterales, superior e inferior no hacen más que molestar. Solución: el típico botón de "imprimir" que genera una página limpia (o casi) y más apta para la impresora. Pero ese botón, ¿de dónde lo saco?

En los foros de Google he encontrado lo que buscaba. Lo he adaptado un poco a mis gustos, los colorines y tal, pero se trata de editar la página en cuestión en HTML e insertar el siguiente código:

<form xmlns="http://www.w3.org/1999/xhtml">

<STYLE type="text/css">
input.btn {
  color:#005;
  font: 75% 'trebuchet ms',helvetica,sans-serif;
  background-color:#ddd;
  border:0px solid;
  border-color: #696 #363 #363 #696;
}
</STYLE>
<input class="btn" onclick="window.open('http://fbddocs.dlsi.ua.es/practicas-sql-espanol/expresiones-de-seleccion-de-filas?tmpl=/system/app/templates/print/&showPrintDialog=1')" style="width:75px; height:25px" type="button" value="Imprimir" />
</form>

Acto seguido, al salir de la edición HTML, se convierte en un gadget que puede editarse y colocarse donde queramos. El inline style es para darle ese aspecto más personalizado. El resto no merece más comentario. Por cierto la página en cuestión, la original se puede ver aquí, con el botoncito de marras a la derecha.

Bonito.

miércoles, 1 de febrero de 2012

La timidez de MySQL

No sorprende ya el que MySQL haya dejado para más tarde ciertos aspectos de SQL, de hecho, forma parte de su filosofía de origen, un producto destinado a obtener la máxima velocidad en entornos cliente-servidor sobre HTTP.

No obstante, esto ha sido hasta gracioso, uno de esos errores que dice uno "manda uebos" pero que mira, es así. Todo surge de un compañero que me llama todo alarmado porque MySQL no funciona como es debido.
 use apruebas;

 select *
 from L_TA rigth join  L_TB on  a=d ;

 select *
 from L_TB left join  L_TA on  a=d ;

Me he tomado la libertad de ponerle colorines a las palabras clave en vez de colocar un pantallazo de MySQL Workbench, pero es tal y como se ve en su ventana de edición. Tampoco muestro la estructura de las tablas porque no hace falta para lo que voy a contar. En cualquier caso, parece evidente que las dos consultas deberían dar el mismo resultado. Pues no.

Hasta que me he dado cuenta del colorín de rigth, y es que, claro, está mal escrito:
 select *
 from L_TA right join  L_TB on  a=d ;

Adonde quería llegar es que MySQL no dice nada sobre el "rigth", se lo traga sin más, y ejecuta un inner join sin más preocupaciones. Como siempre, la suerte de comentárselo al de al lado, y la suerte de la inspiración de este. Ya conocía los casos de foreign key fuera de innodb pero ¿esto? Será que MySQL es tímido...