El tutorial de VB-MySQL – Parte 1

November 5th, 2006 Leave a comment Go to comments

Por Mike Hillyer
Última actualización: 4 de Febrero, 2005

Ir al foro de este Artículo

1. Introducción
2. Elección de una Aplicación
3. Listado de Requerimientos y Características

    El Triángulo de Desarrollo

4. Diseño de Entidades

    Usuarios
    Grupos
    Eventos

5. Entidades y Relaciones
6. Diseño de la Base de Datos

    Elección de una Clave Primaria
    Elección de los Nombres de Campo y Campos Requeridos
    Relaciones Uno-a-Muchos
    Relaciones Muchos-a-Muchos

7. Normalizando la Base de Datos

    Primera Forma Normal
    Segunda Forma Normal
    Tercera Forma Normal

8. Elección de los Tipos de Columnas y Armado de Sentencias CREATE TABLE

    NOT NULL, DEFAULT, AUTO_INCREMENT y PRIMARY KEY
    CHAR vs. VARCHAR
    Almacenamiento de Números Telefónicos
    Columnas ENUM
    Columnas de Fecha
    Campos TIMESTAMP
    Claves Primarias Compuestas
    Definición de las Tablas Restantes

9. Conclusión

Introducción

Si bien los artículos de vbmysql.com han tenido una buena recepción, siempre hay algo nuevo para exponer. Cada semana me llegan pedidos de nuevos artículos y códigos de ejemplo que expliquen algún aspecto nuevo de la utilización de Visual Basic y MySQL. Uno de los pedidos recurrentes ha sido el de un tutorial que explique la creación de una aplicación, desde el diseño hasta la implementación, utilizando Visual Basic y MySQL. En respuesta a estos pedidos, he escrito este artículo como el primero de una serie de artículos que proporcionarán una guía completa para la creación de una aplicación con Visual Basic.NET y MySQL. Explicaré el diseño de aplicaciones, diseño de bases de datos, programación con bases de datos en VB.NET y la implementación de la aplicación terminada.

Este tutorial será muy práctico, documentando la creación de una aplicación real que luego estará disponible para ser descargada ya sea en forma binaria o en código fuente para referencia futura. Los archivos intermedios estarán disponibles al final de cada sección del tutorial para que se familiaricen con el proyecto a medida que vayamos progresando.

En esta primera entrega de la serie comentaré el diseño de la base de datos de nuestra aplicación. Una base de datos bien creada puede ser crítica para el éxito de tu proyecto de base de datos, permitiendo la capacidad de expansión y escalabilidad, además de facilitar el desarrollo. En este tutorial describiré los pasos a seguir para comenzar con el diseño de la aplicación, luego seguiré con el diseño de la base de datos y terminaré con la escritura de las sentencias de creación de tablas.

Elección de una Aplicación

Lo primero que necesitamos al crear una aplicación es un requerimiento. Los programas de computadoras se crean para satisfacer requerimientos de los usuarios de aplicaciones. En mi oficina tenemos muchos empleados, los cuales pueden estar o no en la oficina en un momento dado. En la actualidad, utilizamos una simple aplicación que registra qué empleados están en la oficina y muestra un pequeño mensaje con aquellos que no están, indicando cuándo regresarán.

Este tipo de software de registro de entradas y salidas es muy común, pero este tipo de aplicaciones tienen generalmente dos limitaciones; muchas de estas aplicaciones están limitadas sólo a un cierto número de usuarios, normalmente alrededor de 50-100. Además, estas aplicaciones utilizan a menudo archivos planos (flat files) para almacenar información, requiriendo que cada usuario tenga acceso a un directorio de red compartido para poder usar el sistema. Estas dos limitaciones pueden vencerse utilizando una base de datos SQL (en inglés, pronunciado “ess-que-ell”, no “sequel”). Si la aplicación que usamos en la oficina tuviese su código fuente disponible, una opción sería modificarla (la libertad para modificar una aplicación que se ajuste a tus necesidades es uno de los beneficios del software y herramientas Open Source). Dado que la aplicación en cuestión es relativamente simple, he preferido rehacerla utilizando Visual Basic y MySQL.

La idea para tu aplicación puede venir del deseo de “crear una mejor ratonera” – desarrollar una versión mejor de una aplicación existente. Por otra parte, quizás necesites una aplicación pero no puedas encontrar un proyecto existente apropiado. Finalmente, la idea puede ser de otra persona, ya sea un cliente o tu empleador. En cualquier caso, el primer paso al desarrollar una aplicación es decidir qué aplicación crear.

Listado de Requerimientos y Características

Una vez que hayas elegido qué aplicación vas a desarrollar, es importante decidir específicamente qué es lo que hará la aplicación. Deberás definir las funciones básicas además de ciertas características que implementará el software. Si estás desarrollando este software para ti mismo, este paso del proceso de desarrollo puede ser bastante informal, pero no deja de ser importante. Si estás desarrollando software para un cliente o un empleador, entonces es vital que hagas una lista de características y requerimientos. La lista determinará cuáles son tus responsabilidades como desarrollador de software y te dará una clara definición de lo que necesitas para que tu proyecto se considere completo. También debe recordarse que los clientes y empleadores tienden a solicitar funciones adicionales a medida que avanza el proyecto negándose a aportar dinero adicional para implementarlas. Si tienes una lista de funciones a mano, puedes informarle a tu cliente que tu trabajo es implementar las funciones de la lista y que cualquier característica adicional requerirá costos adicionales.

Además de listar las características y requerimientos, también querrás desarrollar una línea de tiempo y un presupuesto. Sería deseable planificar hitos como la finalización del proyecto y etapas importantes de trabajo realizado. Por ejemplo, podrías planificar un hito para denotar la entrega de los diseños de aplicación y base de datos al cliente. También podrías agregar un hito para la entrega de una demostración funcional del proyecto. A menudo, estos hitos coinciden con los pagos del cliente cuando trabajas como consultor, estando los pagos definidos en tu presupuesto.

El Triángulo de Desarrollo

En cuanto al dinero, las funciones y los tiempos, es importante comprender el equilibrio que debe existir entre los tres. Sin dudas, tu cliente pretenderá que le entregues tantas funciones como sea posible dentro de un pequeño presupuesto y breve período de tiempo. Será importante tener en cuenta que a veces tienes que rechazar algún pedido de funciones o reducción de tiempos con el propósito de mantener todo equilibrado. Suponte que el tiempo, las funciones y el dinero son las tres esquinas de un triángulo:

Aunque es posible estirar las esquinas de este triángulo, no puedes cambiar el área que ocupa, ya que el área del triángulo representa tus recursos totales. El efecto de esto es que cada sección puede aumentar a expensas de las otras dos: Si quieres que un proyecto tenga más funciones tendrás que utilizar más tiempo o invertir más dinero en herramientas o desarrolladores adicionales. Si deseas que un proyecto cueste menos dinero, tendrás que reducir el número de funciones o permitir que el proyecto demore más tiempo (ya sea porque reduces el número de desarrolladores o sólo les permites trabajar en el proyecto en su tiempo libre). Finalmente, si quieres que el proyecto finalice rápidamente, tendrás que reducir el número de funciones o invertir más dinero en más herramientas y/o desarrolladores (o al menos pagarles horas extras a los desarrolladores existentes).

Al negociar una lista de funciones y tiempos con tu cliente o empleador, asegúrate de recordar el triángulo e incluso mostrárselo a tu cliente para que puedan comprender la relación entre las funciones, dinero y tiempo. Si estás desarrollando el proyecto para tu propio uso tienes la ventaja de contar con el cliente perfecto, pero recuerda de todos modos que puedes hacer muy poco en tu tiempo limitado.

Echemos un vistazo a la lista de funciones y requerimientos de nuestro software de registro de entradas/salidas:

    * El ingreso al sistema debería solicitar un nombre de usuario y contraseña
    * Debería mostrarse un mensaje de estado al usuario cuando ingrese al sistema.
    * Los usuarios podrían elegir entre ningún mensaje de estado, un mensaje de estado predefinido o especificar su propio mensaje al ingresar o salir del sistema.
    * Los últimos dos mensajes de estado definidos por los usuarios deberían estar disponibles en una lista junto con los predefinidos.
    * Los usuarios deberían poder ingresar al sistema desde cualquier PC con conexión a Internet, con una conexión encriptada disponible.
    * Los usuarios deberían poder marcar un compañero y ser notificados cuando ingrese.
    * Los usuarios deberían dividirse en distintos grupos (Ventas, Contaduría, Sistemas, etc.).
    * La pantalla principal debería mostrar una lista de todo el personal (o grupos seleccionados) con nombres, estados de entrada/salida, mensajes de estado, y campos personalizados.
    * La aplicación debe poder minimizarse a la barra de tareas.
    * Los usuarios deben poder personalizar la apariencia, el tamaño de ventana, tamaño de fuente, formato de fecha, formato de nombre y colores.
    * Los usuarios estándar podrán cambiar sus estados, formato de visualización y enviarles mensajes a otros usuarios.
    * Los usuarios recepcionistas podrán cambiar los estados de grupos de usuarios (varios grupos pueden ser recepcionistas).
    * Los coordinadores podrán agregar/eliminar usuarios dentro de un grupo, cambiar sus estados (de sus grupos) y asignar recepcionistas.
    * Los administradores podrán crear usuarios, asignar coordinadores y administradores y cambiar la pertenencia a los grupos. No tienen restricciones.
    * Los usuarios deberían poder elegir entre tener la aplicación minimizada o maximizada.
    * Los usuarios deberían poder elegir una frecuencia de actualización de la ventana abierta.

