Too Cool for Internet Explorer

Multiple ‘GROUP BY’ en SQL 2

Hora y Fecha: Noviembre 30, 2006 @ 12:45 am Autor: Moisés Maciá
Categorías:
918 views

Os planteo una dudilla típica en el mundo de las bases de datos: tenemos una tabla con todos los empleados de una empresa, cada empleado tiene un único perfil asociado y además cada uno de ellos puede tener (o no) una serie de atributos.

Lo que quiero es obtener una tabla de frecuencias en la que diga cuantos empleados pertenecientes a un perfil y con una serie de atributos, empiezan con la letra A, con la B, con la C y así hasta la Z.

Es decir agrupar los empleados por perfil/atributo y después por letra alfabetica; algo parecido a una nube de tags o un histográma.

La instrucción GROUP BY de SQL sólo nos permite agrupar por un campo, entonces ¿Se puede sacar con una sola consulta sin utilizar programación ni tablas temporales? Si.

Veamos el esquema de datos sobre MySQL:

Tabla employees, almacena los datos relativos a los empleados:

  1.  
  2. CREATE TABLE employees (
  3.   id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  4.   name varchar(50),
  5.   profile_id int(10) UNSIGNED NOT NULL,
  6.   PRIMARY KEY (id)
  7. ) ENGINE=MyISAM;

Tabla profile, almacena el perfil de los empleados (uno por empleado):

  1.  
  2. CREATE TABLE profiles (
  3.   id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  4.   name varchar(50),
  5.   PRIMARY KEY (id)
  6. ) ENGINE=MyISAM;

Tabla attributes, almacena todos los atributos:

  1.  
  2. CREATE TABLE attributes (
  3.   id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  4.   name varchar(50),
  5.   PRIMARY KEY (id)
  6. ) ENGINE=MyISAM;

Tabla employee_attributes, almacena las relaciones entre empleados y atributos:

  1.  
  2. CREATE TABLE employee_attributes (
  3.   id int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  4.   employee_id int(10) UNSIGNED NOT NULL,
  5.   attribute_id int(10) UNSIGNED NOT NULL,
  6.   PRIMARY KEY (id)
  7. ) ENGINE=MyISAM;

Insertamos algunos datos de prueba:

  1.  
  2. INSERT INTO profiles (name) VALUES(‘perfil de programador’);
  3. INSERT INTO profiles (name) VALUES(‘perfil de manager’);
  4. INSERT INTO profiles (name) VALUES(‘perfil de tester’);
  5.  
  6. INSERT INTO attributes (name) VALUES(‘jornada completa’);
  7. INSERT INTO attributes (name) VALUES(‘empleado del mes’);
  8. INSERT INTO attributes (name) VALUES(‘encargado de sección’);
  9. INSERT INTO attributes (name) VALUES(‘le toca guardia’);
  10.  
  11. INSERT INTO employees (name,profile_id) VALUES(‘pepito’, 1);
  12. INSERT INTO employees (name,profile_id) VALUES(‘juanito’, 1);
  13. INSERT INTO employees (name,profile_id) VALUES(‘manolito’, 1);
  14. INSERT INTO employees (name,profile_id) VALUES(‘menganito’, 1);
  15.  
  16. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(1,1);
  17. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(1,3);
  18. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(2,1);
  19. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(2,2);
  20. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(2,3);
  21. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(3,1);
  22. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(3,4);
  23. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(3,3);
  24. INSERT INTO employee_attributes (employee_id,attribute_id) VALUES(3,2);

La solución Quick&Dirt empleada masivamente en estos casos es hacer una consulta para filtrar los empleados que nos interesan mediante la siguiente consulta:

  1.  
  2. SELECT Employee.id, Employee.name
  3. FROM employees AS Employee, employee_attributes AS EmployeeAttr
  4. WHERE Employee.id = EmployeeAttr.employee_id
  5.     AND EmployeeAttr.attribute_id IN (1,2,3)
  6.     AND Employee.profile_id = 1
  7. GROUP BY Employee.id

Resultado:

  id    name
----------------
  1    pepito
  2    juanito
  3    manolito
  4    menganito

… para después mediante programación, agruparlos y realizar el conteo.

¿Es óptimo? NO, hay que hacer un tratamiento a posteriori de los datos.

¿Es sencillo? NO, quizá sea más complicado y engorroso la programación del tratamiento posterior que hacerlo corréctamente.

¿Es elegante? NO, se mezcla la capa de negocio con la capa de datos.

¿Entonces cómo lo hago?

La mejor forma de hacer este tipo de consulta y mantener tu karma como programador es utilizar una Subquery. Una subquery es una manera especial de anidar sentencias SQL para componer consultas mas complejas que de otra forma no se podrían realizar.

