- Principios de las operaciones de base de datos en MQL5
- Conceptos básicos de SQL
- Estructura de las tablas: tipos de datos y restricciones
- POO (MQL5) e integración SQL: concepto de ORM
- Crear, abrir y cerrar bases de datos
- Ejecutar consultas sin enlace de datos MQL5
- Comprobar si una tabla existe en la base de datos
- Preparar consultas vinculadas: DatabasePrepare
- Borrar y reiniciar consultas preparadas
- Vincular datos a parámetros de consulta: DatabaseBind/Array
- Ejecutar consultas preparadas: DatabaseRead/Bind
- Leer campos por separado: funciones DatabaseColumn
- Ejemplos de operaciones CRUD en SQLite mediante objetos ORM
- Transacciones
- Importar y exportar tablas de bases de datos
- Imprimir tablas y consultas SQL en registros
- Ejemplo de búsqueda de una estrategia de trading mediante SQLite
Ejecutar consultas preparadas: DatabaseRead/Bind
Las consultas preparadas se ejecutan mediante las funciones DatabaseRead y DatabaseReadBind. La primera función extrae los resultados de la base de datos de forma que posteriormente se puedan leer campos individuales de cada registro recibido a su vez como respuesta, y la segunda extrae cada registro coincidente en su totalidad, en forma de estructura.
bool DatabaseRead(int request)
En la primera llamada, después de Database Prepare o DatabaseReset, la función DatabaseRead ejecuta la consulta y establece el puntero interno de resultado de la consulta en el primer registro recuperado (si la consulta espera que se devuelvan registros). Las funciones DatabaseColumn permiten leer los valores de los campos del registro, es decir, las columnas especificadas en la consulta.
En las siguientes llamadas, la función DatabaseRead salta al siguiente registro de los resultados de la consulta hasta llegar al final.
La función devuelve true una vez completada con éxito. El valor false se utiliza como indicador de un error (por ejemplo, la base de datos puede estar bloqueada u ocupada), así como cuando se alcanza normalmente el final de los resultados, por lo que debe analizar el código en _LastError. En concreto, el valor ERR_DATABASE_NO_MORE_DATA (5126) indica que los resultados han finalizado.
¡Atención! Si DatabaseRead se utiliza para ejecutar consultas que no devuelven datos, como INSERT, UPDATE, etc., la función devuelve inmediatamente false y establece el código de error ERR_DATABASE_NO_MORE_DATA si la solicitud se ha realizado correctamente.
El patrón habitual de uso de la función se ilustra con el siguiente pseudocódigo (DatabaseColumn las funciones para los distintos tipos se presentan en la sección siguiente).
int r = DatabasePrepare(db, "SELECT... WHERE...?",
|
Obsérvese que, dado que la consulta (lectura de datos condicionales) sólo se ejecuta una vez (en la primera iteración), no es necesario llamar a DatabaseReset, como hicimos al registrar los datos cambiantes. No obstante, si queremos volver a ejecutar la consulta y «recorrer» los nuevos resultados, sería necesario llamar a DatabaseReset.
bool DatabaseReadBind(int request, void &object)
La función DatabaseReadBind opera de forma similar a DatabaseRead: la primera llamada ejecuta la consulta SQL y, en caso de éxito (hay datos adecuados en el resultado), rellena la estructura object pasada por referencia con los campos del primer registro; las llamadas posteriores continúan moviendo el puntero interno a través de los registros de los resultados de la consulta, rellenando la estructura con los datos del siguiente registro.
La estructura debe tener sólo tipos numéricos y/o cadenas como miembros (no se permiten arrays), no puede heredar de ni contener miembros estáticos de tipos objeto.
El número de campos de la estructura object no debe superar el número de columnas de los resultados de la consulta; de lo contrario, obtendremos un error. El número de columnas puede determinarse dinámicamente mediante la función DatabaseColumnsCount; sin embargo, el llamante suele necesitar «conocer» de antemano la configuración de datos esperada según la solicitud original.
Si el número de campos de la estructura es inferior al número de campos del registro, se realizará una lectura parcial. El resto de los datos pueden obtenerse utilizando las funciones DatabaseColumn correspondientes.
Se supone que los tipos de campo de la estructura coinciden con los tipos de datos de las columnas de resultados. De lo contrario, se realizará una conversión automática implícita, que puede tener consecuencias inesperadas (por ejemplo, una cadena leída en un campo numérico dará 0).
En el caso más sencillo, cuando calculamos un determinado valor total para los registros de la base de datos, por ejemplo, llamando a una función agregada como SUM(column), COUNT(column) o AVERAGE(column), el resultado de la consulta será un único registro con un único campo.
SELECT SUM(swap) FROM trades; |
Dado que la lectura de los resultados está relacionada con las funciones de DatabaseColumn, aplazaremos el desarrollo del ejemplo hasta la siguiente sección, donde éstas se presentan.