Tu lista de funciones y requerimientos debería ser tan detallada como sea necesario para ti y tu cliente, y las aplicaciones más complejas deberían contar con documentación más detallada. Una vez que tu lista de funciones, tu presupuesto y tus tiempos hayan sido aprobados puedes seguir con el diseño de la aplicación.

Diseño de Entidades

Un buen acercamiento al diseño de aplicaciones consiste en identificar las distintas entidades que estarán involucradas en la aplicación. Una entidad es simplemente un objeto sobre el cual deseamos almacenar información. El diseño de aplicaciones basado en las entidades que la conforman es un principio básico de la programación orientada a objetos. En nuestra aplicación las entidades principales son nuestros usuarios. Existen cuatro clases de usuarios: Usuario Regular, Recepcionista, Coordinador y Administrador. Hay dos aproximaciones que podemos hacer para representar los distintos tipos de usuarios. Podríamos describir cuatro entidades distintas, una para cada tipo de usuario o podríamos tener una única entidad de usuario con un atributo que defina su tipo.

Cuando distintas entidades tienen una base en común pero aún conservan diferencias significativas, puede resultar beneficioso pensar en una entidad base que es heredada por las otras entidades. Tomemos como ejemplo los vehículos. Aunque todos los vehículos comparten una base común al tener ruedas y desplazarse hacia delante y hacia atrás, siguen teniendo características únicas:

Como podrás ver, cada vehículo tiene propiedades comunes a todos los vehículos, tales como las ruedas, volantes y radios. Sin embargo cada vehículo es único en cierto modo. Los autos son más pequeños y generalmente llevan más pasajeros que los camiones. Los camiones llevan menos pasajeros pero tienen más lugar para transportar cargas. Los taxis son similares a los autos pero llevan pasajeros que pagan una tarifa y tienen radio transmisores y equipos para calcular las tarifas. Podríamos incluso haber concebido al taxi como una sub-entidad de un auto, heredando todos los rasgos de un auto y luego agregando otros propios.

La única propiedad particular a cada una de nuestras entidades de usuario es si corresponden a un coordinador, administrador o recepcionista. Como existe una diferencia muy pequeña entre los distintos usuarios es mejor crear una única entidad con una propiedad que designe las responsabilidades administrativas del usuario. Otras entidades de nuestra aplicación incluyen grupos y eventos. Echemos un vistazo detallado a cada una de las entidades.

Usuarios

Un usuario es cualquier usuario del sistema. Los usuarios pueden ingresar a la aplicación, establecer su estado y ver los estados de los demás. Un usuario tiene las siguientes propiedades:

    * Nombre
    * Número de Teléfono
    * Nombre de Usuario
    * Contraseña
    * Administrador (Sí/No)
    * Fecha de Alta
    * Eliminado (Sí/No)
    * Mensajes de Estado Personalizados
    * Grupos coordinados por el usuario
    * Grupos para los cuales el usuario es recepcionista

El indicador “Eliminado” se utiliza para determinar si un usuario debe aparecer en los listados. Si bien podemos eliminar fácilmente un usuario de nuestra base de datos cuando abandona la compañía, simplemente es mejor marcarlos como eliminados. Aunque esto ocupa más espacio en la base de datos, es una buena práctica para conservar los registros. Puedes ver que no hay un estado de Entrada/Salida asociado al usuario, esto se debe a que su estado será registrado en la entidad Eventos.

Grupos

Un grupo es un conjunto de usuarios que comparten algo en común. En la mayoría de las empresas el personal se agrupa por departamentos, tales como Contaduría, Ventas y Atención al cliente. Puede ser útil permitir que los usuarios sean miembros de más de un grupo de forma tal que pueda estar en el grupo de su departamento y quizás pertenecer a algún grupo especial formado para un proyecto inter-departamental. Las siguientes propiedades se aplican a los grupos:

    * Nombre
    * Fecha de Alta
    * Descripción
    * Privado/Público
    * Eliminado (Sí/No)
    * Coordinadores
    * Recepcionistas

Un grupo privado es aquel que no es visible para los usuarios que no pertenecen a él. Un ejemplo sería un grupo de ejecutivos que no desean que sus estados sean conocidos por los no-ejecutivos.

Eventos

Un evento es simplemente un cambio en el estado de un usuario. Cuando un usuario sale del sistema, se generará un evento que registrará a qué usuario se refiere el evento, si el usuario entró o salió, su mensaje de estado y quién generó el evento. Aunque normalmente un usuario generará su propio evento, los recepcionistas pueden ingresar y retirar usuarios del sistema. Es importante registrar quién ingresó o retiró a un usuario dado. Las propiedades de los eventos son las siguientes:

    * Marca de Tiempo
    * Usuario
    * Entrada/Salida
    * Mensaje de Estado
    * Generador

Una vez que hayamos definido nuestras entidades, podemos armar un diagrama:

En la realidad existen algunas entidades más pero estas tres entidades principales son suficientes para este tutorial.

Entidades y Relaciones

Ahora que hemos definido nuestras entidades, es necesario estudiar las relaciones entre ellas. MySQL es una base de datos relacional y, como tal, los datos que la componen se definen mediante relaciones. Una forma de definir las relaciones entre entidades es en términos de las cantidades a cada lado de la relación entre dos entidades dadas. Por ejemplo, un usuario puede pertenecer a un grupo (Contaduría) o muchos grupos (Contaduría, Equipo de Fin de Año, Comité Organizador de Navidad). Esto se denomina relación de uno-a-muchos. Cada grupo contendrá muchos usuarios. La relación entre las entidades de grupos y usuarios es una relación muchos-a-muchos (muchos usuarios pertenecen a muchos grupos).

La relación entre los usuarios y eventos es diferente. Un evento se refiere a un usuario, ni uno más ni uno menos. Un usuario, por el contrario, tendrá muchas muchos eventos que se refieren a él. Esto significa que existirá una relación uno-a-muchos entre los eventos y los usuarios.

Estos dos tipos de relaciones (uno-a-muchos y muchos-a-muchos) serán tenidos en cuenta cuando diseñemos las tablas de nuestra base de datos. Por ahora, dibujemos unas flechitas para identificar una relación, con las puntas identificando el lado de “muchos” de la relación.

Las relaciones son opcionales cuando una relación puede definirse como cero-a-muchas, como es el caso entre las entidades usuario y evento. Un nuevo usuario podría no haber entrado o salido nunca del sistema. En este caso no existirían eventos relacionados con tal usuario.

Nuestras entidades afectarán nuestro software de dos formas. Las entidades que hemos diseñado serán utilizadas posteriormente para armar la base de las tablas de la base de datos. Además, estas entidades nos ayudarán a formar las clases, una unidad de construcción de nuestra aplicación final (el uso de clases en la programación de aplicaciones se denomina programación orientada a objetos y será explicada en una sección futura del tutorial).

Existen unas cuantas maneras de definir entidades de datos y sus relaciones. La descripción anterior es simplemente un vistazo general para que empieces a pensar en términos de entidades y no representa ningún método particular concreto para describir ni diagramar entidades. ¿Quieres aprender un método en particular? Depende.

Cuando trabajes por tu cuenta desarrollando una aplicación generalmente alcanza con armar un diagrama rápido de las entidades, sus propiedades y relaciones utilizando algún sistema que entiendas y con el cual te sientas cómodo. Si tienes que coordinar un gran proyecto y trabajar con otros desarrolladores será importante que adoptes un enfoque más formalizado.

Un buen sistema que se está haciendo bastante popular es UML, o Unified Modeling Language (Lenguaje de Modelado Unificado). Hay cientos de libros sobre UML, algunos de los cuales están específicamente orientados al uso de UML para diseñar aplicaciones en Visual Basic 6. Un ejemplo de esto es Developing Applications with Visual Basic and UML por Paul Reed. Un buen portal sobre recursos UML está disponible por IBM en http://www-306.ibm.com/software/rational/uml/. Presta mucha atención al documento “Introduction to the Unified Modeling Language”

Diseño de la Base de Datos

Una vez que hayamos definido nuestras entidades y sus relaciones, podemos continuar con el diseño del esquema de la base de datos. Al diseñar una base de datos, querremos dibujar nuestras tablas, con un icono por tabla, e incluir el nombre de la tabla y las columnas que la conforman. Yo utilizaré la herramienta de diseño Visio de Microsoft par realizar los diagramas de la base de datos pero ustedes pueden utilizar cualquier herramienta de dibujo que tengan (incluso el precario lápiz). Comencemos por lo siguiente:

