3 Crear una base de datos

Hemos empezado por lo más simple: leer datos desde una base de datos existente. En este capítulo veremos cómo crear y eliminar bases de datos y tablas.

En este capítulo y el siguiente crearemos una aplicación de ejemplo para gestionar una base de datos simple de contactos, con sólo nombres y números de teléfono.

La base de datos se llamará "agenda", y para poder empezar a trabajar con ella necesitaremos un usuario con acceso a esa base de datos y con todos los privilegios. De modo que empezaremos por abrir una sesión MySQL y conceder al usuario "curso" todos los privilegios sobre la tabla "agenda". Recondermos que esto se puede hacer aunque tal base de datos no exista:

mysql> GRANT ALL ON agenda.* TO curso;
Query OK, 0 rows affected (0.08 sec)

La base de datos "agenda" contendrá dos tablas, una con los nombres de los contactos, y una segunda con los números de teléfono. Ambas tablas estarán interrelacionadas por una clave de indentificación de usuario:

Diagrama de Agenda
Diagrama de Agenda

La estructura de la tabla de nombres es:

  • id: clave identificadora. Usaremos un entero autoincrementado.
  • nombre: nombre de contacto. Usaremos una cadena de longitud variable de 40 caracteres.

En cuanto a la tabla de teléfonos, la estructura es:

  • id: clave identificadora de contacto. Clave foránea de la tabla de nombres. Crearemos una referencia de modo que las modificaciones de clave se transmitan en cascada y los borrados también.
  • tipo: tipo de teléfono. Indicará si es un celular, fijo, particular, etc. Usaremos una cadena de longitud variable de 20 caracteres.
  • numero: número de teléfono. Usaremos una cadena de longitud variable de 15 caracteres.

Por supuesto, usaremos tablas InnoDB.

Averiguar si existe una base de datos

Antes de empezar a trabajar con una base de datos puede ser interesante saber si tal base de datos existe o no. Esto nos permitirá crear la base de datos si es la primera vez que se ejecuta la aplicación o si se ha eliminado la base de datos desde la última ejecución.

Para averiguar si una base de datos existe intentaremos activarla, y si se produce un error, verificaremos si ese error es debido a que la base de datos no existe. Para ello comprobaremos si el valor de error es ER_BAD_DB_ERROR. Vamos a crear una función C++ para esta tarea:

bool ExisteDB(MYSQL *myData, char *db)
{
   // Conectar a base de datos.
   if(mysql_select_db(myData, db)) {
      if(ER_BAD_DB_ERROR == mysql_errno(myData)) return false;
   }
   return true;
}

Otra alternativa, quizás mucho mejor, es verificar si existe la base de datos usando una sentencia SHOW DATABASES. Si mostramos sólo las bases de datos cuyo nombre coincida con el de la que deseamos verificar, bastará con comprobar el número de filas retornadas. Si ese número es cero significa que la base de datos no existe:

bool ExisteDB(MYSQL *myData, char *db)
{
   char *consulta;
   char *plantilla = "SHOW DATABASES LIKE \'%s\'";
   MYSQL_RES *res;
   bool valorret = true;

   consulta = new char[strlen(db)+strlen(plantilla)];
   sprintf(consulta, plantilla, db);

   if(!mysql_query(myData, consulta)) {
      if((res = mysql_store_result(myData))) {
         // Procesar resultados
         if(!mysql_num_rows(res)) valorret = false;
         // Liberar el resultado de la consulta:
         mysql_free_result(res);
      }
   }
   delete[] consulta;
   return valorret;
}

Hemos tenido que hacer uso de memoria dinámica para preparar la cadena para hacer la consulta. Esto será muy habitual, sobre todo cuando las consultas se compliquen, y requieran selecciones y proyecciones (seleccionar columnas y filas). Más adelante crearemos una función para hacer este proceso más sencillo.

Crear una base de datos

A pesar de que existe una función en el API C de MySQL para crear bases de datos, mysql_create_db, su uso está desaconsejado, y es preferible usar mysql_query para lanzar una consulta CREATE DATABASE.

   if(!ExisteDB(myData, "agenda")) {
      cout << "La base de datos \"agenda\" no existe." << endl;
      cout << "La creamos..." << endl;
      mysql_query(myData, "CREATE DATABASE agenda");
   }