Las subqueries se agrupan fundamentalmente en dos grandes grupos: escalares y correlacionadas, aunque la que voy a utilizar yo es un poco diferente puesto que el resultado de la subquery suplantará a una tabla; jugando con este efecto conseguimos el comportamiento de un GROUP BY multiple.

  • Más información en el apartado Subquery Syntax de la documentación de MySQL.
  • Más infromación sobre Subqueries correlacionadas y escalares (con muchos ejemplos) en MySQL Hispano.

Veamos la consulta:

  1.  
  2. SELECT LEFT(Employee.name,1) AS alphacrum, COUNT(LEFT(Employee.name,1)) AS total
  3. FROM (
  4.   SELECT Employee.id, Employee.name
  5.     FROM employees AS Employee, employee_attributes AS EmployeeAttr
  6.     WHERE Employee.id = EmployeeAttr.employee_id
  7.       AND EmployeeAttr.attribute_id IN (1,2,3)
  8.       AND Employee.profile_id = 1
  9.     GROUP BY Employee.id
  10.   ) AS Employee
  11. GROUP BY alphacrum
  12. ORDER BY alphacrum ASC;

Resultado:

  alphacrum    total
----------------------------
  j                    1
  m                  2
  p                   1

Como podeis observar, la tabla employees de la consulta principal no es la original; es el resultado del filtrado previo según los parametros que nos interesen.

Una vez filtrados es muy sencillo reordenar los datos a nuestro gusto, únicamente agrupamos por letra y realizamos el conteo de los resultados con COUNT, devolviendonos los datos tal y como nos hacen falta.

De esta manera se utiliza efectivamente el cache del servidor de bases de datos y la programación de la aplicación no se satura con un montón funciones de tratamiento de datos. Simple y elegante.



Convertir audio APE/CUE en WAV/OGG/MP3 bajo Linux 4

Hora y Fecha: Noviembre 25, 2006 @ 9:40 pm Autor: Moisés Maciá
Categorías:
1,168 views

Ateción. El código fuene de Monkey’s Audio ha dejado de estar disponible. La última versión puede obtenerse a través de los repositorios de backports de Morgoth.

Monkey’s Audio no es libre, ni siquiera multiplataforma así que continuar utilizándolo es un billete al fracaso, emplead FLAC en su lugar.

Monkey’s Audio es un formato que está ganando popularidad en los últimos meses. Se trata de un formato de compresión de audio sin perdida que ofrece una alta calidad de sonido (técnicamente igual al original) y es por ello que es muy habitual encontrar discos codificados en este formato cuando buscamos música clásica u opera.

Los discos en este formato se presentan en forma de imagen con dos archivos: disco.ape (que contiene la imagen del disco de audio), y disco.ape.cue que contiene toda la información del disco (meta tags, pistas, duración, etc).

Reproducir estos archivos bajo GNU/Linux se presenta algo complicado porque la mayoría de los reproductores de audio no soportan directamente el formato Monkey’s Audio (la honrosa excepción son los plugins para XMMS y Beep Media Player).

El objetivo de este post es convertir un disco codificado en formato Monkey’s Audio a algo más extendido como Ogg Vorbis o MP3.

Pasos previos

El software que vamos a necesitar no se encuentra en los repositorios habituales de Ubuntu, así que toca compilar. Para compilar el soft necesitamos una serie de programas y utilidades que no se instalan por defecto.

Instalamos todas las utilidades y compiladores de desarrollo:

  1.  
  2. apt-get install build-essential
  3.  

Instalamos el ensamblador YASM:

  1.  
  2. apt-get install yasm
  3.  

Instalamos mp3splt, necesario para extraer las pistas:

  1.  
  2. apt-get install mp3splt
  3.  

Compilar Monkey’s Audio Coder

Bajamos la última versión de Monkey’s Audio

Descomprimimos el contenido y nos situamos en el directorio de trabajo:

  1.  
  2. tar xvzf mac-3.99-u4-b5.tar.gz
  3. cd mac-3.99-u4-b5/
  4.  

Preparamos el entorno para la compilación y compilamos:

  1.  
  2. ./configure
  3. make
  4.  

Instalamos el programa (es necesario ser root):

  1.  
  2. make install
  3.  

Convertir de APE a WAV

  1.  
  2. mac disco.ape disco.wav -d
  3.  

Convertir de WAV a OGG/MP3

Mi recomendación es que utiliceis Ogg Vorbis :)

Ogg Vorbis:

  1.  
  2. oggenc -q 9 disco.wav
  3.  

MP3:

  1.  
  2. lame –preset standard disco.wav
  3.  