Elección de una Clave Primaria

Ya tenemos todas nuestras entidades listadas con los campos que conformaran sus tablas. Lo primero que necesitamos agregar a nuestras tablas es una CLAVE PRIMARIA. Una clave primaria es una columna de la tabla que identifica unívocamente a cada fila de la tabla. En la tabla Usuario podrías tentarte y usar Nombre o quizás Número de Teléfono como clave primaria pero tu empresa podría tener más de un John Smith o los empleados podrían compartir un teléfono.

Aunque es posible juntar más de una columna como clave primaria compuesta (por ejemplo, hacer clave primaria la composición de Nombre y Número de Teléfono), tienes que asegurarte de que cada entrada sea única (¿qué sucede cuando dos John Smiths comparten los teléfonos?). ¿Entonces qué usamos como clave primaria? En este caso seguramente sea mejor agregar una nueva columna, llamada ID_Usuario. Esta columna será un entero y será incrementado automáticamente por MySQL mediante el uso de la palabra clave AUTO_INCREMENT (veremos más sobre AUTO_INCREMENT luego).

Para la tabla Grupo podemos utilizar la columna Nombre como clave primaria, ya es necesario que cada grupo tenga un nombre diferente para evitar la confusión cuando deba elegirse a qué grupos pertenecerán los usuarios. Para la tabla Evento podríamos usar la columna Marca de Tiempo como clave primaria pero hay una advertencia para este uso: el tipo de datos TIMESTAMP tiene una precisión del orden de segundos, lo que significa que si dos usuarios registran un evento en el mismo segundo (nada improbable en un sistema con cientos de usuarios), se violaría el requisito de unicidad de la clave primaria. En este caso tenemos dos alternativas: podemos usar la combinación de las columnas Usuario y Marca de Tiempo como clave primaria, asumiendo con seguridad que es improbable que un usuario dispare dos eventos en el mismo segundo. Al usar la clave primaria de otra tabla (el ID_Usuario de la tabla Usuario) como parte de la clave primaria de una tabla, estamos creando lo que se conoce como Relación Identificatoria.

Una relación identificatoria es aquella donde la tabla o entidad hija no puede existir sin su padre. Usuario y Grupo tienen una Relación No-Identificatoria porque un Usuario puede existir independientemente de pertenecer a un Grupo, y un Grupo puede existir sin que existan miembros. Un Evento, por el contrario, carece de sentido si no se refiriera a un usuario.

Otra opción es crear una nueva columna (ID_Evento) que sería una vez más un valor entero AUTO_INCREMENT. Generalmente cualquier enfoque resulta válido pero hay algo importante que debes tener en cuenta: MySQL y Visual Basic usan diferentes formatos de fecha. El formato YYYY-MM-DD HH:MM:SS de MySQL es generalmente malinterpretado por Visual Basic, que utiliza una fecha con formato M/D/YYYY HH:MM:SS. Veamos las diferencias, primero con una consulta MySQL y luego con un pequeño ejemplo en VB:

mysql> select now();
+---------------------+
| now() |
+---------------------+
| 2004-01-05 13:29:03 |
+---------------------+
1 row in set (0.02 sec)

Y ahora en la ventana inmediato de VB:

?now
1/5/2004 1:25:38 PM

Como podrás ver, hay grandes diferencias en el manejo de fechas. Aparte del orden de los valores, MySQL utiliza ceros a la izquierda para representar números menores que diez y utiliza un reloj de 24 horas. Estas diferencias en el manejo de las fechas pueden producir serios problemas para Visual Basic dado que VB esperará un formato mientras MySQL esperará otro. Por esta razón, se recomienda que NUNCA usen ninguna columna con tipo de dato fecha como parte de la clave primaria de una tabla. Por eso, utilizaremos una columna ID_Evento como clave primaria de nuestra tabla evento. Si bien esto no produce una relación identificatoria, igual la tratamos como perteneciente a la aplicación.

Echemos un vistazo a nuestro diagrama ahora que tiene claves primarias:

Debes haberte dado cuenta que cambié la columna Nombre de la tabla Grupo por Nombre_Grupo. El motivo por el cual hice esto es que las claves primarias generalmente se utilizan en las consultas a la base de datos que involucran múltiples tablas y es más fácil escribir SELECT Nombre_Grupo FROM Grupo, Usuario; en vez de SELECT Grupo.Nombre FROM Grupo, Usuario, en serio, es mucho más fácil así. Como verás, nuestras columnas de clave primaria se colocan en el cuadro central de nuestros iconos de tabla y han sido resaltados en negrita. Con un diagrama de base de datos de Visio, todas las columnas que forman parte de la clave primaria se muestras en el cuadro central y tienen el identificador PK a su izquierda. El resaltado en negrita indica que este es un campo requerido y no puede dejarse en blanco (un campo que no tiene un valor asignado en realidad tiene asignado el valor NULL, lo que significa que no está definido o no tiene un valor).

Elección de los Nombres de Campo y Campos Requeridos

A continuación, querremos abreviar los nombres de nuestros campos y designar los demás campos requeridos. Una aclaración sobre los nombres de campo: aunque en MySQL se pueden utilizar nombres campo con espacios, te hará las cosas más difíciles porque tendrás que encerrar el nombre entre comillas (“) cada vez que quieras usarlo. Por ejemplo, para acceder a la columna Fecha de Alta tendrías que hacer la consulta de esta manera: SELECT `Fecha de Alta` FROM Grupo; personalmente, no me gusta utilizar comillas y siempre uso guiones en las columnas para representar espacios cuando asigno las claves primarias (ID_Usuario) y uso mayúsculas para distinguir los nombres de columnas comunes (FechaAlta). Cuando pongas nombres a los campos, debes mantener la legibilidad, querrás que los nombres de columnas sean lo suficientemente cortos como para tipearlos rápido cuando los uses repetidas veces, pero también querrás asegurarte de que los desarrolladores (incluso tu mismo) puedan entender su significado:

Relaciones Uno-a-Muchos

Ahora que hemos nombrado las columnas, definamos las relaciones entre las tablas. Primero miremos la relación uno-a-muchos entre un Evento y un Usuario. Cuando manejamos una relación uno-a-muchos, ubicamos la clave primaria de la tabla de “muchos” como un campo en la tabla de “uno” (debería comentar que columna, campo y propiedad son sinónimos). En este caso, ya tenemos una columna Usuario en la tabla Evento pero hagámoslo más claro renombrándola para que concuerde con la definición de la tabla Usuario, llamándola ID_Usuario. También podemos usar la fecha de relación para dibujar nuestra relación (una vez más, la punta de la flecha apunta a la tabla de “muchos”):

Como puedes ver, se ha agregado un identificador FK1 a la columna de la izquierda, FK significa Foreign Key (Clave Foránea). Una clave foránea es simplemente una columna que se refiere a la clave primaria de otra tabla. El manejador InnoDB incluido en MySQL maneja lo que se conoce como integridad referencial. La integridad referencial es el requerimiento de que las claves foráneas representen valores reales. Por ejemplo, si trataras de insertar una fila a la tabla Evento que tuviera el ID_Usuario 10, InnoDB verificaría que existe un ID_Usuario 10 en la tabla Usuario y devolvería un error si tal fila padre no existiera. De manera contraria, no se permitiría eliminar una fila de la tabla Usuario si existieran filas en la tabla Evento que se refieran a la fila en cuestión. El uso de InnoDB está más allá del alcance de un tutorial sobre el uso básico de MySQL y no será tratado con más profundidad en este tutorial pero sí será el tema de algún artículo futuro. Puedes encontrar más información sobre InnoDB en: http://www.mysql.com/doc/en/InnoDB.html.

Relaciones Muchos-a-Muchos

Una vez establecidas las relaciones entre Evento y Usuario, podemos continuar con la definición de la relación entre Usuario y Grupo. Como recordarán, la relación entre Usuario y Grupo es una relación muchos-a-muchos. Esta clase de relación no es tan simple de implementar como una relación uno-a-muchos. En una relación uno-a-muchos, podemos ubicar la clave primaria de la tabla de “muchos” en una columna de la tabla de “uno”, pero esto no encaja efectivamente en nuestra situación de muchos-a-muchos: ¿qué tabla contendrá la clave primaria de la otra? La respuesta es que ninguna de las dos tablas contendrá la clave primaria de la otra. Por el contrario, crearemos una tercera tabla para unir las dos.

En este caso, la tabla Usuario_Grupo tiene dos claves foráneas: Nombre_Grupo e ID_Usuario. Estas dos claves foráneas forman una Clave Primaria Compuesta, asegurando que exista una sola entrada en la tabla para cada combinación única de Usuario/Grupo. Además, se han agregado dos campos que indicarán si es usuario es coordinador o recepcionista del grupo, permitiéndonos eliminar los campos de ambas tablas que se referían a coordinadores y/o recepcionistas de cada grupo y permitiendo también que un único usuario maneje varios grupos.