Esto creará la base de datos "agenda" si no existe previamente, pero no creará ninguna tabla.

Comprobar si una tabla existe

Para comprobar si existe una tabla podemos hacer algo parecido a lo que hemos hecho con la base de datos. Intentaremos hacer una consulta sobre la tabla, y si fracasamos, verificaremos si el error es ER_NO_SUCH_TABLE. En tal caso, la tabla no existe.

Crearemos otra función C++ para esta tarea:

bool ExisteTabla(MYSQL *myData, char *db, char *tabla)
{
   char *consulta;
   char *plantilla = "SELECT * FROM %s.%s";
   bool valorret = true;

   consulta = new char[strlen(db)+strlen(tabla)+strlen(plantilla)-1];
   sprintf(consulta, plantilla, db, tabla);
   if(mysql_query(myData, consulta)) {
      if(ER_NO_SUCH_TABLE == mysql_errno(myData)) valorret = false;
   }
   delete[] consulta;
   return valorret;
}

Otra opción, mucho más recomendable, es hacer una consulta usando la sentencia SHOW TABLES, de un modo análogo al usado con las bases de datos:

bool ExisteTabla(MYSQL *myData, char *db, char *tabla)
{
   char *consulta;
   char *plantilla = "SHOW TABLES FROM %s LIKE \'%s\'";
   MYSQL_RES *res;
   bool valorret = true;

   consulta = new char[strlen(db)+strlen(tabla)+strlen(plantilla)-1];
   sprintf(consulta, plantilla, db, tabla);

   if(!mysql_query(myData, consulta)) {
      if((res = mysql_store_result(myData))) {
         // Procesar resultados
         if(!mysql_num_rows(res)) valorret = false;
         // Liberar el resultado de la consulta:
         mysql_free_result(res);
      }
   }
   delete[] consulta;
   return valorret;
}

Crear una tabla

Para crear una tabla usaremos la sentencia CREATE TABLE. El proceso se explica con detalle en el capítulo 7 del curso de MySQL.

Para crear las tablas que necesitamos para esta base de datos usaremos las siguientes consultas SQL:

mysql> CREATE TABLE agenda.nombres (
    -> id INT NOT NULL AUTO_INCREMENT,
    -> nombre VARCHAR(40),
    -> PRIMARY KEY (id))
    -> ENGINE=InnoDB;
Query OK, 0 rows affected (0.61 sec)

mysql> CREATE TABLE agenda.telefonos (
    -> id INT NOT NULL,
    -> tipo VARCHAR(20),
    -> numero VARCHAR(15),
    -> FOREIGN KEY (id) REFERENCES nombres(id)
    -> ON DELETE CASCADE
    -> ON UPDATE CASCADE)
    -> ENGINE=InnoDB;
Query OK, 0 rows affected (0.14 sec)

mysql>

En nuestro programa C++ crearemos las tablas que no existan usando este código:

   if(!ExisteTabla(myData, "agenda", "nombres")) {
      cout << "La tabla \"Nombres\" no existe." << endl;
      cout << "La creamos..." << endl;
      mysql_query(myData, "CREATE TABLE agenda.nombres ("
         "id INT NOT NULL AUTO_INCREMENT, "
         ";nombre VARCHAR(40), "
         ";PRIMARY KEY (id)) "
         "ENGINE=InnoDB");
   }

   if(!ExisteTabla(myData, "agenda", "telefonos")) {
      cout << "La tabla \"Telefonos\" no existe." << endl;
      cout << "La creamos..." << endl;
      mysql_query(myData, "CREATE TABLE agenda.telefonos ("
         "id INT NOT NULL, "
         "tipo VARCHAR(20), "
         "numero VARCHAR(15), "
         "FOREIGN KEY (id) REFERENCES nombres(id) "
         "ON DELETE CASCADE "
         "ON UPDATE CASCADE) "
         "ENGINE=InnoDB");
   }

Eliminar una tabla

Análogamente podemos eliminar tablas usando consultas con la sentencia DROP TABLE:

   cout << "Eliminar tabla de nombres" << endl;
   mysql_query(myData, "DROP TABLE agenda.nombres");

Eliminar una base de datos

Lo mismo sirve para eliminar bases de datos, usando la sentencia DROP DATABASE:

   cout << "Eliminar base de datos" << endl;
   mysql_query(myData, "DROP DATABASE agenda");