Separar las pistas y rematar el trabajo

Ogg Vorbis:

  1.  
  2. oggsplt disco.ogg -c disco.ape.cue
  3.  

MP3:

  1.  
  2. mp3splt disco.mp3 -c disco.ape.cue
  3.  

Finalmente con Amarok podemos editar y ajustar los meta tags a placer.



IBM recomienda CakePHP 4

Hora y Fecha: Noviembre 22, 2006 @ 1:19 am Autor: Moisés Maciá
Categorías:
811 views

Vaya lujazo, IBM ha dedicado nada menos que 5 artículos al desarrollo de aplicaciones con CakePHP en su portal IBM’s developerWorks, un framework en el que llevo colaborando algún tiempo (aunque todavía no he ganado el privilegio necesario para subir cosas directamente al SVN).

Los artículos de la serie son:

  • Parte 1: configuración, puesta en marcha de CakePHP y una pequeña aplicación de login.
  • Parte 2: cubre el scaffolding, la herramienta Bake y las listas de control de acceso (ACL).
  • Parte 3: sobre Sanitize y cómo crear aplicaciones seguras filtrando los datos de entrada, el componente Security y cómo manejar peticiones mal formadas y temas avanzados de validación.
  • Parte 4: cubre el componente Session, mostrando tres mecanismos para guardar datos de estado, así como el componente Request Handler para manejar multiples tipos de peticiones (navegadores embebidos, peticiones XML, peticiones HTML, etc).
  • Parte 5: cacheado de vistas y layouts.

Los artículos se encuentran aquí (de momento sólo el primero). Hace falta registrarse para verlos (el registro es incomodo pero gratuito).

Tiembla Rails :)



Cosas a tener en cuenta cuando diseñamos un modelo de datos 1

Hora y Fecha: @ 12:11 am Autor: Moisés Maciá
Categorías:
603 views

… y que la mayoría de los “programadores” ni siquiera saben que existen:

  1. Crea indices para las columnas, pero hazlo con cabeza. Muchos indices pueden hacer que las inserciones, borrados y actualizaciones sean operaciones muy lentas.
  2. Utiliza EXPLAIN para optimizar las consultas y observar como afectan los indices al rendimiento.
  3. Minimiza los datos que devuelven las consultas. No utilices SELECT *, trocea los datos en páginas con LIMIT e intenta agrupar varias consultas en una sola con UNION o JOIN.
  4. El mayor cuello de botella de las bases de datos suele ser el disco duro. Si necesitas rendimiento considera montar un RAID para datos y otro para los logs, así como dedicar una máquina únicamente para la BD. Manejar tablas temporales en memoria también mejora notablemente el rendimiento.
  5. LOAD DATA funciona mucho más rápido que INSERT: por cada inserción se actualiza el árbol de indices, así que si no te queda mas remedio que hacer muchos INSERT seguidos, desactiva los indices y actualizalos al terminar.
  6. No selecciones columnas de tipo BLOB o TEXT directamente, hazlo siempre a través de una tabla relacionada. Cuando se borran filas con estos tipos de datos, las tablas tienden a fragmentarse. Analiza y reconstruye los indices al eliminar filas de este tipo.
  7. Normaliza tu modelo, por lo menos hasta la tercera forma normal. En ocasiones se degradan las formas normales de alguna relación para ganar rendimiento, pero eso sólo es cierto en determinado tipo de situaciones muy específicas. Normaliza siempre.
  8. Considera utilizar el tipo de datos ENUM en lugar de una tabla relacionada.
  9. La integridad referencial y abusar de los triggers baja el rendimiento de las consultas. Activalos cuando los necesites pero no abuses.
  10. Si puedes hacerlo con un procedimiento almacenado, hazlo.
  11. Prepara benchmarks y mide el rendimiento de tus consultas sobre datos reales.

Si todo esto te queda grande, contrata a un DBA.



Esos pequeños hijos de puta 1

Hora y Fecha: Noviembre 21, 2006 @ 6:15 pm Autor: Moisés Maciá
Categorías:
314 views

Art Attax
Art Attax 2
Art Attax 3



OpenOffice y SQLite 3

Hora y Fecha: Noviembre 14, 2006 @ 12:30 am Autor: Moisés Maciá
Categorías:
707 views

Las entradas sobre SQLite están teniendo mucho éxito entre los lectores de QuarkBlog. Algunos de vosotros me habéis preguntado si utilizo algún interfaz gráfico para borrar, insertar, actualizar filas y manejar las tablas y las consultas.