Normalizando la Base de Datos

La normalización de bases de datos se explica en detalle en otro artículo que escribí ubicado en http://www.vbmysql.com/articles/database-design/normalize.html y recomiendo que lo lean para más información sobre normalización de bases de datos. En este tutorial comentaré lo básico dado que se aplica a nuestro diseño de ejemplo. La normalización es el proceso de eliminar datos redundantes de las tablas con el fin de mejorar la eficiencia del almacenamiento, la integridad de los datos y la escalabilidad. Esta mejora supone un aumento de complejidad y potenciales pérdidas de performance debido a la unión de tablas normalizadas al realizar consultas.

Primera Forma Normal

El proceso de normalización apunta a lograr que nuestros datos se adapten a tres formas normales progresivas, y cada nivel superior de la normalización no se puede alcanzar hasta que se hayan alcanzado los niveles anteriores (en realidad existen cinco formas normales pero las últimas dos son principalmente académicas y no se discutirán). La primera forma normal (o 1NF) tiene como objetivo eliminar los datos redundantes de las filas horizontales. Queremos asegurarnos de que no existen datos duplicados en una fila dada y que cada columna almacena la menor cantidad de información posible (haciendo que los campos sean atómicos).

Tenemos dos violaciones a la Primera Forma Normal (1NF) en nuestro modelo de base de datos. El primero es que nuestra columna Nombre de la tabla Usuario guarda tanto los nombres como los apellidos de un usuario. Esto no representa la menor cantidad de datos posible. Además, dificulta el ordenamiento de usuarios por apellido. Finalmente, nuestros usuarios no podrás personalizar sus listas para mostrar fácilmente los nombres ordenados por nombre/apellido o apellido/nombre. Para resolver esto, simplemente dividimos nuestra columna Nombre en dos columnas:

La segunda violación a la 1NF es la redundancia horizontal de las columnas Estado (nota que aunque las columnas aparecen verticalmente en este diagrama, en realidad las columnas se agrupan horizontalmente cuando toman la forma de una tabla. Imagina la tabla como una hoja de un libro mayor, con encabezados de columnas en la parte superior de la página y filas individuales hacia abajo). No sólo será difícil hacer consultas sobre columnas horizontalmente redundantes (necesitarías una consulta como SELECT * FROM Usuario WHERE Estado1 = ‘Mi Estado’ OR Estado2 = ‘Mi Estado’), sino que les has restringido a tus usuarios la posibilidad de tener solamente dos mensajes de estado personalizados. Si un cliente solicita algún día la capacidad de almacenar tres mensajes de estado, tendrás que agregar otra columna y rescribir la consulta de ejemplo que di anteriormente. Las columnas horizontalmente redundantes pueden solucionarse agregando otra tabla para guardar los mensajes de estado. Esto también nos brinda la oportunidad de agregar los mensajes de estado predefinidos al sistema:

Nuestra nueva tabla de estados contendrá todos los mensajes de estado que se hayan ingresado alguna vez, sea un mensaje personalizado o predefinido. Nuestra tabla de eventos se vincula entonces con la tabla Estado para indicar qué mensaje de Estado utiliza el evento. Si un mensaje es predefinido entonces el campo ID_Usuario no se completará. Si el mensaje es un mensaje personalizado, entonces debe completarse el campo ID_Usuario, asociando el mensaje de estado con su autor para su posterior recuperación (recuerda que una de las características que figurará en la lista será la recuperación de mensajes de estado personalizados viejos para su reutilización).

Antes de poder decir que nuestra base de datos está en primera forma normal, hay otro ajuste que podemos hacer. En vez de guardar un indicador para Coordinador y otro distinto para Recepcionista, podemos combinar las dos columnas en una columna de Nivel Administrativo. Como los dos puestos son mutuamente excluyentes no tiene mucho sentido guardar los dos campos por separado ya que ningún usuario será Coordinador Y Recepcionista a la misma vez para un mismo grupo.

Como un usuario podría no tener privilegios de administrador sobre el grupo, puse el campo como no requerido. De esta forma, el campo puede completarse con NULL para indicar que el usuario no tiene privilegios de administrador.

Segunda Forma Normal

Así como la Primera Forma Normal elimina la redundancia de datos a lo largo de una fila horizontal, la Segunda Forma Normal (o 2NF) elimina la redundancia de datos de columnas verticales (en las que el mismo dato aparece en varias columnas). Las formas normales son progresivas, por lo tanto, para alcanzar la Segunda Forma Normal las tablas ya deben estar en Primera Forma Normal. En este caso, los títulos asignados a los niveles administrativos (recepcionista, coordinador) podrían aparecer potencialmente en muchas filas, ya que una gran empresa podría tener muchos recepcionistas. Solucionaremos la redundancia vertical del mismo modo que la redundancia horizontal, agregando tablas a nuestro esquema:

Nuestra nueva tabla nos permitirá cambiar el título de un nivel administrativo (por ejemplo, Coordinador por Supervisor) sin tener que hacer el cambio para cada usuario que es coordinador, como sería el caso si tuvieras la palabra coordinador en cada fila que le corresponda. Esto facilita el mantenimiento. Asimismo, puede pasarnos que eventualmente necesitamos agregar más datos acerca del nivel administrativo. Con este enfoque podemos agregar fácilmente indicadores a la tabla que representen los distintos privilegios que posee el usuario, luego permitir que los administradores creen nuevos niveles administrativos según lo crean conveniente, dando varios permisos según corresponda.

Tercera Forma Normal

En la Tercera Formal Normal buscamos datos en la tabla que no sean totalmente dependientes de la clave primaria pero dependientes de otro valor de la tabla. Toma una dirección como ejemplo: tu Ciudad y Estado no dependen de ti sino del código postal. Entonces, crearíamos una tabla aparte con Código Postal, Ciudad y Estado y sólo almacenaríamos el código postal en la tabla Usuario. Si bien este enfoque puede facilitar el mantenimiento, también puede introducir complejidad al tratar de armar una dirección. Por tal motivo, los datos deberían pasarse a tercera forma normal cuando sea necesario para lograr un buen mantenimiento de la información. En nuestro caso, no existe ninguna información en el esquema que requiera mayor normalización para llevarlo a tercera forma normal.

Elección de los Tipos de Columnas y Armado de Sentencias CREATE TABLE

Una sentencia CREATE TABLE es una consulta especial que le pasamos a MySQL para indicarle que cree una nueva tabla para almacenar nuestros datos. La sintaxis de CREATE TABLE puede encontrarse en el manual de referencia de MySQL en http://www.mysql.com/doc/en/CREATE_TABLE.html. Aunque la sintaxis parezca complicada, en realidad es bastante simple. Para crear tablas en MySQL, necesitamos básicamente un nombre de tabla, nombres para las columnas y el tipo de datos que soportará cada columna. Veamos la tabla Usuario primero.

El primer componente de nuestra consulta CREATE TABLE es la sentencia CREATE TABLE propiamente dicha, que indica el nombre de nuestra tabla:

