====== Bases de Datos ======

===== El lenguaje SQL =====

El lenguaje [[https://es.wikipedia.org/wiki/SQL|SQL]] (Structured Query Language) es el lenguaje que se emplea para comunicarse con las Bases de Datos Relacionales.

Las operaciones más comunes son las que se conoce como DML (Data Manipulation Language), que son las instrucciones que permiten manipular la información, y dentro de ellas, la operación más compleja y utilizada con diferencia, es la instrucción de consulta o visualización de datos. Echaremos un vistazo a estas sentencias para hacer que las aplicaciones Java se puedan comunicar con la Base de Datos para registrar, modificar, eliminar y visualizar información.

Para el momento inicial, el de crear la Base de Datos vacía, que sirva como soporte para los datos, utilizaremos una aplicación como [[https://sqlitebrowser.org|SQLiteBrowser]] que nos permitirá, de una forma visual, crear dichas estructuras.

==== Registrar información ====

La sentencia de inserción ''INSERT'' permite registrar nueva información en la base de datos. Se puede utilizar para registrar una o varias filas de datos en una sola ejecución.

<code sql>
INSERT INTO nombre_tabla [ '('columnas')' ] 
{ VALUES '(' { valores } ')',} | consulta
</code>

Veamos algunos ejemplos:

=== Registra un producto en la base de datos ===

<code sql>
INSERT INTO productos (nombre, precio) VALUES ('Galletas', 10.45)
</code>

=== Registra un par de productos en la base de datos ===
<code sql>
INSERT INTO productos (nombre, precio) VALUES ('Galletas', 10.45), ('Aceite', 5)
</code>

==== Modificar información ====

La sentencia para modificar datos ''UPDATE'' permite modificar uno o varios campos de una o varias filas en una sola ejecución, siempre dependiendo de los campos que se indiquen en la claúsula ''SET'' y las condiciones en la claúsula ''WHERE''. Las primeras indican los valores que serán asignados a una serie de columnas y las segundas indicarán las condiciones que cumplen las filas que se van a modificar.

Hay que tener en cuenta que la claúsula ''WHERE'' es opcional y que, si no es especifica, la operación de modificación afectará a todas las filas de la tabla.

<code sql>
UPDATE nombre_tabla
SET columna = valor [ {, columna = valor} ]
[ WHERE condiciones ]
</code>

Así, en el siguiente ejemplo, si no se especificará en la claúsula ''WHERE'' el producto al que se quiere subir el precio, se subiría el precio a todos los productos registrados en la Base de Datos.

Veamos algunos ejemplos:

=== Modifica el precio de un producto para aumentarlo ===
<code sql>
UPDATE productos
SET precio = precio + 10
WHERE nombre = 'Galletas'
</code>

=== Modifica directamente el precio sobrescribiéndolo ===
<code sql>
UPDATE productos
SET precio = 4.5
WHERE nombre = 'Galletas'
</code>

=== Modifica el precio de varios productos ===
<code sql>
UPDATE productos
SET precio = precio * 1.25
WHERE precio BETWEEN 1 AND 5
</code>

==== Eliminar información ====

La sentencia para eliminar información ''DELETE'' permite eliminar filas completas de la tabla.

Hay que tener en cuenta que, de forma similar a como ocurre con la sentencia ''UPDATE'', la claúsula ''WHERE''  es opcional. En este caso, si no se especifica, una sentencia ''DELETE'' eliminará todas las filas de una tabla.

<code sql>
DELETE FROM nombre_tabla
[ WHERE condiciones ]
</code>

Veamos algunos ejemplos:

=== Elimina el producto que se llama 'Galletas' ===
<code sql>
DELETE FROM productos
WHERE nombre = 'Galletas'
</code>

=== Elimina los productos cuyo precio es menor que 10 ===
<code sql>
DELETE FROM productos
WHERE precio < 10
</code>

=== Elimina los productos 'Galletas' y 'Aceite' ===
<code sql>
DELETE FROM productos
WHERE nombre = 'Galletas' OR nombre = 'Aceite'
</code>

=== Elimina todos los productos ===
<code sql>
DELETE FROM productos
</code>

==== Consultar/Visualizar información ====

La sentencia más compleja y utilizada es ''SELECT'' puesto que es la instrucción que permite visualizar la información de la Base de Datos, combinándola de todas las formas posibles con otros registros de otras tablas para extraer la información y poder aprovecharla lo máximo posible.

Veremos una versión reducida de dicha sentencia, donde podremos especificar que campos visualizar con la claúsula ''SELECT'', y con las claúsulas ''WHERE'' y ''ORDER'' podremos indicar qué filas queremos ver y cómo ordenarlas al visualizarlas en pantalla.

Al igual que ocurre con ''UPDATE'' y ''DELETE'', la claúsula ''WHERE'' es opcional. En caso de que no se especifique, se visualizarán todas las filas de la tabla (mostrándose solamente los campos especificados con la claúsula ''SELECT'').

<code sql>
SELECT columnas
FROM tablas
[ WHERE condiciones ]
[ ORDER BY columnas_a_ordenar [ASC|DESC] ]
</code>

Veamos algunos ejemplos:

=== Muestra el nombre y el precio de todos los productos cuyo precio es mayor que 5. Muestra los resultados ordenados por el nombre del producto en orden ascendente ===
<code sql>
SELECT nombre, precio
FROM productos
WHERE precio > 5
ORDER BY nombre ASC
</code>

=== Muestra el nombre de todos los productos. Muestra los resultados en el orden en que se hayan insertado en la tabla ===
<code sql>
SELECT nombre
FROM productos
</code>

=== Muestra el nombre y precio de los productos 'Galletas' y que el precio sea de 10 euros ===
<code sql>
SELECT nombre, precio
FROM productos
WHERE precio = 10 AND nombre = 'Galletas'
</code>

=== Muestra todos los campos de todos los productos ===
<code sql>
SELECT *
FROM productos
</code>

===== Acceso a una base de datos desde Java y JDBC =====

El acceso a Bases de Datos desde Java se hace utilizando lo que se conoce como el driver de JDBC, que es la API de Java que ofrece toda una serie de Clases y sus métodos para operar con Bases de Datos.

Java define la API para JDBC y tiene que ser cada fabricante quien defina la implementación o driver, que será el fichero que debemos incluir a nuestro proyecto para que éste pueda conectarse a un SGBD (Sistema Gestor de Bases de Datos) concreto y comunicarse con él mediante lenguaje //SQL//.

En nuestro caso, vamos a trabajar con [[https://www.sqlite.org/index.html|SQLite]], que es un SGBD Relacional muy ligero, utilizando en pequeñas aplicaciones (y también presente, de serie, en todos los terminales Android para dar soporte de base de datos a sus aplicaciones y a las desarrolladas por otros). No es un SGBD de alto rendimiento pero es más que suficiente para realizar aplicaciones con Bases de Datos de unos cuantos cientos de MB.

Para comenzar a trabajar con SQLite, lo primero es descargar el [[https://github.com/xerial/sqlite-jdbc|driver JDBC para SQLite]] e incluirlo al proyecto con ayuda del IDE. Lo añadiremos al //Classpath// para que Java pueda utilizar las clases implementadas en él cuando nos conectemos y comuniquemos con la Base de Datos. De forma muy similar a como hace nuestro Sistema Operativo para comunicarse con los periféricos utilizando los Drivers.

==== Conectar con una base de datos SQLite y registrar datos ====

Para conectar con una Base de Datos, en este caso de //SQLite//, sólo hay que cargar el driver e indicar la ubicación de la misma.

El siguiente ejemplo sirve como ejemplo de conexión y de comprobación de que el driver está bien cargado y todo funciona correctamente. La conexión queda establecida sobre el objecto ''conexion'', que servirá como enlace entre la aplicación y la Base de Datos con ayuda del objeto ''PreparedStatement'' que veremos a continuación.

<code java>
. . .
try {
    System.out.println("Prueba de conexión");
    Class.forName("org.sqlite.JDBC");
 
    Connection conexion = null;
    connexion = DriverManager.getConnection("jdbc:sqlite:productos.db");
    System.out.println("Conexión establecida con éxito");

    // Aqui se podría realizar cualquier operación sobre la 
    // Base de Datos (INSERT, UPDATE, DELETE, SELECT)

    if (connexion!= null)
        connexion.close();
    System.out.println("Desconexión correcta");
} catch (ClassNotFoundException cnfe) {
    System.out.println("Error. No se ha podido cargar el driver");
    cnfe.printStackTrace();
} catch (SQLException sqle) {
    System.out.println("Error. Se ha producido algún error al establecer la conexión");
    sqle.printStackTrace();
}
</code>

===== PreparedStatement =====

''PreparedStatement'' es la clase Java de la API de JDBC que se utiliza para ejecutar cualquier sentencia SQL sobre una Base de Datos. Se encarga de ejecutar el código SQL sobre la conexión establecida y de obtener los resultados de dicha ejecución, si son necesarios.

<code java>
. . .
// Se solicitan los datos al usuario
String nombre = . . .;
float precio = . . .;
. . .
// Se introducen en la Base de datos
sql = "INSERT INTO productos (nombre, precio) VALUES (?, ?)";
PreparedStatement sentencia = conexion.prepareStatement(sql);
sentencia.setString(1, nombre);
sentencia.setFloat(2, precio);
sentencia.executeUpdate();
. . .
</code>

==== Registro de información ====

<code java>
. . .
// Se solicitan los datos al usuario
String nombre = . . .;
float precio = . . .;
. . .
// Se introducen en la Base de datos
sql = "INSERT INTO productos (nombre, precio) VALUES (?, ?)";
PreparedStatement sentencia = conexion.prepareStatement(sql);
sentencia.setString(1, nombre);
sentencia.setFloat(2, precio);
// Devuelve el número de filas registradas
int filasAfectadas = sentencia.executeUpdate();
sentencia.close();
. . .
</code>

==== Modificar información ====

<code java>
. . .
// Se solicitan los datos al usuario
String nombre = . . .;
float nuevoPrecio = . . .;
. . .
// Se modifica el campo del producto seleccionado
sql = "UPDATE productos SET precio = ? WHERE nombre = ?";
PreparedStatement sentencia = conexion.prepareStatement(sql);
sentencia.setFloat(1, nuevoPrecio);
sentencia.setString(2, nombre);
// Devuelve el número de filas modificadas
int filasAfectadas = sentencia.executeUpdate();
sentencia.close();
. . .
</code>

==== Eliminar información ====

<code java>
. . .
// Se solicitan los datos al usuario
String nombre = . . .;
. . .
// Se eliminan los productos que cumplen la condición
sql = "DELETE FROM productos WHERE precio = ?";
PreparedStatement sentencia = conexion.prepareStatement(sql);
sentencia.setInt(1, precio);
// Devuelve el número de filas eliminadas
int filasAfectadas = sentencia.executeUpdate();
sentencia.close();
. . .
</code>

==== Consulta de información ====

<code java>
. . .
sql = "SELECT nombre, precio FROM productos";
PreparedStatement sentencia = conexion.prepareStatement(sql);
// Devuelve un cursor con todas las filas
ResultSet resultado = sentencia.executeQuery();
// Se recorren todas las filas una a una
while (resultado.next()) {
    String nombre = resultado.getString(1);
    float precio = resultado.getFloat(2);
    System.out.println("PRODUCTO: " + nombre + ", PRECIO: " + precio);
}
sentencia.close();
. . .
</code>

===== Creación del CRUD =====

El acrónimo [[https://es.wikipedia.org/wiki/CRUD|CRUD]] (Create, Read, Update, Delete) es un acrónimo que hace referencia a las 4 operaciones que se pueden hacer para gestionar datos en una base de datos (''INSERT'', ''SELECT'', ''UPDATE'', ''DELETE''). Es un acrónimo muy utilizado para hacer referencia a la operativa básica de una aplicación de gestión que opera sobre una Base de Datos y realiza esas 4 operaciones sobre los datos que gestiona.

En este caso, consistiría en preparar una aplicación en la que se mostrara al usuario un menú para que pudiera llevar a cabo las 4 operaciones que hemos visto sobre un conjunto de datos.

----

(c) 2019-{{date>%Y}} Santiago Faci