La verdad es que no, utilizo simplemente el interprete de comandos que viene de serie con la instalación de SQLite, escribiendo directamente las consultas en SQL. Realmente es lo más rápido y lo más potente, pero viendo que varias personas me lo han preguntado, he investigado un poco acerca del tema.

He encontrado muchos interfaces gráficos (sobre todo para Windows), todos ellos de pago o en su defecto shareware y además terriblemente malos.

Muchas veces nos empeñamos en buscar herramientas específicas sin pararnos a pensar que ya hay algo que soluciona el problema: OpenOffice :)

El resultado de la conjunción SQLite+OpenOffice es un gestor de bases de datos con todas las ventajas de Microsoft Access y ninguno de sus problemas.

Básicamente hay dos formas de conectar OpenOffice con SQLite: una me ha funcionado y la otra no. Rebuscando por la web de OpenOffice he dado con esta página en la que explican como instalar un driver específico. Este es el método que no me ha funcionado, aunque tampoco he insistido mucho …

La otra forma sólo he podido reproducirla en Windows, consiste en registrar un driver ODBC y crear una conexión de datos que podremos importar desde OpenOffice sin problema. Técnicamente esta solución también es válida para Linux, pero configurar fuentes ODBC es un dolor y no tengo tiempo.

El driver ODBC para SQLite lo podeis conseguir aquí (licencia BSD).

Aquí podéis ver una consulta:

SQLite sobre OpenOffice



Mi escritorio 1

Hora y Fecha: Noviembre 11, 2006 @ 10:23 pm Autor: Moisés Maciá
Categorías:
429 views

Cada cierto tiempo subo un pantallazo de mi escritorio:

KDE 3.5.5 small

Ojo, la captura completa pesa 4Mb. Lo que veis es:

  • Kubuntu Edgy Eft con KDE 3.5.5
  • Dos monitores en configuración TwinView, con una resolución total de 3280×1200, como podéis observar uno es panorámico y el otro no, por eso no ajusta (probé Beryl pero se arrastraba miserablemente … :().
  • El fondo de escritorio lo podéis conseguir en KDE-Look, me gustan los paisajes justo antes de empezar una tormenta.
  • Liquid Weather ++, un applet para ver el estado meteorológico.
  • Aero All in One, otro applet super útil para controlar las constantes del sistema.
  • Amarok, EL reproductor de audio.
  • Applets varios propios de KDE.


I recommend Ubuntu Linux 3

Hora y Fecha: Noviembre 10, 2006 @ 7:41 pm Autor: Moisés Maciá
Categorías:
368 views
I Recommend Ubuntu Linux

Visto por Flickr



Selenium: Testing funcional para la web 0

Hora y Fecha: Noviembre 3, 2006 @ 1:09 am Autor: Moisés Maciá
Categorías:
584 views

El testing funcional o de caja negra es una metodología utilizada en la ingeniería del software para comprobar como de bien (o mal) funcionan las cosas dentro del desarrollo de un programa. Estas comprobaciones pueden efectuarse en prácticamente cualquier nivel del desarrollo: implementación, integración, etc.

El tester elige una serie de entradas para el programa y comprueba si las salidas son correctas o incorrectas en función del sentido común. En cualquier caso no se conoce a priori el funcionamiento interno del software, por eso lo de caja negra.

Si bien el tester no puede cubrir de esta forma todos los caminos posibles que puede tomar la ejecución el programa, es una forma bastante sencilla de comprobar someramente que todo está en su sitio y el último commit no ha roto nada. Y mucho menos coñazo que el testing unitario :)

Mas info sobre el testing funcional en la wikipedia.

Para aplicaciones web, 2.0 o no :), existe el maravilloso, espectacular, potente y versátil a la par que poco conocido: Selenium.

Selenium funciona directamente sobre el navegador web, carga los script de test y los va comprobando uno a uno dando al final una tabla con los resultados. También puede funcionar “en modo consola” para integrarlo en vuestro cruise crontrol particular del desarrollo y hacer comprobaciones periodicas cada noche por ejemplo.

Un test muy sencillo podría ser la comprobación del modulo de login. En el test le indicariamos los siguientes pasos:

  1. Ve a la pagina de inicio.
  2. Escribe paquito en el login box.
  3. Escribe 1234 en la cajetin de password.
  4. Haz click en Login.
  5. Comprueba si aparece el texto “Bienvenido paquito”.

Tan simple como eso, 5 lineas y la seguridad de que si se rompe lo vas a saber al instante de pasarle los tests.

Selenium funciona sobre aplicaciones web “en marcha”, sin importar si están implementadas en PHP, Java, Ruby, etc.

Os recomiendo que le deis una oportunidad, a mi me sorprendió gratamente.




Bad Behavior has blocked 374 access attempts in the last 7 days.