CREATE TABLE Usuario
(

El paréntesis inicial indica que las líneas que siguen a continuación definen las columnas de nuestra tabla. Cuando definamos los campos necesitaremos alguna que otra información: primero necesitamos el nombre del campo, que tomaremos directo del diagrama anterior. Segundo, necesitamos los tipos de datos de cada campo. Es en este punto donde determinamos si el campo guardará información numérica o alfanumérica, información sobre fecha y hora u otros tipos de datos especiales. La lista completa de tipos de datos está disponible en el manual de referencia de MySQL en http://www.mysql.com/doc/en/Column_types.html, y les recomiendo que se remitan a la tabla de conversión de tipos de datos entre VB/MySQL en http://www.vbmysql.com/articles/visual-basic_mysql/datatypes.html.

Al elegir tipos de datos es importante mantener un equilibrio entre el tamaño de fila y el aprovechamiento. Cada campo ocupará una cierta cantidad de espacio en la fila y tendrá cierta capacidad para guardar información. Tomemos como ejemplo del ID_Usuario; nuestro campo ID_Usuario tendrá un valor entero y en teoría necesitamos uno por cada empleado de nuestra organización. Nuestras alternativas de tipos de datos incluyen TINYINT, SMALLINT, MEDIUMINT, INT y BIGINT. Los números máximos que se pueden almacenar con estos distintos tipos de datos son 127, 32767, 8388607, 2147483647 y 9223372036854775807 respectivamente.

En este caso podemos tomar el tipo TINYINT cuya capacidad es 127 y considerarlo demasiado pequeño para nuestro propósito. SMALLINT, cuya capacidad es 32767, debería ser más adecuado, incluso para las organizaciones más grandes. La razón por la que elegimos el tipo de datos más pequeño posible para nuestros datos reside en que los tipos de datos mayores generan filas más largas y las filas más largas requieren mayor tiempo de búsqueda al realizar consultas. Por lo tanto, siempre será conveniente hacer las filas lo más pequeñas posibles. Al elegir el tipo de datos SMALLINT de 16 bits en vez de, por ejemplo, el tipo de datos INT de 32 bits, nos hemos ahorrado casi 2 gigabytes de almacenamiento en más de un millón de filas. Como consecuencia, otra ventaja de elegir tipos de datos más pequeños es la mejor eficiencia de almacenamiento. Siempre podrás redefinir una columna a un tipo de datos más grande en el futuro, incluso cuando el servidor ya esté en funcionamiento.

El resto de nuestra descripción de filas se destina a información extra acerca del campo. Ante todo, cuando manejamos tipos de datos numéricos, tenemos la opción de especificar si el campo aceptará números negativos. El rango real de números que se pueden almacenar en un campo SMALLINT es de -32768 a 32767. En nuestra aplicación particular no tiene sentido tener un ID_Usuario negativo. Por tal motivo, sería mejor declarar el campo como UNSIGNED (sin signo). Esto no sólo evita la inserción de números negativos en nuestra tabla sino que además aumenta el valor máximo que podemos almacenar en nuestro campo a 65535 (esto se debe a que en formato binario el bit más a la izquierda de un número se reserva para representar el signo del número. MySQL utilizará el bit más a la izquierda para aumentar el tamaño máximo del número cuando se especifique UNSIGNED).

NOT NULL, DEFAULT, AUTO_INCREMENT y PRIMARY KEY

Otras opciones que podemos definir para este campo es si el campo permite valores NULL o no. Como recordarás, los campos definidos como requeridos en nuestro diseño deben tener un valor cuando se crea o actualiza una fila y NULL es una palabra clave que indica que el campo no tiene un valor asignado. Por eso, cualquier campo que hayamos definido como requerido tendrá que tener las palabras claves NOT NULL agregadas. NOT NULL evitará la inserción de NULLs y hará obligatorio el campo.

Relacionada con NOT NULL aparece la palabra clave DEFAULT. El hecho de que un campo se defina como NOT NULL no significa que tenemos que especificar un valor al insertar registros. Cualquier campo NOT NULL que no se especifique al insertar una fila tendrá el valor predefinido por la palabra clave DEFAULT. A los valores numéricos se les asignarán automáticamente un valor de cero, mientras que los strings tendrán por defecto una cadena vacía (‘’). Puedes utilizar la palabra clave DEFAULT para modificar este comportamiento.

Existen otras dos palabras claves finales que se utilizan comúnmente al crear tablas pero que sólo pueden definirse una sola vez. Estas son las palabras claves AUTO_INCREMENT y PRIMARY KEY. AUTO_INCREMENT indica que si no se especifica el campo al insertar filas, la base de datos generará automáticamente un valor automático incremental y lo guardará en el campo definido como AUTO_INCREMENT. Esto es muy útil cuando se utilizan enteros para identificar las filas, ya que el programador no tiene que preocuparse por crear un único número para cada fila que agrega. La palabra clave PRIMARY KEY se utiliza para definir un campo como clave primaria de la tabla. Veamos la definición de nuestra primera columna:

CREATE TABLE Usuario
(
ID_Usuario INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,

CHAR vs. VARCHAR

Ahora que ya hemos definido nuestra clave primaria, echemos un vistazo a nuestra tabla Usuario. Nuestros nombres de columna serán manejados como strings a los cuales se permite que contengan valores alfanuméricos. Los dos campos básicos para contener strings son CHAR y VARCHAR, los cuales se definen en términos de la cadena de texto máxima que pueden almacenar (definida en caracteres, entre 1 y 255). La diferencia entre CHAR y VARCHAR radica en la manera en que manejan el espacio sin usar. Suponte que consideramos que la cadena más larga para un apellido es de 40 caracteres y un usuario tiene el apellido Winstead (8 caracteres). En un campo CHAR, el campo aún seguiría siendo de 40 bytes de tamaño (1 carácter = 1 byte) y los últimos 32 caracteres serían espacios en blanco utilizados para rellenar la cadena a los 40 caracteres completos (los espacios sobrantes serán eliminados cuando recuperes el valor). Esto significa que no importa qué tan larga sea la cadena en realidad, siempre ocupará los 40 caracteres de espacio completos dentro de la tabla. VARHAR, por el contrario, almacenará sólo los 8 caracteres y ocupará solamente 8 bytes de espacio en la tabla.

Tu primer impulso sería elegir VARCHAR y sacar provecho del menor espacio de almacenamiento requerido en la tabla con el objetivo de aumentar la velocidad en las búsquedas tal como yo lo describí anteriormente pero VARCHAR es la excepción a la regla. Cuando usas VARCHAR en una tabla (al igual que ciertas columnas creadas para grandes cantidades de texto y valores binarios) el ancho de cada fila se hace inconsistente. Una fila podría tener 40 bytes de longitud mientras que otra sólo 8. MySQL puede manejar esto almacenando la longitud de la fila en su sistema de archivos pero el servidor debe leer la longitud de cada fila antes de buscarla y continuar con la siguiente fila, donde deberá verificar la longitud otra vez, ad nauseam. Al definir campos de texto como CHAR ocuparemos más espacio en el disco rígido pero habrá un aumento en la velocidad ya que el servidor sabrá que cada una de las filas tiene exactamente el mismo tamaño (por ejemplo 120 bytes), permitiéndole que busque entre las filas sin verificar su longitud primero. Por tal motivo, recomiendo que definas tus campos de texto como CHAR para mejorar la performance de las consultas, a menos que el espacio de almacenamiento sea una consideración importante (y con los precios de los discos de hoy en día esta no es una gran preocupación, principalmente con nuestra aplicación).

Echemos un vistazo a los nombres de las columnas:

CREATE TABLE Usuario
(
ID_Usuario INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
Apellido CHAR(40) NOT NULL,
Nombre CHAR(40) NOT NULL,

Como verás, cada campo será un campo CHAR que contendrá hasta 40 caracteres. Los campos se definen como NOT NULL para hacerlos obligatorios, con el uso del valor estándar de cadena vacía dado que no hemos definido lo contrario.

Almacenamiento de Números Telefónicos

No existe una manera de almacenar un número telefónico ya que el tipo de datos a utilizar puede depender de lo que planeas hacer con tus números de teléfono. Si quieres hacer búsquedas basadas en los códigos de área quizás te convenga almacenar las distintas partes de un número telefónico en forma separada, con un campo para el código de área, un campo para los primeros tres dígitos, un campo para los cuatro dígitos y quizás algún campo opcional para la extensión. Esto facilitará las búsquedas y el ordenamiento de los números de teléfono. En nuestro caso, sólo estamos almacenando el número para tener una referencia de los compañeros de trabajo de un usuario así que sólo lo guardaremos en una columna CHAR.

CREATE TABLE Usuario
(
ID_Usuario INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
Apellido CHAR(40) NOT NULL,
Nombre CHAR(40) NOT NULL,
Telefono CHAR(10) NOT NULL,

Nuestros campos NombreUsuario y Contraseña también serán declarados como columnas CHAR:

CREATE TABLE Usuario
(
ID_Usuario INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
Apellido CHAR(40) NOT NULL,
Nombre CHAR(40) NOT NULL,
Telefono CHAR(10) NOT NULL,
NombreUsuario CHAR(16) NOT NULL,
Contraseña CHAR(40) BINARY NOT NULL,

El manejo de ingresos de usuarios al sistema será discutido en un artículo futuro. La palabra clave BINARY utilizada en el campo Contraseña indica que queremos que todas las comparaciones en el campo Contraseña sean sensibles a mayúsculas y minúsculas (de forma que ConTRaseÑA y contraseña se traten como cadenas distintas al validar usuarios). Las cadenas en MySQL se tratan de forma sensible a mayúsculas y minúsculas a menos que se utilice la palabra clave BINARY.

Columnas ENUM

Para nuestro campo Administrador utilizaremos una columna ENUM. A una columna ENUM puede asignársele un solo valor, elegido de una lista de valores predefinido que declaramos al crear el campo. ENUM es muy práctico para representar conjuntos de valores que no aumentarán su tamaño a medida que crece la base de datos (por eso utilizaremos una tabla separada como con la tabla NivelesAdmin). En este caso, queremos representar un escenario que sólo puede tener dos valores: verdadero o falso (o eres administrador o no). Asignar un ENUM implica crear un conjunto de strings separadas por comas formando una lista de todos los valores posibles (puedes definir hasta 65535 valores potenciales distintos para una columna ENUM, pero si necesitas más de cinco o seis quizás sea mejor crear una tabla para guardar los valores):

CREATE TABLE Usuario
(
ID_Usuario INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
Apellido CHAR(40) NOT NULL,
Nombre CHAR(40) NOT NULL,
Telefono CHAR(10) NOT NULL,
NombreUsuario CHAR(16) NOT NULL,
Contraseña CHAR(40) BINARY NOT NULL,
Administrator ENUM('VERDADERO', 'FALSO') NOT NULL,

Columnas de Fecha

Las últimas dos columnas de nuestra tabla son los campos Creado y Eliminado. El campo Eliminado. El campo Eliminado es una vez más una columna verdadero/falso y será tratada igual que el campo Administrador. El campo Creado representa la fecha en la que se creó el registro. MySQL proporciona cuatro columnas para manejar información de fecha, cada una de las cuales es bastante descriptiva: DATE (fecha), TIME (hora), DATETIME (fecha y hora) e YEAR (año) (existe una quinta columna TIMESTAMP (marca de tiempo) que discutiremos más adelante). A la hora de elegir un tipo de datos a utilizar, considera qué clase de información necesitas. En su mayoría, los formatos más comúnmente utilizados son DATE y DATETIME ya que no tiene mucho sentido guardar sólo la hora del día o el año al almacenar información (recuerda que la mayoría de las personas no buscan información de hora sin tener en cuenta el día). Para nuestros propósitos, es apropiada la columna DATE ya que no es esencial saber la hora del día en que se creó la fila:

CREATE TABLE Usuario
(
ID_Usuario INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
Apellido CHAR(40) NOT NULL,
Nombre CHAR(40) NOT NULL,
Telefono CHAR(10) NOT NULL,
NombreUsuario CHAR(16) NOT NULL,
Contraseña CHAR(40) BINARY NOT NULL,
Administrator ENUM('VERDADERO', 'FALSO') NOT NULL,
Eliminado ENUM('VERDADERO', 'FALSO') NOT NULL,
Creado DATETIME NOT NULL
)TYPE = MyISAM;

El paréntesis final indica el fin de las definiciones de columnas. La palabra clave TYPE es opcional porque el tipo de tabla por defecto es MyISAM, pero podemos usar la palabra clave posteriormente para indicar que queremos utilizar algún otro manejador de tablas de MySQL, tales como InnoDB, HEAP o BDB por nombrar sólo algunos. Puedes encontrar más información sobre los manejadores de tablas en http://www.mysql.com/doc/en/Table_types.html, pero para los propósitos de este artículo nos quedaremos con el manejador de tablas por defecto MyISAM. El carácter punto y coma (;) le dice al servidor MySQL que hemos finalizado nuestra consulta y que puede proceder a ejecutarla. La ejecución de consultas será explicada en un tutorial futuro, por ahora sólo prepararemos las consultas para uso posterior. Te recomiendo que armes tus consultas en un editor de texto como el Bloc de Notas y las guardes con un nombre de archivo tipo sentencias_creación_tablas.sql. La extensión .sql indicará que el archivo contiene consultas SQL.

Campos TIMESTAMP

Un tipo de datos especial disponible en muchas bases de datos es TIMESTAMP. Una columna timestamp (marca de tiempo) es muy parecida al campo DATETIME (fecha y hora) pero tiene ciertas propiedades especiales. Si una tabla tiene una columna timestamp entonces MySQL llenará al campo automáticamente con la hora actual cuando se inserte una fila sin especificar un valor para la columna timestamp (o si la columna timestamp se especifica como NULL). La columna timestamp también será actualizada a la hora actual cuando se actualice una fila con nueva información (otra vez, siempre y cuando la columna no se especifique o se establezca a NULL).

Una propiedad útil de las columnas timestamp es su comportamiento cuando tienes más de una columna timestamp en una tabla. Cuando tienes varias columnas timestamp en una tabla, a todos los campos timestamp se les asignará la hora actual cuando se inserte una nueva fila, pero sólo la columna timestamp más a la izquierda será actualizada en las actualizaciones subsiguientes de la tabla. Esto significa que puedes poner dos campos timestamp en la tabla, con el de la derecha almacenando la fecha de creación de la tabla y el de la izquierda registrando la última actualización de la fila. Nosotros utilizaremos el tipo de datos TIMESTAMP para guardar la hora de creación de los eventos en nuestra tabla Evento, utilizando el nombre MarcaTiempo o Timestamp en inglés. Generalmente, no se puede utilizar un tipo de datos como nombre de columna porque es una palabra reservada, pero el uso de la palabra Timestamp como nombre de columna es una excepción en MySQL:

CREATE TABLE Evento
(
ID_Evento MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
ID_Usuario SMALLINT UNSIGNED NOT NULL,
ID_Mensaje MEDIUMINT UNSIGNED NOT NULL,
MarcaTiempo TIMESTAMP,
Estado ENUM('Entrada','Salida') NOT NULL,
Creador SMALLINT UNSIGNED
)TYPE = MyISAM;

Un par de cosas a tener en cuenta es que se cambió el nombre de la columna Entrada/Salida por Estado para reflejar mejor su significado (ya que Entrada/Salida dice qué se puede almacenar en la columna pero no qué significa). Además, la columna Creador se cambió de requerido a no requerido. La razón por la que hacemos esto es que un creador NULL puede significar que el usuario descrito por el evento es su creador, lo que podría ser de ayuda en un futuro para determinar cada cuánto se crean eventos por parte de usuarios distintos al especificado por el evento. Es importante destacar que el diseño puede ser un proceso iterativo y que cambios como éste se hacen frecuentemente. Lo importante es acordarse de actualizar tu documentación al hacer cambios:

Claves Primarias Compuestas

En la tabla Usuario_Grupo tenemos una clave primaria compuesta. No podemos definir ambas columnas con la palabra clave PRIMARY KEY sino que debemos utilizar una sintaxis diferente:

CREATE TABLE Usuario_Grupo
(
Nombre_Grupo CHAR(20) NOT NULL,
ID_Usuario SMALLINT UNSIGNED NOT NULL,
ID_Nivel TINYINT UNSIGNED,
PRIMARY KEY (ID_Usuario, Nombre_Grupo)
)TYPE = MyISAM;

Cuando definimos claves primarias compuestas, definimos la clave primaria luego de terminar de definir las columnas.

Definición de las Tablas Restantes

Las tablas restantes de nuestra aplicación siguen los mismos principios que hemos descrito hasta ahora:

CREATE TABLE Estado
(
ID_Mensaje MEDIUMINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
ID_Usuario SMALLINT UNSIGNED,
Mensaje CHAR(255) NOT NULL,
Eliminado ENUM('Verdadero','Falso')
)TYPE = MyISAM;

CREATE TABLE Grupo
(
Nombre_Grupo CHAR(20) NOT NULL PRIMARY KEY,
Creado DATETIME NOT NULL,
Ambito ENUM(‘Publico’,'Privado’),
Eliminado ENUM(‘Verdadero’,'Falso’)
)TYPE = MyISAM;

CREATE TABLE NivelesAdmin
(
ID_Nivel TINYINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
Titulo CHAR(20) NOT NULL
)TYPE = MyISAM;

El conjunto entero de definiciones de las tablas se encuentra disponible en http://www.vbmysql.com/download/vb-mysql-tutorial.sql.

Fíjate que en inglés una vez más ha surgido el problema de las palabras reservadas ya que la tabla Group (Grupo) utilizaba una palabra reservada. Es posible usar una palabra reservada como nombre de columna o tabla encerrándola entre comillas simples (`Group`) cada vez que quieras usarla pero yo prefiero evitar el problema. En cambio, se renombraría la tabla por Groups (Grupos) (en general debe evitarse el uso de palabras plurales en los nombres de tabla).

Debe observarse que al igual que usar el mismo nombre para una clave foránea y la clave primaria (usa ID_Usuario en todas las tablas en las que se haga referencia), también deberías asegurarte de usar el mismo tipo de datos. Por lo tanto, asegúrate de que todos los campos ID_Usuario son SMALLINT UNSIGNED y que todos los campos Nombre_Grupo son CHAR(20). Asegúrate de que todas las columnas CHAR y VARCHAR tengan el mismo ancho (en este caso 20 caracteres) ya que no querrás que una tabla pueda almacenar un nombre de grupo más largo que otra.

Conclusión

Hemos creado una lista de funciones y requerimientos para nuestra aplicación que no sólo nos ayudará a determinar cuándo estará completo nuestro proyecto sin que también nos ayudará a definir las entidades de nuestra aplicación. Utilizaremos nuestro diseño de entidades para definir los objetos de nuestra aplicación y también para diseñar las tablas de nuestra base de datos. Una ven que nuestras tablas han sido definidas y diseñadas, podemos utilizar sentencias CREATE TABLE para crear las tablas en nuestro servidor MySQL.

En mi próximo artículo explicaré la instalación del servidor MySQL bajo Windows y luego comentaré lo básico para crear una base de datos y las tablas que la componen.

  1. aser
    December 22nd, 2006 at 23:44 | #1

    excelente tutorial

  2. Arquimedes
    February 2nd, 2007 at 12:52 | #2

    Excelente lo felicito, mejor imposible

  3. lalo
    February 27th, 2007 at 23:32 | #3

    tutorial 1

  4. Julio
    February 28th, 2007 at 13:08 | #4

    Espero que este manual contenga lo que necesito.

  5. Alberto
    March 7th, 2007 at 12:21 | #5

    No funcionan los enlaces para bajarse los scripts

  6. March 20th, 2007 at 12:57 | #6

    Apreciado compañero necesito un tutorial de mysql que enseñe como crear el usuario administrador y hacer las conecciones con las diferentes bases de datos.

    gracia por tu apoyo.

  7. April 5th, 2007 at 00:11 | #7

    Que tal he logrado trabajar con BD de MySQL de forma local, pero quisiera hacerlo de forma remota, cuando trato de hacerlo mi programa encuentra el servidor pero no se puede conectar, como hago para configurar el MySQL para aceptar un usuario remoto..

    Desde ya gracias.

    J. Roberto

  8. welington
    April 20th, 2007 at 21:55 | #8

    estuve practicando lo de vb.net primera y segunda parte pero, cuando instalo el MySql y Browser este ultimo no se conecta ni con 127.0.0.1 ni con el nombre de mi pc local…

    me dice que no puede establecer la coneccion con la base de datos aunque le especifique “test” por que es la defaul.. este es el mensaje original

    could no connect to the specified instance
    Mysql erro number 1045
    Access denied for user ODBC@localhost (using password no)
    if you want to check the network connection, pleasi click ping bottom

    en ping botton me muestra que tengo acceso, me hace ping al localhost

    nota esta es la informacion que escribo en el browser
    store connection nada (en blanco)
    server host (127.0.0.1)
    port (defaul 3306)
    user name (en blanco)
    password (en blanco)
    defaul schema (test)

    como lo indica el manual, que podria estar pasando…

  9. M.Ivan
    May 23rd, 2007 at 01:14 | #9

    hola quisiera saber como conectar una base de datos de Mysql a un formulario de Visual Basic 6
    toda la sentencias por fa vor se como crear database, table llenarlas por comando se trabajar sobre vb6 pero no se como hacer la ligas entre ambas

  10. Aser
    May 26th, 2007 at 21:37 | #10

    Ivan aqui te va un ejemplo del codigo para la conexion

    Dim CnnService As ADODB.Connection
    Dim Cnn4 As New ADODB.Recordset

    strConn = “DRIVER={MySQL ODBC 3.51 Driver}; SERVER=ip_servidor; DATABASE=test;UID=root;PWD=; OPTION=3″

    Set CnnService = New ADODB.Connection
    CnnService.CursorLocation = adUseClient

    por supesto solo tienes que poner los datos de server, database, UID y PWD, pero antes tienes q bajar la libreria ODBC que se encuentra gratuita en la pagina de MySQL
    y luego agregar el componente a tu proyecto. y listo tienes un objeto connection(CnnService) y un objeto recorset(Cnn4) mediante el cual puedes realizar las consultas

  11. Richitsu
    June 7th, 2007 at 19:53 | #11

    Tengo una duda, si quiero implementar mysql visual basic empresarial 6.0, es necesario primero meterse a mysql por consola o visual basic contiene un comando para conectarse?

    Gracias Saludos

  12. Jhorbam
    June 10th, 2007 at 02:53 | #12

    Hola a todo mundo…me podrian colaborar indicandome como usar los comandos Grant y Revoke desde Visual Basic 6….gracias

  13. omishe
    June 18th, 2007 at 21:47 | #13

    Saludos, necesito saber que hacer para que mis campos de texto acepten una cantidad mayor a los 255 caracteres que te permite el mysql, para agregar una caja de comentarios como la que contiene este portal.

    Gracias!

    Saludos, necesito saber que hacer para que mis campos de texto acepten una cantidad mayor a los 255 caracteres que te permite el mysql, para agregar una caja de comentarios como la que contiene este portal.

    Gracias!

    Saludos, necesito saber que hacer para que mis campos de texto acepten una cantidad mayor a los 255 caracteres que te permite el mysql, para agregar una caja de comentarios como la que contiene este portal.

    Gracias!

    Saludos, necesito saber que hacer para que mis campos de texto acepten una cantidad mayor a los 255 caracteres que te permite el mysql, para agregar una caja de comentarios como la que contiene este portal.

    Gracias!

    Saludos, necesito saber que hacer para que mis campos de texto acepten una cantidad mayor a los 255 caracteres que te permite el mysql, para agregar una caja de comentarios como la que contiene este portal.

    Gracias!

    Saludos, necesito saber que hacer para que mis campos de texto acepten una cantidad mayor a los 255 caracteres que te permite el mysql, para agregar una caja de comentarios como la que contiene este portal.

    Gracias!

  14. June 21st, 2007 at 16:18 | #14

    PUEDES UTLIZAR EL TIPO DE DATO TEXT EN VEZ DE VARCHAR(255)

  15. omishe
    June 21st, 2007 at 16:20 | #15

    muchas garcias Alex Figueroa, voy a poner en practica la información que me has proporcionado.

  16. christian
    June 21st, 2007 at 19:28 | #16

    Hola necesito saber como esq enlazo una base de datos en mysql a visual basic

  17. Jarzhino
    July 13th, 2007 at 15:38 | #17

    Buenos dias, estoy diseñando un sistema uttilizando visual basic 6 y mysql. Tengo el siguiente problema: cuando registro los datos en las tablas, si dentro de la cadena que ingreso esta el siguiente caracter \ o la ñ o las vocales con tilde (á, é í ó ú )simplemente este no se almacena en la tabla. Por favor podrian ayudarme con respecto a esto.
    Gracias

  18. July 13th, 2007 at 15:43 | #18

    Hola, creo que deberías volver a configurar el servidor de Mysql, ahí hay la opción de que te acepte caracteres o te de soprte para multilenguaje…

    Espero que te ayude

  19. Margarita
    August 23rd, 2007 at 18:05 | #19

    hola, muy buen articulo!!!! :) , estoy trabjando con mysql y visual basic 6.0 , de hecho ya casi termino pero ahora estoy tratando de sacar reportes, y hooooooo sorpresa, primero por q apenas estoy iniciandome en esto pero ya trate de muchas formas de sacar mis reportes y nada, pero me surgio una gran duda y es que no habia notado q visual basic maneja de una forma distinta las fechas a mysql hasta que decidi sacar mis reportes por fechas y buscarlos por medio de un DTPicker y ahi es donde me causa muchos problemas ya que por ejemplo del DTPicker la fecha se rescata asi 15/08/2007 y al dar la instrucción del select le digo q me lo cambie a el formato yyyy/mm/dd osea q queda asi 2007/08/15 pero el grannnn PROBLEMA es que en mysql al haber realizado una venta se guardo asi 2007/8/15, asi que al buscar una venta con esta fecha no me trae nada por q la fecha no coincide y me manda un error de q el registro no se encuentra o se elimino.
    Alguien podría ayudarme por favor!!!, se los agradeceria muchisisisisismo.
    saludos!!!

  20. September 2nd, 2007 at 01:08 | #20

    Ya termine un sistema pero ahora, como puedo crear un instalador q instale MYSQL de forma local junto con mi aplicacion en VB.net.. para poder distribuirla e instalarla en una PC. ue herramientas puedo utilzar. Gracias de antemano, y el manual esta muy bien explicado Thks.

  21. Emmanuel
    September 25th, 2007 at 20:23 | #21

    Muy bueno tu tutorial, lo que mas me fasino es que explicas muchas cosas a detalle como los tipos de datos que se usan en mysql.
    Gracias
    Saludos

  22. Esteban Ruiz
    October 1st, 2007 at 00:51 | #22

    Hola a todos:
    Hace tiempo hice un programa en Visual Basic ocupando MySql como base de datos, resulta que hice todo lo que encotre en los manuales y de hecho resulto muy bien, pude hacer consultas, insertar registros crear tablas, y crear la la estructura completa de mi base de datos en MySql desde Visual Basic.
    El problema sucedio cuando quise intalar mi programa en otro computador, al prinsipio no hubo problema me podia conectar a la base de datos y hacer consultas pero cuando la la cantidad de resgistros que obtenia despues de hacer una consulta sobrepasa una catidad por ejemplo de 30 datos el programa se cae y Window me arroja un error y hace referencial al dll MSRDO20.DLL que hace la coneccion entre VB y MySql, lo he provado en varios coputadores que poseen la misma version de window que tiene mi computador, he copiado esta dll desde mi Computador a los demas computadores y la he registrado pero no se soluciona el problema, he revisado cada parte de codigo y me atrevo a decir que no es el problema.
    Lo “misterioso” de esto es que el programa funciona pero solo en mi computador,

    Si alguen me puede ayudar lo agadeceria mucho, les ha pasado alguna vez a ustedes algo parecido, Agradeceria mucho cualquier comentario.

    Saludos a todos

  23. Esteban Ruiz
    October 5th, 2007 at 20:12 | #23

    Hola a todos

    Si ha alguen le interesa ya encontre la solucion. El problema estaba con el conector ODBC de MySql yo estaba trabajando con el 3.51.16 y cuando lo hice correr el programa en otro equipo ocupe el conector ODBC 3.51.17 Luego intale el 3.51.20 y se soluciono el problema al parecer el conector 3.51.17 produjo el error.
    Otra cosa mas deben tener cuidado cando definen en MySql una columna del tipo DECIMAL suele producir problemas cuando trabajas con VB, ya que no te aproxima el decimal cuando necesitas trabajar con muchos decimales.

    Saludos a todos

  24. Esteban Ruiz
    October 5th, 2007 at 20:14 | #24

    Correccion: No te entrega todos los decimales en algunos casos

  25. Gusstavv
    October 9th, 2007 at 19:49 | #25

    Hola!
    Tengo el mismo problema que Jarzhino sobre los simbolos especiales en español, como es la ñ, y los acentos… Igual estoy con VB6. Alguien sabe como solucionarlo?? Se que es problema de encoding, porque el VB6 no maneja nativamente el UTF8, y normalmente las bases de datos en MySQL para almacenar estos simbolos, asignan el “cotejamiento” a utf8_general_ci…
    Alguien ha encontrado la combinacion correcta de cotejamiento en la base de datos para q funcione en VB6??? o es el maldito ODBC???
    Saludosss!!

  26. Gusstavv
    October 9th, 2007 at 21:07 | #26

    Lo sabia… pa q pifen las ñ y los acentos, necesitas definir el cotejamiento como latin1_general_ci y establecer en el odbc que el charset es latin1, y lizzztoo!! ^^

  27. OMARmm
    January 20th, 2008 at 21:34 | #27

    TE FELICITO MUY BUENA AYUDA PARA LOS QE ESTAMOS INICIANDONOS, TE TENGO DOS CONSULTAS Y CREO ESTAR SEGURO QUE PODRAS AYUDARME. PASA QE TENGO UNA APLICACION CLIENTE SERVIDOR CON VB6 Y EL MYSQL 4.1.0. MI CONSULTA ES PUNTUAL ES POSIBLE ACTUALIZAR UN REGISTRO EN UNA TABLA SIN NECESIDAD DE HABER HECHO ALGUNA MODIFICACION CON DICHO REGISTRO AL USAR UN UPDATE CON CONECCION ADO??, POR QUE CUANDO ESTABA AVANZANDO CON MIS MANTENIMIENTOS ME SALIO UN ERROR AL ACTUALIZAR UN REGISTRO QUE NO HICE CAMBIOS, PERO DICHO ERROR NO ME SALE CUANDO SI SE HACE ALGUNA MODIFICACION SOBRE DICHO REGISTRO. EN OTRAS PALABRAS ASI COMO ESTA INSTALADA MI MYSQL AL NIVEL CLIENTE ME FUERZA A ACTUALIZAR ALGUN DATO DE UN REGISTRO NECESARIAMENTE LO CUAL NO LO VEO PRACTICO O ES CUESTION DE CONFIGURACION DEL MYSQL AL NIVEL SERVIDOR. Y MI OTRA CONSULTA ES QUE EL PATH DEL DIRECTORIO DONDE SE GUARDA LA BASE DE DATOS PODRIA SER DIRECCIONADA A OTRA CARPETA U OTRA UNIDAD LOGICA??, GRACIAS DE ANTEMANO AMIGO, TU APORTE VA SER MUY LEIDA POR TODOS. UN SALUDO DESDE PERU A TODA LA GENTE :)

  28. justorfc
    March 21st, 2008 at 21:15 | #28

    Excelente artículo

  29. yohnike
    April 20th, 2008 at 18:47 | #29

    Hola bueno , estube leyendo los comentarios y por supuesto el tutorial, lo encontre muy bueno, pero aun asi no encontre la respuesta a mi problema, se q’ para Ud’s sera facil, pero yo e intentado y no lo he podido solucionar, aqui va!!

    No he podido insertar registros a los campos , a través de vb 6 a mi base de datos de Mysql.
    Con este formulario debo ingresar el NOMBRE PROFESOR y DERECCION, y de hay insertarlo en mi bd en los campos PRO_NOMBRE (NOMBRE PROFESOR) y PRO_DIRECCION (DIRECCION).

    Bueno en definitiba eso no se hacer como insertar registros a los campos de mi bd a través de vb 6!

    Ojal a me ayuden , se los agradesere mucho!!

  30. jose miguel
    April 24th, 2008 at 12:46 | #30

    hola me pueden explicar como guardar datos en una base de dqatos desde visual basic a una base de datos en mysql, si pudieran ayudarme

  31. jesus osuna
    July 1st, 2008 at 01:36 | #31

    me prece muy bien los temas e interesantes

  32. October 18th, 2008 at 14:25 | #32

    No puedo guardar acentos en la base de datos de MySql,
    como hacer para almacenar palabras acentuadas en MYSQL desde VB
    y como hacer para recuperar los campos..

    Saludos
    Por favor si pueden hechenme una mano..

    Gracias de ante mano.

  33. chechu
    January 13th, 2009 at 23:09 | #33

    Haciendo una breve reseña de lo que estoy intentando hacer, les comento:
    Estoy trabajando con VB .NET 2005 y MYSQL 5.0
    Conectando via ADO .NET
    Mi problema es el siguiente:
    Tengo una llamada Costos (por darle un Nombre)
    Que tiene una columna con datos Decimales
    Pero cuando hago mi consulta y lo cargo en un Dataset, para luego asignar a un Textbox, como en mi Configuración Regional esta Predeterminado que la coma (,) es separador de Decimales, me toma al punto (.) como separador de Miles, por lo tanto como en la Base de Datos el valor es por ej. 10.3 entonces me toma como 103,00

    Quisiera poder recibir bien los datos, sin necesidad de modificar mis configuraciones Regionales.

    Aguardo sus comentarios al respecto, y desde ya agradezco su ayuda.

    Saludos..

  34. Martha
    February 23rd, 2009 at 13:12 | #34

    el tutorial es muy bueno quisiera acceder al proximo si lo puedes mandar a mi imail te lo agradeceria

  35. Isaac Laquedem
    April 13th, 2009 at 04:30 | #35

    hola chechu

    Tu solución es muy simple

    Tienes una cadena de entrada (lo que lees en tu base de datos pasado a cadena)
    Necesitas una cadena de salida para pasar al textbox

    El código en Vb6.0 es el siguiente
    Operas así: CadenaSalida = Replace(CadenaEntrada, “.”, “,”)
    imagino que en vbNet sea muy similar.

    I.L.

  36. jorge
    May 25th, 2009 at 19:09 | #36

    que es esto?, dinos como hacer la coneccion desde el cliente a una base de datos alojada en un servidor.

  37. AVECOSoft
    November 22nd, 2009 at 17:42 | #37

    Hola:

    Oye yo tengo un problema, migre mi bd de Access a MySQL y los campos que eran SI/NO ahora son TinyINT con valores -1 y 0 respectivamente. Mi problema recide al intentar comparar directamente un campo de este tipo en visual basic 6 ej.

    if Recordset.Fields(“Supervisor”) = -1 then MsgBox “Es un supervisor”)

    Al realizar dicha comparación me devuelve el error:

    458 : La variable usa un tipo de Automatización no admitido en Visual Basic

    Como puedo solucionar esto, ojala me ayudes por fa!

    Saludos…

  38. OpenComm
    December 21st, 2009 at 12:27 | #38

    Hola:

    Tengo el siguiente problema, migré mi bd de Access a MySQL y los campos que eran SI/NO ahora son TinyINT con valores -1 y 0 respectivamente. Mi problema recide al intentar comparar directamente un campo de este tipo en visual basic 6 ej.

    if Recordset.Fields(”Supervisor”) = True then

    Al realizar dicha comparación me devuelve el siguiente error:

    458 : La variable usa un tipo de Automatización no admitido en Visual Basic

    Como puedo solucionar esto, ojala me ayuden. Muchas gracias

    Saludos…

  39. March 26th, 2010 at 16:30 | #39

    Hola, muchas felicidades a tu publicacion, me parece que es bueno que hagas publicaciones para ayudar a entender mas acerca de este tipo de temas.

    Yo no hago muchos comentarios acerca de este tipo de temas en sitios web, pero me parecio muy interesante este tema y la forma en que redactas, no perdiendo detalle acerca de que se esta realizando.

    Si me permites acerte un comentario, espero que para tu proxima publicacion agregues nuevos software para el diseño de bases de datos como el navicat o el Phpcake.

    Buena suerte. Y felicidades.

  40. carlos
    May 17th, 2010 at 16:18 | #40

    hola
    necesito ayuda urgente lo que pasa es que estoy realizando una aplicacion con visula basic 2005 y sql server sobre el registro y prestamo de equipos y necesito que al momento de registrar el prestamo el estado del equipo se actualice automaticamente que pase de disponible a no disponible la verdad necesito ayuda lo mas pronto posible

  41. ClaCS
    May 20th, 2010 at 21:47 | #41

    Muy buen tutorial

    Me despejo de algunas dudillas y me dio a conocer otras cosas q desconocia ;)

    …por cierto muy bueno el site y la tematica

    Salu2

  1. No trackbacks yet.