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...

martes, 31 de enero de 2012

Kill, kill, kill... procesos en MySQL

A toda prisa me he tenido que ir al interné a buscar como parar un bucle infinito de inserciones en una tabla desde PHP.

Después del susto inicial, nada, fácil: show full processlist y kill x. Menos mal.

Tampoco me voy a arrostrar todo el mérito, el primero que me lo aclaró fue Trucos Informáticos.

martes, 20 de diciembre de 2011

Conexión a SQL Server 2008 Express por TCP/IP

Resulta que SQL Server, en otras ediciones, te pide datos acerca de cómo quieres que se conecten los usuarios pero como la versión Express tiene vocación doméstica, de monousuario y trabajo en local, pues no te lo pregunta.

¿Y qué pasa si sí quiero conectarme remotamente y, además, por TCP/IP? Pues que hay que ir a una herramienta de configuración y tocar. Concretamente hay que ejecutar ...\Menú Inicio\Programas\Microsoft SQL Server 2008\Herramientas de configuración\Administrador de configuración de SQL Server y allí modificar los siguientes parámetros:


Habilitar TCP/iP en los protocolos de SQLEXPRESS:



Entrar en sus propiedades y modificar IPAll poniendo el puerto elegido para las conexiones:



En este caso se desea un puerto estático, y tanto IP1 como IP2 no hace falta tocarlos. Aceptar y cerrar.

Para más información, pues al fabricante.

martes, 13 de diciembre de 2011

Xampp y Skype no se quieren

Me acaba de ocurrir. Necesitaba poner en marcha el Apache para un par de pruebas que quería hacer y recién lanzado el Xampp Control Panel le doy acelerado a los botones start del servidor web y del MySQL.

De tan rápido, casi no me doy cuenta: el MySQL en marcha  pero el Apache no. Le doy otra vez, parpadea en verde y que nada. Le doy a la casilla de instalarlo como servicio, pero que tampoco, no arranca.

Perro viejo, me pregunto, ¿qué hay de nuevo que hace que lo que funcionaba ayer no funcione hoy? Pues el Skype, que conecto de vez en cuando, si la necesidad lo requiere.

Con la osadía que da la casi absoluta certeza y confianza, salgo completamente de Skype, desmarco la casilla de funcionamiento de Apache como servicio y le doy nuevamente al botón. Ahora sí, se mantiene en marcha. Curiosamente, arranco de nuevo el Skype y los dos tan contentos.

Qué cosas.

Actualización.
¡Qué cosas, me ha vuelto a pasar! Me he pegado de tortazos otra vez porque tenía el Skype abierto antes que el Apache. Ahora he sido disciplinado y he rebuscado y, efectivamente, hay un conflicto entre uno y otro por el puerto 80: en knowledgesutra.com y en moodle.org.

jueves, 8 de diciembre de 2011

Un router WiFi ADSL como puente (bridge)

Una red doméstica

Mi red local, la de casa, es un desastre. Más bien es la casa, pensada para los veraneantes que no tienen tiempo entre quemada mañanera en la playa, arroz de chiringo y quemada vespertina; urgencias, para el día antes de volver a la gran ciudad. Pues eso, que tirar cable queda feo, entre el propio cable en sí y los agujeros previsibles en la pared del salón.

Recién estrenada mi conexión WiMAX (la ADSL aquí llega en las últimas, pero las últimas, a punto de morir, en el último aliento de 7 Km de distancia a la central), viene el problema de distribuir la señal al resto de la casa. Vosotros diréis, WiFi y a tirar Mbs. Pues no, yo prefiero una comunicación PLC que, en mi caso, deja la WiFi para las ocasiones y, de paso, me evita tirar mucho cable.

La situación es la siguiente: la señal de WiMAX llega desde la antena hasta un cacharrico que me proporciona la empresa y donde se encuentra un puerto RJ-45 para cable Ethernet. Ni que decir tiene que necesito más bocas, a ver, ordenador, consola, segundo ordenador, televisión, reproductor Blu-Ray/DVD y WiFi. Si bien TV y BR, la verdad, no los tengo conectados ni mucho ni poco, sí se plantea la necesidad de cierta electrónica de red, más si cabe si tenemos en cuenta que yo trabajo en una habitación que no es el salón donde está, precisamente, la entrada de señal WiMAX.

He aquí el esquema de cómo lo tengo montado, más o menos.



Enrutador: TP-LINK TL-R480T+
Concentrador: TP-LINK TL-SG1005D

En el salón, el cacharrico WiMAX se conecta al enrutador (router, pero no un router ADSL1) y este configura una red 192.168.1.0/24, siendo el propio router la puerta de enlace 192.168.1.1. De aquí sale un cable ethernet hacia el módulo PLC que, a través de los cables de la corriente eléctrica, se comunica con otro módulo PLC que da servicio a la habitación en la que estoy escribiendo esto. Aquí, lo que tengo es un concentrador (hub) que me permite conectar más de un dispositivo a la red mediante DHCP, concretamente el PC y la consola.

El cacharrico WiMAX (habría que llamarlo por su nombre, LinkSys Phone Adapter and Router, o sea otro enrutador) viene configurado con la red local 192.168.0.0/24. Para no provocar confusión entre tanta puerta de enlace, sea la del enrutador 192.168.1.0/24. Hay que entender que se trata de un router capaz de gestionar varias puertas de enlace (varios "internets", si os resulta más comprensible) y repartir la carga de red entre ellas (repartir los paquetes por una u otra red dependiendo de su estado en cierto momento). 

De hecho, sospecho que un concentrador normal y corriente hubiera bastado, pero por reciclar y aprovechar... aparte de que la operadora no me da ningún parámetro de conexión, todo viene encapsulado en el "cacharrico" y no tengo ganas ni tiempo de hackear. No importa, el motivo de esta entrada no es este sino que todavía no tengo WiFi.

¿Y para qué están los routers ADSL WiFi que vas acumulando por tu infructuoso paso de una operadora a otra?

Un router WiFi ADSL transformado en bridge

Volvamos al salón. La cuestión es que sí necesito WiFi, también hay portátiles, tabletas, teléfonos, etc. La solución más económica ha sido aprovechar un router ADSL en desuso por el cambio de compañía. Concretamente el Zyxel P-660HW-D1 de Telefónica (el blanco).


La idea es que este hiciera las funciones de puente (bridge) WiFi lanzando al aire la señal del cable WiMAX. Eso está fácil, se configura el Zyxel como puente:



Esto hace que cualquier aparato que se conecte a la WiFi ahora tiene como puerta de enlace el router, es decir, la 192.168.1.1, y adquiere la IP 192.168.1.x que le proporcione el DHCP del mismo enrutador. Nótese que no es el Zyxel quien da la IP, es el router "neutro": el Zyxel solo es una pasarela, traspasa nuestras peticiones WiFi al enrutador que es el que realmente manda. Con este simple cambio ya funciona, ya me da acceso a Internet desde los portátiles.

Lo que ya me dió algún quebradero de cabeza es ¿cómo accedo a la página de configuración del Zyxel, la de toda la vida, 192.168.0.1? El router WiMAX viene configurado con la misma IP por lo que nunca llegaría al Zyxel. Entre otras cosas, lo necesitas si quieres cambiar la encriptación WiFi y sus claves, establecer filtros, etc.

No soy experto en redes. La solución es tan tonta que me da un poco de vergüenza mostrarla (por el tiempo que me costó darme cuenta). Además, igual era más sencillo todavía. Da igual, lo que he hecho ha sido configurar la LAN del Zyxel a una IP de la red 192.168.1.0/24:



Ahora, si pongo en mi navegador 192.168.1.1, accedo a las páginas de configuración del router. Si es la 192.168.1.2, me salen las páginas de configuración del Zyxel convertido en puente. Si pongo la 192.168.0.1... no me deja porque la empresa no me ha dado usuario y contraseña, pero llega también.

Esta ha sido la descripción de como reciclar toda la cacharrería que se acumula durante todos estos años de sufrir ADSLes penosas.

1. Como muchas cosas de estas de la electrónica, al router de toda la vida se le ha añadido el calificativo de "neutro" para que los clientes tengan bien claro que NO es un router ADSL, aunque en ciertas funciones se solapen.

El gráfico del portátil del esquema de red es una derivación de iconhive.