Difference between revisions of "SqlDBHowto/es"

From Lazarus wiki
Jump to navigationJump to search
m (Fixed syntax highlighting)
 
(45 intermediate revisions by 7 users not shown)
Line 9: Line 9:
 
== ¿Cómo conectarse a un servidor de base de datos? ==
 
== ¿Cómo conectarse a un servidor de base de datos? ==
  
   SQLdb no se conecta a un servidor de base de datos directamente sino que utiliza el cliente correspondiente al servidor de base de datos utilizado. SQLdb envía los comandos de la librería de cliente, la cual se conecta a la base de datos y le pasa los comandos. Esto significa que una librería de cliente debe ser instalada en el equipo para establecer una conexión con una base de datos. En Windows un cliente suele ser una .dll, bajo Linux un .so y bajo OS/X una .dylib.
+
   SQLdb no se conecta a un servidor de base de datos directamente sino que utiliza el cliente correspondiente al servidor de base de datos utilizado. SQLdb envía los comandos a la librería de cliente, la cual se conecta a la base de datos y le pasa los comandos. Esto significa que una librería de cliente debe ser instalada en el equipo para establecer una conexión con una base de datos. En Windows un cliente suele ser una .dll, bajo Linux un .so y bajo OS/X una .dylib.
  
   Cuando la librería de cliente se ha instalado correctamente puede conectarse a un servidor de base de datos utilizando un componente TSQLConnection. Hay disponibles componentes TSQLConnection para diferentes servidores de base de datos. Por ejemplo, utiliza TIBConnection para conectarse a una base de datos Firebird/Interbase; TPQConnection para PostgreSQL y TMySQL40Connection, TMySQL41Connection y TMySQL50Connection para bases de datos MySQL con número de versión 4.0, 4,1 y 5,0 respectivamente.
+
   Cuando la librería de cliente se ha instalado correctamente puede conectarse a un servidor de base de datos utilizando un componente TSQLConnection. Hay disponibles componentes TSQLConnection para diferentes servidores de base de datos ( [[SQLdb_Package/es| ver paquete SQLdb]]) - siendo el listado de las disponibles el siguiente:
  
   Las diferencias entre las versiones de cliente MySQL son grandes, en la medida que los clientes y las conexiones no se pueden intercambiar. Con un cliente MySQL versión 4.1 es instalado, tienes que utilizar un TMySQL41Connection. Esto no está relacionado con el servidor MySQL.
+
* Firebird/Interbase: TIBConnection ([[Firebird#Connection| ver enlace]])
 +
* MS-SQL: TMSSQLConnection (disponible desde la versión 2.6.1 de FPC,[[Lazarus_Database_Overview#Lazarus_and_MSSQL.2FSybase|ver enlace]])se puede crear una conexión con el método ''open''. Si
 +
* MySQL v4.0: TMySQL40Connection ([[mysql#SQLDB|ver enlace]])
 +
* MySQL v4.1: TMySQL41Connection ([[mysql#SQLDB|ver enlace]])
 +
* MySQL v5.0: TMySQL50Connection ([[mysql#SQLDB|ver enlace]])
 +
* MySQL v5.1: TMySQL51Connection (disponible desde la versión 2.5.1 de FPC,[[mysql#SQLDB|ver enlace]])
 +
* MySQL v5.5: TMySQL55Connection (disponible desde la versión 2.?.? [[mysql#SQLDB|ver enlace]])
 +
* ODBC: TODBCConnection ([[ODBCConn#TODBCConnection|ver enlace]])
 +
* Oracle: TOracleConnection (Oracle)
 +
* PostgreSQL:  TPQConnection ([[postgresql#SQLDB|ver enlace]])
 +
* Sqlite3: TSQLite3Connection (disponible desde la versión 2.2.2 de FPC, [[SQLite#Built-in_SQLDB|ver enlace]])
 +
* Sybase ASE: TSybaseConnection (disponible desde la versión 2.6.1 de FPC, [[Lazarus_Database_Overview#Lazarus_and_MSSQL.2FSybase|ver enlace]])
  
   Aunque los detalles difieren entre las distintas base de datos, por lo general hay que establecer cuatro propiedades para conectarse a un servidor de base de datos: el nombre de la base de datos, el nombre del servidor o dirección IP, el nombre de usuario y la contraseña. Cuando estas propiedades se establecen, se puede crear una conexión con el método ''open''. Si falla la conexión se lanza una excepción ''EDatabaseError''. Utiliza la propiedad ''connected'' para comprobar si la conexión se ha establecido con el servidor de base de datos. Utiliza el método ''close'' para finalizar la conexión con el servidor.
 
  
<delphi>Program ConectaDB
+
[[File:Conectores_BBDD.png|center]]
 +
 
 +
&nbsp;&nbsp;&nbsp;Las diferencias entre las versiones de cliente MySQL son grandes, en la medida que los clientes y las conexiones no se pueden intercambiar. Con un cliente MySQL versión 4.1 instalado, tienes que utilizar un TMySQL41Connection. ''Si se utiliza la misma versión de librería que de cliente'' probablemente con la 4.1 se podría conectar a ''un servidor'' MySQL 5.0, pero el requerimiento de correspondencia librería-conector a la misma versión es necesario.
 +
 
 +
&nbsp;&nbsp;&nbsp;Aunque los detalles difieren entre las distintas base de datos, por lo general hay que establecer cuatro propiedades para conectarse a un servidor de base de datos:
 +
 
 +
* El nombre del servidor o su dirección IP.
 +
* El nombre de la base de datos.
 +
* El usuario.
 +
* La contraseña.
 +
 
 +
&nbsp;&nbsp;&nbsp;Cuando estas propiedades se establecen, se puede crear una conexión con el método, ''open''. Si
 +
falla la conexión se lanza una excepción ''EDatabaseError''. Utiliza la propiedad ''connected'' para comprobar si la conexión se ha establecido con el servidor de base de datos. Utiliza el método
 +
''close'' para finalizar la conexión con el servidor.
 +
 
 +
<syntaxhighlight lang=pascal>Program ConectaDB
 
   
 
   
 
  var UnaConexion : TSQLConnection;
 
  var UnaConexion : TSQLConnection;
Line 27: Line 52:
 
   UnaConexion.DatabaseName := '/opt/firebird/examples/employee.fdb';
 
   UnaConexion.DatabaseName := '/opt/firebird/examples/employee.fdb';
 
   UnaConexion.UserName := 'sysdba';
 
   UnaConexion.UserName := 'sysdba';
   UnaConexion.Password := 'contranyamaestra';
+
   UnaConexion.Password := 'contraseñamaestra';
 
  end;
 
  end;
 
   
 
   
Line 41: Line 66:
 
   UnaConexion.Close;
 
   UnaConexion.Close;
 
   UnaConexion.Free;
 
   UnaConexion.Free;
  end.</delphi>
+
  end.</syntaxhighlight>
  
&nbsp;&nbsp;&nbsp;Si se produce una excepción, lea atentamente el mensaje de error. Tal vez el servidor de base de datos no está funcionando, el nombre de usuario o la contraseña es incorrecta o el nombre o la dirección IP de base de datos estan escritos de forma incorrecta. Si el mensaje de error indica que la librería cliente no puede ser encontrada, comprueba si el cliente está instalado correctamente. A menudo, el mensaje de error muestra literalmente el nombre del archivo buscado.
+
&nbsp;&nbsp;&nbsp;Si se produce una excepción, lea atentamente el mensaje de error. Tal vez el servidor de base de datos no está funcionando, el nombre de usuario o la contraseña son incorrectos o el nombre o la dirección IP de base de datos estan escritos de forma incorrecta. Si el mensaje de error indica que la librería cliente no puede ser encontrada, comprueba si el cliente está instalado correctamente. A menudo, el mensaje de error muestra literalmente el nombre del archivo buscado.
 +
También es buena idea verificar en la documentación si alguna de estas propiedades está o no soportada para un conector concreto puesto que es posible que en algún caso deban dejarse sin rellenar (no me refiero a la documentación de la BBDD sino de la unidad que conecta).
  
== How to execute direct queries/make a table? ==
+
== ¿Cómo ejecutar consultas directas o crear una tabla? ==
  
Sqldb - the name says it all - only works with database server that make use of SQL. SQL stands for 'Structured Query Language' SQL is a language developed to allow working with relational databases. Virtually every database system has its own dialect, but a large number of SQL statements are the same for all database systems. We can make a difference between SQL statements that return information and statements that do not return information. If you want to use the information that is returned by the SQL statement, you have to use the TSQLQuery component (see [[#How to read data from a table?]].)
+
&nbsp;&nbsp;&nbsp;SQLdb -el nombre lo dice todo- sólo funciona con servidores de base de datos que hacen uso de SQL. SQL significa ''Structured Query Language'' (Lenguaje estructurado de consulta). SQL es un lenguaje desarrollado para permitir trabajar con bases de datos relacionales. Prácticamente todos los sistemas de base de datos tiene su propio dialecto, pero un gran número de sentencias SQL son iguales en todos los sistemas de base de datos. Podemos hacer una diferencia entre las sentencias SQL que devuelven la información y sentencias que no devuelven información. Si desea utilizar la información que devuelve la sentencias SQL, tienes que utilizar el componente ''TSQLQuery'' (ver [[#¿Cómo leer datos de una tabla?|¿Cómo leer datos de una tabla?]]). Si no piensas utilizar la información devuelta por la consulta SQL, entonces también puedes usar el método ''ExecuteDirect'' de un ''TSQLConnection''.
If you do not expect to use the information returned by the SQL statement, then you may also use the 'ExecuteDirect' method of a TSQLConnection.  
 
  
Most database system execute SQL statements within a transaction. If you want changes made within a transaction available in other transactions, or have those changes available even after closing the transaction, then you have to 'commit' the transaction. To support transactions Sqldb contains the TSQLTransaction component. A SQL statement that is executed by Sqldb must always be executed within a transaction. Even if the database system does not support transactions. Also, there are database sustems that do support transaction for which TSQLConnection does not (yet) support transaction. Even then, you must use the TSQLTransaction component.
+
&nbsp;&nbsp;&nbsp;La mayoría de sistemas de base de datos ejecutan las sentencias SQL dentro de una transacción. Si desea que los cambios realizados dentro de una transacción estén disponible en otras transacciones, o disponer de los cambios disponible incluso después de cerrar la transacción, entonces tienes que realizar el ''commit'' de la transacción. Para soportar las operaciones SQLdb tiene el componente TSQLTransaction. Una sentencia SQL que se ejecuta por SQLdb siempre debe ser ejecutada dentro de una transacción. Incluso si el sistema de base de datos no soporta las transacciones. Además, hay sistemas de bases de datos que soportan transacciones para los que TSQLConnection no (todavía) soporta la transacción. Incluso entonces, debes utilizar el componente TSQLTransaction.
  
To use <tt>TSQLConnection.ExecuteDirect</tt> to execute a SQL statement you must specify which 'Transaction' must be used. In turn, to use TSQLTransaction you must specify which 'Connection' must be used.
+
&nbsp;&nbsp;&nbsp;Para utilizar <tt>TSQLConnection.ExecuteDirect</tt> para ejecutar una sentencia SQL debes especificar que ''Transaction'' se debe utilizar. A su vez, al utilizar <tt>TSQLTransaction</tt> debes especificar que ''TSQLConnection'' se debe utilizar.
  
The following example creates a table 'TBLNAMES' with fields 'NAME' and 'ID' and inserts two records. The used SQL statements are not explained. For more information about the SQL statements, their use and syntax, please refer to the database system documentation. The procedure 'CreateConnection' is defined in the code example in [[#How to connect to a database server?]] above.
+
&nbsp;&nbsp;&nbsp;En el ejemplo siguiente se crea una tabla 'TBLNOMBRE' con los campos ''NOMBRE'' y ''nID'' e inserta dos registros. Las instrucciones SQL utilizadas no se explican. Para obtener más información acerca de las instrucciones SQL, su uso y su sintaxis, consulte la documentación del sistema de base de datos. El procedimiento ''CreateConnection'' se define en el ejemplo de código de [[#¿Cómo conectarse a un servidor de base de datos?|¿Cómo conectarse a un servidor de base de datos?]].
  
<delphi>program CreateTable;
+
<syntaxhighlight lang=pascal>program CreateTable;
 
   
 
   
 
  var AConnection : TSQLConnection;
 
  var AConnection : TSQLConnection;
Line 86: Line 111:
 
   AConnection.Free;
 
   AConnection.Free;
 
   ATransaction.Free;
 
   ATransaction.Free;
  end.</delphi>
+
  end.</syntaxhighlight>
  
== How to read data from a table? ==
+
== ¿Cómo leer datos de una tabla? ==
  
Use the TSQLQuery component to read data from a table. A TSQLQuery component must be connected to a TSQLConnection component and a TSQLTransaction component to do its work. Setting the TSQLConnection and TSQLTransaction is discussed in [[#How to connect to a database server? ]] and [[#How to execute direct queries/make a table?]].  
+
&nbsp;&nbsp;&nbsp;Utiliza el componente TSQLQuery para leer datos de una tabla. Un componente ''TSQLQuery'' debe estar enlazado a un componente ''TSQLConnection'' y a un componente ''TSQLTransaction'' para hacer su trabajo. El ajuste de ''TSQLConnection'' y de ''TSQLTransaction'' se discute en [[#¿Cómo conectarse a un servidor de base de datos?|¿Cómo conectarse a un servidor de base de datos?]] y en [[#¿Cómo ejecutar consultas directas o crear una tabla?|¿Cómo ejecutar consultas directas o crear una tabla?]].
  
When the TSQLConnection, TSQLTransaction and TSQLQuery are connected, then TSQLQuery needs more settings. TSQLQuery has a 'SQL' property containing a TStrings object. The 'SQL' property contains a SQL statement that must be executed. If all data from a table must be read, then set the 'SQL' property to 'SELECT * FROM tablename;' Use 'open' to read the table from the server and put the data in the TSQLQuery dataset. The data can be access through TSQLQuery until the query is closed using 'close'.
+
&nbsp;&nbsp;&nbsp;Cuando ''TSQLConnection'', ''TSQLTransaction'' y ''TSQLQuery'' están conectados, entonces ''TSQLQuery'' necesita más ajustes. TSQLQuery tiene una propiedad ''SQL'' que contiene un objeto ''TStrings''. La propiedad 'SQL' contiene la sentencia SQL que debe ejecutarse. Si todos los datos de una tabla debe ser leídos establece la propiedad ''SQL'' a ''SELECT * FROM nombretabla;''. Utiliza ''open'' para leer la tabla desde el servidor y poner los datos en el conjunto de datos ''TSQLQuery''. Los datos se pueden acceder a través de ''TSQLQuery'' hasta que la consulta se cierra con ''close''.
TSQLQuery is a subclass of TDataset. TDataset has a 'Fields' collection that contains all columns of the table. The TDataset also keeps track of the current record. Use 'First', 'Next', 'Prior' and 'Last' to change the current record. 'Bof' returns 'True' if the first record is reached, and 'Eof' returns 'True' if the last record is reached. To read the value of a field in the current record, first find the right 'TField' object and then use 'AsString', 'AsInteger', etc.
 
  
 +
&nbsp;&nbsp;&nbsp;''TSQLQuery'' es una subclase de ''TDataset''. ''TDataset'' tiene una colección ''Fields'' que contiene todas las columnas de la tabla. El ''TDataset'' también mantiene una marca del registro actual. Utiliza ''First'', ''Next'', ''Prior'' y ''Last'' para cambiar el registro actual. ''Bof'' devuelve  ''true'' (verdadero) si se llegó al primer registro, y ''Eof'' devuelve ''true'' si se llegó al último registro. Para leer el valor de un campo en el registro actual, en primer lugar hayamos el objeto ''TField'' adecuado y luego usar 'AsString', 'AsInteger', etc.
  
Below is an example that displays all values of the table as it was made in [[#How to execute direct queries/make a table?]] above.
+
&nbsp;&nbsp;&nbsp;A continuación se muestra un ejemplo que muestra todos los valores de la tabla como se hizo en [[#¿Cómo ejecutar consultas directas o crear una tabla?|¿Cómo ejecutar consultas directas o crear una tabla?]].
  
<delphi>Program ShowData;
+
<syntaxhighlight lang=pascal>Program ShowData;
 
   
 
   
 
  var AConnection : TSQLConnection;
 
  var AConnection : TSQLConnection;
Line 132: Line 157:
 
   ATransaction.Free;
 
   ATransaction.Free;
 
   AConnection.Free;
 
   AConnection.Free;
  end.</delphi>
+
  end.</syntaxhighlight>
 +
 
 +
&nbsp;&nbsp;&nbsp;(El código anterior, por supuesto, no está terminado, se echa de menos bloques ''try ... finally''. Sin embargo, el código anterior tiene la intención de mostrar el código para base de datos y por lo tanto los toques finales son dejados de lado.) Ten en cuenta que ''TSQLTransaction.StartTransaction'' no se utiliza. Esto no es necesario. Cuando ''TSQLQuery'' se abre, la instrucción SQL se ejecuta y si no hay ninguna transacción está disponible, esta se inicia automáticamente. El programador no necesita iniciar la transacción explícitamente. Lo mismo se aplica para la conexión gestionada por ''TSQLConnection''. La conexión se abre según sea necesario, la línea ''Aconnection.Open'' no es realmente necesaria.
  
(The code above of course is not quite finished, it misses 'try...finally' blocks. However, the above code intends to show the database code and thus the finishing touches are left out.) Please note that 'TSQLTransaction.StartTransaction' is not used. This is not necessary. When TSQLQuery is opened, the SQL statement is executed and if no transaction is available then a transaction is automatically started. The programmer does not need to start the transaction explicitly. The same applies for the connection maintained by TSQLConnection. The connection is opened as needed, the line 'Aconnection.Open' is not really required.
+
&nbsp;&nbsp;&nbsp;Si se destruye un ''TSQLTransaction'', un ''rollback'' (deshacer) automático será ejecutado. Los posibles cambios a los datos contenidos en la transacción se perderán.
If a TSQLTransaction is destroyed, an automatic 'rollback' will be executed. Possible changes to data contained in the transaction will be lost.
 
  
=== Why does TSQLQuery.RecordCount always return 10? ===
+
=== ¿Por qué ''TSQLQuery.RecordCount'' siempre devuelve 10? ===
  
To count the records in a datase, use '.RecordCount'. However, notice that '.RecordCount' shows the number of records that is already loaded from the server. Sqldb does not read all records when opening TSQLQuery by default, only the first 10. Only when the eleventh record is accessed then the next set of 10 records is loaded. Using '.Last' all records will be loaded.  
+
&nbsp;&nbsp;&nbsp;Para contar los registros de un ''dataset'', usaremos ''RecordCount''. Sin embargo, observa que ''RecordCount'' muestra el número de registros que se ha cargado desde el servidor. SQLdb no lee todos los registros al abrir un ''TSQLQuery'' de forma predeterminada, sólo los 10 primeros. Sólo cuando se accede al undécimo registro entonces el siguiente conjunto de 10 registros se carga. Usando ''.Last'' todos los registros se cargarán.
  
When you want to know the real number of records on the server you can first call '.Last' and then call '.RecordCount'. An alternative is available. The number of records returned by the server is set by the '.PacketRecords' property. The default value is 10, if you make it -1 then all records will be loaded at once.
+
&nbsp;&nbsp;&nbsp;Si desea conocer el número real de registros en el servidor hay que llamar primero '.Last' y luego llamar a ''.RecordCount''. Hay una alternativa disponible. El número de registros devueltos por el servidor está determinado por el valor de la propiedad ''PacketRecords''. El valor por defecto es 10, si se pone a -1 entonces todos los registros serán cargados a la vez.
  
 
=== Lazarus ===
 
=== Lazarus ===
  
Lazarus has various components to show data from a TDataset on a form. Instead of a While-loop and Writeln statements as use avobe, you can use the components to show the data in a table. Place the right TSQLConnection, TSQLTransaction and TSQLQuery components on a form, then connect them and set them properly. In addition you will need a TDatasource, set to 'TDatasource.Dataset' property to the TSQLQuery component you used. ('''Note''' do not set the 'TSQLQuery.Datasource' property to the TDatasource compnent you used. The 'TSQLQuery.Datasource' property is only used only in master-detial tables.) Subsequently you may put a TDBGrid onto the form and set the 'Datasource' property of the grid to the TDatasource component you added before.
+
&nbsp;&nbsp;&nbsp;Lazarus tiene diversos componentes para mostrar datos de un ''TDataset'' en un formulario. En lugar de un bucle ''while'' y declaraciones ''Writeln'' usados en el ejemplo, puedes utilizar componentes para mostrar los datos de una tabla. Coloca los adecuados componentes ''TSQLConnection'', ''TSQLTransaction'' y ''TSQLQuery'' en un formulario, a continuación, se conectan y configuran correctamente. Además se necesita un ''TDataSource'', ajusta la propiedad ''TDatasource.Dataset'' al componente ''TSQLQuery'' utilizado. ('''Nota''' no establecer la propiedad ''TSQLQuery.Datasource'' al componente ''TDataSource''. La propiedad ''TSQLQuery.Datasource'' se utiliza solamente en tablas maestro/detalle) A continuación puedes poner un ''TDBGrid'' en el formulario y establece la propiedad ''Datasource'' de la rejill (''grid'') al componente TDataSource agregado antes.
  
To see if it all works, set the 'Connected' property of the TSQLConnection to 'True' in the Lazarus IDE. The IDE will try to connect to the database server immediately. If this works you can set the 'TSQLQuery.Active' property to 'True'. If everything is right, you will see - within the IDE - all data from the table immediately on the screen.
+
&nbsp;&nbsp;&nbsp;Para ver si funciona todo, establece la propiedad ''Connected'' del ''TSQLConnection'' a ''True'' en el IDE de Lazarus. El IDE intenta conectar con el servidor de base de datos inmediatamente. Si funciona se puede establecer la propiedad ''TSQLQuery.Active'' a 'True'. Si todo está correcto, podrás ver -en el IDE- todos los datos de la tabla inmediatamente en la pantalla.
  
== How to change data in a table? ==
+
== ¿Cómo cambiar los datos en una tabla? ==
  
To change the data in a record, the TDataset (from which TSQLQuery is derived) must be set to edit mode. To enter edit mode call the '.Edit', '.Insert' or '.Append' methods. Use the '.Edit' method to change the current record. Use '.Insert' to insert a new record before the current record. Use '.Append' to insert a new record at the end of the table. In edit mode you can change field values through the 'Fields' property. Use 'Post' to validate the new data, if the data is valid then the edit mode is left. If you move to another record - for example by using '.Next' - and the dataset is in edit mode, then first '.Post' is called. Use '.Cancel' to discard all changes you made since the last '.Post' call and leave the edit mode.
+
&nbsp;&nbsp;&nbsp;Para cambiar datos en un registro, el ''TDataset'' (del que se deriva ''TSQLQuery'') debe ponerse en modo de edición. Para activar el modo de edición podemos llamar a los métodos ''.Edit'', ''. Insert''o ''.Append''. Utiliza el método ''.Edita'' para modificar el registro actual. Utiliza ''.Insert'' para crear un nuevo registro antes del registro actual. Utiliza ''.Append'' paara añadir un nuevo registro al final de la tabla. En modo edición puedes cambiar el valor de los campos a través de la propiedad ''Fields''. Utiliza ''Post'' para validar los nuevos datos, si los datos son válidos entonces se abandona el modo de edición. Si se cambia a un nuevo registro -por ejemplo, utilizando ''.Next''- y el conjunto de datos está en modo de edición, se llamará a ''.Post'' antes. Utiliza  ''.Cancel'' para descartar todos los cambios realizados desde la última llamada a ''.Post'' y termina el modo de edición.
  
<delphi>Query.Edit;
+
<syntaxhighlight lang=pascal> Query.Edit;
  Query.FieldByName('NAME').AsString := 'Edited name';
+
  Consulta.FieldByName('NOMBRE').AsString := 'Nombre editado';
  Query.Post;</delphi>
+
  Consulta.Post;</syntaxhighlight>
  
The above is not the complete story yet. TSQLQuery is derived from TBufDataset which makes use of buffered updates. Buffered update mean that after you called 'Post' the changes in the dataset are visible immediately, but they are not sent to the database server. What does happen is that the changes are maintained in a change log. When the '.ApplyUpdates' method is called, then all changes in the change log are sent to the databse. Only then the database server knows all the changes. The changes are sent to the server within a transaction of TSQLTransaction. Make sure to properly set the transaction before 'ApplyUpdates'. After applying the updates, a commit must be executed to publish or store the changes.
 
  
The below is an example of changing the data in a table, sending the changes to the server and comitting the transaction.
+
&nbsp;&nbsp;&nbsp;Lo anterior no es la historia completa todavía. ''TSQLQuery'' se deriva de ''TBufDataset'' que hace uso de actualizaciones en un ''buffer''. Actualización en ''buffer'' significa que después de llamado ''Post'' los cambios en el conjunto de datos son visibles de inmediato, pero no se envían al servidor de base de datos. Lo que sucede es que los cambios se mantienen en un registro de cambios. Cuando se llama al método ''.ApplyUpdates''  todos los cambios en el registro de cambios se envían al servidor de base de datos. Sólo entonces el servidor de base de datos conoce todos los cambios. Los cambios se envían al servidor en una transacción de ''TSQLTransaction''. Asegúrese de establecer correctamente la transacción antes de ''ApplyUpdates''. Después de aplicar las actualizaciones, se debe ejecutar ''commit'' para publicar o guardar los cambios.
  
<delphi>Program EditData;
+
 
 +
&nbsp;&nbsp;&nbsp;El siguiente es un ejemplo de la cambio de datos en una tabla, envío de los cambios al servidor y confirmación de la transacción.
 +
 
 +
<syntaxhighlight lang=pascal> Program EditarDatos;
 
   
 
   
  var AConnection : TSQLConnection;
+
  var unaConexion : TSQLConnection;
     ATransaction : TSQLTransaction;
+
     unaTransaccion : TSQLTransaction;
     Query : TSQLQuery;
+
     Consulta : TSQLQuery;
 
   
 
   
 
  begin
 
  begin
   CreateConnection;
+
   CrearConexion;
   CreateTransaction;
+
   CrearTransaccion;
   AConnection.Transaction := ATransaction;
+
   unaConexion.Transaction := unaTransaccion;
   Query := GetQuery;
+
   Consulta := GetQuery;
   Query.SQL.Text := 'select * from tblNames';
+
   Consulta.SQL.Text := 'select * from tblNombres';
   Query.Open;
+
   Consulta.Open;
   Query.Edit;
+
   Consulta.Edit;
   Query.FieldByName('NAME').AsString := 'Edited name';
+
   Consulta.FieldByName('NOMBRE').AsString := 'Nombre editado';
   Query.Post;
+
   Consulta.Post;
   Query.UpdateMode := upWhereAll;
+
   Consulta.UpdateMode := upWhereAll;
   Query.ApplyUpdates;
+
   Consulta.ApplyUpdates;
 
   AConnection.Transaction.Commit;
 
   AConnection.Transaction.Commit;
   Query.Free;
+
   Consulta.Free;
   ATransaction.Free;
+
   unaTransaccion.Free;
   AConnection.Free;
+
   unaConexion.Free;
  end.</delphi>
+
  end.</syntaxhighlight>
 +
 
 +
 
 +
&nbsp;&nbsp;&nbsp;Para una discusión de ''UpdateMode'' sigue leyendo.
  
For a discussion of 'UpdateMode' continue reading.
+
== ¿Cómo SQLdb envia los cambios al servidor de base de datos? ==
  
== How does Sqldb send the changes to the database server? ==
+
&nbsp;&nbsp;&nbsp;En el ejemplo de código de [[#¿Cómo cambiar los datos en una tabla?|¿Cómo cambiar los datos en una tabla?]], se encuentra la línea.
 +
<syntaxhighlight lang=pascal> Consulta.UpdateMode := upWhereAll;</syntaxhighlight>
 +
sin ninguna explicación de lo que hace. La mejor manera de averiguar lo que esa línea hace es quitarla. Si se omite la orden y se sigue esta guía con precisión, se recibirá el siguiente mensaje de error:
 +
<syntaxhighlight lang=pascal> No update query specified and failed to generate one. (No fields for inclusion in where statement found)</syntaxhighlight>
 +
&nbsp;&nbsp;&nbsp;Para entender lo que salió mal, debes entender cómo los cambios se envían al servidor de base de datos. La única manera de obtener datos en un servidor SQL es mediante la ejecución de consultas SQL. SQL tiene tres tipos de consultas para tres maneras diferentes de manipular un registro. Para crear un nuevo registro, cambiar o eliminar un registro las sentencias ''insert'', ''update'' y ''delete'' se ejecutan, respectivamente. Una sentencia de actualización (''update'') puede ser así:
  
In the code example in [[#How to change data in a table?]], you will find the line
+
<syntaxhighlight lang=pascal> update TBLNAMES set NAME='Edited name' where ID=1;</syntaxhighlight>
<delphi> Query.UpdateMode := upWhereAll;</delphi>
+
&nbsp;&nbsp;&nbsp;Para enviar un cambio al servidor de base de datos, SQLdb debe crear una consulta de actualización. Para crearla consulta, se necesitan tres cosas:
without explanation of what it does. The best way to find out what that line does is to leave it out. If you leave out the statement and the followed this howto precisely, then you will receive the following error message:
+
; El nombre de la tabla: El nombre de la tabla se obtiene de analizar la consulta de selección, aunque esto no siempre funciona.  
<delphi> No update query specified and failed to generate one. (No fields for inclusion in where statement found)</delphi>
+
; Una clásula <tt>UPDATE</tt> o <tt>INSERT</tt>: Estas contienen los campos que se deben cambiar.
To understand what went wrong, you must understand how changes are sent to the database server. The only way to get data in a SQL server is by executing SQL queries. SQL has three types of queries for three different ways of manupulating a record. To create a new record, change or delete a record insert, update and delete statements are executed respectively. An update statement may be as follows:
+
; Una clásula <tt>WHERE</tt>: Esta contiene los campos que determinan qué registros se deben cambiar.
<delphi> update TBLNAMES set NAME='Edited name' where ID=1;</delphi>
 
To send a change to the database server, Sqldb must assemble an update query. To assemble the query, three things are needed:
 
; The name of the table : The table name is retrieved from parsing the select query, although this doesn't always work.  
 
; <tt>UPDATE</tt> or <tt>INSERT</tt> clause : These contain the fields that must be changed.
 
; <tt>WHERE</tt> clause : This contains the fields that determine which records should be changed.
 
  
Every field (each ''TField'' in ''Fields'') has a ProviderFlags property. Only fields with '''pfInUpdate''' in ''ProviderFlags'' will be used in the update or insert cluase of a query. By default all fields have ''pfInUpdate'' set in their ''ProviderFlags'' property.
+
&nbsp;&nbsp;&nbsp;Todos los campos (cada ''TField'' en ''Fields'') tiene una propiedad ''ProviderFlags''. Sólo los campos con ''pfInUpdate'' en ''ProviderFlags'' se utilizarán en la clásula de actualización o inserción de la consulta. Por defecto todos los campos tienen ''pfInUpdate'' puesto en su propiedad ''ProviderFlags''.
  
Which fields are used in the <tt>WHERE</tt> clause depends on the ''UpdateMode'' property of the query and the ''ProviderFlags'' property of the fields. Fields with ''pfInkey'' in their ''ProviderFlags'' are always used in the <tt>WHERE</tt> clause. A field will have the ''pfInKey'' flag set automatically if the field is part of the primary key of the table and 'TSQLQuery.UsePrimaryKeyAsKey' returns 'True'.
+
&nbsp;&nbsp;&nbsp;Qué campos se utilizan en la clásula <tt>WHERE</tt> depende de la propiedad ''UpdateMode'' de la consulta y la propiedad ''ProviderFlags'' de los campos. Los campos con ''pfInkey'' en su ''ProviderFlags'' siempre se utilizan en la clásula<tt>WHERE</tt>. Un campo tendrá el indicador ''pfInKey'' establecido de forma automática si el campo es parte de la clave principal de la tabla y ''TSQLQuery.UsePrimaryKeyAsKey'' devuelve ''True''.
  
The default value for ''UpdateMode'' of the query is ''upWhereKeyOnly''. In this update mode only fields with ''pfInkey'' in their ''ProviderFlags'' property are used in the <tt>WHERE</tt> clause. If none of the fields have their ''pfInKey'' flag set, then no fields are available for the <tt>WHERE</tt> clause and the error message from the beginning of this section will be returned. You can solve the issue by:
+
&nbsp;&nbsp;&nbsp;El valor predeterminado para ''UpdateMode'' de la consulta es ''upWhereKeyOnly''. En este modo se actualizan los campos sólo con ''pfInkey'' en su propiedad ''ProviderFlags'' 'se utilizan en la clásula <tt>WHERE</tt>. Si ninguno de los campos tienen el  indicador ''pfInKey'' establecido, entonces no hay campos disponibles para la cláusula <tt>WHERE </tt> y el mensaje de error del principio de esta sección será devuelto. Puede resolver el problema así:
  
*<tt> Adding a primary key to the table and set ''TSQLQuery.UsePrimaryKeyAsKey'' to 'True', or</tt>
+
*<tt> Añadir una clave principal a la tabla y poner ''TSQLQuery.UsePrimaryKeyAsKey'' a 'True', o</tt>
*<tt> Setting the ''pfInkey'' flag for one or more fields in code.</tt>
+
*<tt> Poner el indicador ''pfInkey'' para uno o varios campos en el código.</tt>
  
The '''UpdateMode''' property knows two more possible values. 'upWhereAll' can be used to add all fields with the 'pfInWhere' flag set to the <tt>WHERE</tt> clause. By default all fields have this flag set. 'upWhereChanged' can be used to add only those fields that have the 'pfInWhere' flag set '''and''' that are changed in the current record.
+
&nbsp;&nbsp;&nbsp;La propiedad ''UpdateMode'' puede tener dos posible valores más. ''UpWhereAll'' puede usarse para agregar todos los campos con el indicador ''pfInWhere'' establecido para la cláusula <tt>WHERE</tt>. Por defecto todos los campos tienen este indicador establecido. ''UpWhereChanged'' puede usarse para agregar sólo los campos que tienen el indicador ''pfInWhere'' establecido '''y''' que se han modificado del registro actual.
  
== How to execute a query using TSQLQuery? ==
+
== ¿Cómo ejecutar una consulta mediante TSQLQuery? ==
  
Next to statements that return a dataset (see [[#How to read data from a table?]]) SQL has statements that do not return data. For example <tt>INSERT</tt>, <tt>UPDATE</tt> and <tt>DELETE</tt> statements do not return data. These statements can be executed using ''[[#How to execute direct queries/make a table?|TSQLConnection.ExecuteDirect]]'', but TSQLWuery can alos be used. If you do not expect return datause ''TSQLQuery.ExecSQL'' instead of ''TSQLQuery.Open''. Use ''TSQLQuery.Open'' to open the dataset returned by the SQL statement.  
+
&nbsp;&nbsp;&nbsp;Junto a las declaraciones que devuelven un conjunto de datos (ver [[#¿Cómo leer datos de una tabla?|¿Cómo leer datos de una tabla?]]) SQL tiene sentencias que no devuelven datos. Por ejemplo <tt>INSERT</tt>, <tt>UPDATE</tt> y <tt>DELETE</tt> no devuelven datos. Estas sentencias se pueden ejecutar mediante ''[[#¿Cómo_ejecutar_consultas_directas_o_crear_una_tabla?|TSQLConnection.ExecuteDirect ]]'', pero ''TSQLQuery'' puede utilizarse también. Si no esperas devolver datos utiliza ''TSQLQuery.ExecSQL'' en lugar de ''TSQLQuery.Open''. Utiliza ''TSQLQuery.Ope''n para abrir el conjunto de datos devuelto por la consulta SQL.
  
The following procedure creates a table and inserts two records using TSQLQuery.
+
&nbsp;&nbsp;&nbsp;El siguiente procedimiento crea una tabla y se insertan dos registros utilizando ''TSQLQuery''.
  
<delphi>procedure CreateTable;
+
<syntaxhighlight lang=pascal>procedure CrearTabla;
 
    
 
    
   var Query : TSQLQuery;
+
   var Consulta : TSQLConsulta;
 
    
 
    
 
   begin
 
   begin
     Query := GetQuery;
+
     Consulta := GetConsulta;
     Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
+
     Consulta.SQL.Text := 'create table TBLNOMBRES (ID integer, NOMBRE varchar(40));';
     Query.ExecSQL;
+
     Consulta.ExecSQL;
 
    
 
    
     Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (1,'Name1');';
+
     Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (1,'Nombre1');';
     Query.ExecSQL;
+
     Consulta.ExecSQL;
 
    
 
    
     Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (2,'Name2');';
+
     Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (2,'Nombre2');';
     Query.ExecSQL;
+
     Consulta.ExecSQL;
 
    
 
    
     Query.Close;
+
     Consulta.Close;
     Query.Free;
+
     Consulta.Free;
   end;</delphi>
+
   end;</syntaxhighlight>
 +
 
 +
== ¿Cómo utilizar parámetros en una consulta? ==
 +
 
 +
&nbsp;&nbsp;&nbsp;En el código de ejemplo de [[#¿Cómo ejecutar una consulta mediante TSQLQuery?|¿Cómo ejecutar una consulta mediante TSQLQuery?]] la misma consulta se utiliza dos veces, sólo difieren en los valores que se insertan. Una manera mejor de hacerlo es mediante el uso de parámetros en la consulta.
 +
 
 +
&nbsp;&nbsp;&nbsp;La sintaxis de los parámetros en las consultas es diferente en cada sistema de base de datos, pero las diferencias las maneja ''TSQLQuery''. Coloca de nuevo los valores en la consulta con dos puntos precediendo al nombre del parámetro que desea utilizar. Por ejemplo:
  
== How to use parameters in a query? ==
+
<syntaxhighlight lang=pascal> Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (:ID,:NOMBRE);';</syntaxhighlight>
 +
&nbsp;&nbsp;&nbsp;Esta consulta crea dos parámetros: 'ID' y 'NOMBRE'. Para determinar los parámetros, la consulta se analiza en el momento en que se asigna o modifica el texto de ''TSQLQuery.SQL''. Todos los parámetros existentes se eliminarán y los nuevos parámetros se añadirán a la propiedad ''TSQLQuery.Params''. Asignar un valor a un parámetro es similar a asignar un valor a un campo en el conjunto de datos:
  
In the code example of [[#How to execute a query using TSQLQuery?]] the same query is used twice, only the values to be inserted differ. A better way to do this is by using parameters in the query.  
+
<syntaxhighlight lang=pascal> Query.Params.ParamByName('Nombre').AsString := 'Name1';</syntaxhighlight>
  
The syntax of parameters in queries is different per database system, but the differences are handles by TSQLQuery. Replace the values in the query with a colon followed by the name of the parameter you want to use. For example:
+
&nbsp;&nbsp;&nbsp;No se puede saber desde consulta qué tipo de datos deben ser almacenados en el parámetro. El tipo de datos del parámetro se determina en el momento en que un valor se asigna al parámetro. Al asignar un valor utilizando ''. AsString'', el parámetro se asigna al tipo de datos ''ftString''. Puede determinar el tipo de datos directamente mediante el establecimiento de la propiedad ''DataType''. Si un tipo de datos incorrecto se asigna al parámetro, entonces los problemas se producirán durante la apertura o ejecución de la consulta.
<delphi>Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';</delphi>
 
This query will create two parameters: 'ID' and 'NAME'.
 
To determine the parameters, the query is parsed at the moment the text of ''TSQLQuery.SQL'' is assinged or changed. All existing parameters will be removed and the new parameters will be added to the 'TSQLQuery.Params' property. Assigning a value to a parameter is similar to assigning a value to a field in teh dataset:
 
<delphi>Query.Params.ParamByName('Name').AsString := 'Name1';</delphi>
 
You can't tell from the query what kind of data must be stored in the parameter. The data type of the parameter is determined at the moment a value is first assigned to the parameter. By assigning a value using '.AsString', the parameter is assigned the data type 'ftString'. You can determine the data type directly by setting the 'DataType' property. If an incorrect datatype is assigned to the parameter, then problems will occur during opening or executing the query.
 
  
The following example creates th same table as the previous example, but now parameters are used:
+
&nbsp;&nbsp;&nbsp;En el ejemplo siguiente se crea la misma tabla del ejemplo anterior, pero ahora se utilizan parámetros:
  
<delphi>procedure CreateTableUsingParameters;
+
<syntaxhighlight lang=pascal> procedure CrearTablaUsandoParametros;
 
    
 
    
   var Query : TSQLQuery;
+
   var Consulta : TSQLQuery;
 
    
 
    
 
   begin
 
   begin
     Query := GetQuery;
+
     Consulta := GetQuery;
     Query.SQL.Text := 'create table TBLNAMES (ID integer, NAME varchar(40));';
+
     Consulta.SQL.Text := 'create table TBLNOMBRES (ID integer, NOMBRE varchar(40));';
     Query.ExecSQL;
+
     Consulta.ExecSQL;
 
    
 
    
     Query.SQL.Text := 'insert into TBLNAMES (ID,NAME) values (:ID,:NAME);';
+
     Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (:ID,:NOMBRE);';
 
    
 
    
     Query.Params.ParamByName('ID').AsInteger := 1;
+
     Consulta.Params.ParamByName('ID').AsInteger := 1;
     Query.Params.ParamByName('ID').AsString := 'Name1';
+
     Consulta.Params.ParamByName('NOMBRE').AsString := 'Nombre1';
     Query.ExecSQL;
+
     Consulta.ExecSQL;
 
    
 
    
     Query.Params.ParamByName('ID').AsInteger := 2;
+
     Consulta.Params.ParamByName('ID').AsInteger := 2;
     Query.Params.ParamByName('ID').AsString := 'Name2;
+
     Consulta.Params.ParamByName('NOMBRE').AsString := 'Nombre2';
     Query.ExecSQL;
+
     Consulta.ExecSQL;
 
    
 
    
     Query.Close;
+
     Consulta.Close;
     Query.Free;
+
     Consulta.Free;
   end;</delphi>
+
   end;</syntaxhighlight>
 +
 
 +
&nbsp;&nbsp;&nbsp;Observa que este ejemplo requiere más código que el ejemplo sin parámetros. Entonces, ¿qué es el ventaja de la utilización de parámetros? La velocidad es una de las razones. El ejemplo con parámetros es más rápido porque la consulta se analiza solamente una vez. TSQLQuery sólo analiza la consulta una vez, pero también el servidor de base de datos analiza la consulta una sola vez. La mayoría de los sistemas de base de datos soportan parámetros. Siempre que una consulta se utiliza más de una vez con diferentes valores para el parámetro cada vez, entonces el servidor de base de datos sólo analiza la consulta y los planes de la consulta una sola vez haciendo la ejecución considerablemente más rápida.
 +
 
 +
&nbsp;&nbsp;&nbsp;Utiliza ''TSQLQuery.Prepare'' para determinar el momento en que se analiza y se planifica la consulta por el servidor de base de datos. Utiliza ''TSQLQuery.UnPrepare'' para asegurarse de que la consulta se analiza y se planifica cada vez por el servidor de datos.
 +
 
 +
&nbsp;&nbsp;&nbsp;Otra razón para usar sentencias preparadas es la prevención de [http://en.wikipedia.org/wiki/SQL_injection inyección de SQL], pero en algunos casos únicamente simplifica la codificación.
 +
 
 +
== Solución de problemas:==
 +
=== Registro de sucesos de ''TSQLConnection'' ===
 +
 
 +
&nbsp;&nbsp;&nbsp;Puedes hacer que TSQLConnection registre lo que está haciendo. Esto puede ser útil para ver exactamente lo que tu programa envía a la base de datos, para depurar los propios componentes de base de datos y también para optimizar las consultas.
 +
 
 +
&nbsp;&nbsp;&nbsp;Nota: si utilizas comandos preparados o consultas parametrizadas (ver la sección anterior), los parámetros son a menudo enviados en binario por el descendiente de ''TSQLConnection''  (por ejemplo, ''TIBConnection''), por lo que no se puedes simplemente copiar o pegar el código SQL registrado en una herramienta de consulta de la base de datos.
 +
 
 +
&nbsp;&nbsp;&nbsp;En cualquier caso, el registro de la activad de la conexión puede dar una gran cantidad de información sobre lo que está haciendo tu programa.
 +
 
 +
&nbsp;&nbsp;&nbsp;Otras alternativas son:
 +
# utilizar el depurador para recorrer el código base de datos si se ha construido el FPC o Lazarus con la depuración habilitada.
 +
# si utilizas controladores ODBC (al menos en Windows) puedes habilitar la salida ''tracelog'' en el panel de control de ODBC.
 +
# muchas bases de datos permiten controlar todas las ordennes que se le envían desde una determinada dirección IP o conexión.
 +
 
 +
&nbsp;&nbsp;&nbsp;Para utilizar el registro de actividad de ''TSQLConnection'', se requieren dos cosas:
 +
# indicar qué tipos de eventos del ''TSQLConnection'' deben registrarse
 +
# apuntar ''TSQLConnection'' a la función que recibe los eventos y los procesa (los registra en un archivo, que se imprima en la pantalla, etc)
 +
 
 +
&nbsp;&nbsp;&nbsp;Esta función debe ser de tipo ''TDBLogNotifyEvent'' (ver sqldb.pp), por lo que seguirá este patrón:
 +
 
 +
<syntaxhighlight lang=pascal> TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;</syntaxhighlight>
  
Notice that this example requires more code than the example without the parameters. Then what is the use of using parameters? Speed is one of the reasons. The example with parameters is faster because the query is parsed only once. TSQLQuery only parses the query once, but also the database server parses the query only once. Most database systems support parameters. Whenever a query is used more than once with different values for the parameter each time, then the database server only parses the query and plans the query only once making execution considerably faster.
+
&nbsp;&nbsp;&nbsp;Este fragmento de código puede ilustrar esto:
Use 'TSQLQuery.Prepare' to determine the moment the query is parsed and planned by the database server. Use 'TSQLQuery.UnPrepare' to make sure the query is parsed and planned every time by the data server.
+
<syntaxhighlight lang=pascal> uses
 +
...//
 +
TSQLConnection, //o un objeto heredero tal que TIBConnection, TMSSQLConnection
 +
...//
 +
var
 +
type
 +
  TMyApplication = class(TCustomApplication); //esta es nuestra aplicación, la que utiliza la conexión
 +
...//
 +
  private
 +
    // Este ejemplo guarda el registro en un stringlist:
 +
    FConnectionLog: TStringList;
 +
...//
 +
  protected
 +
    // Este procedimiento recibe los eventos que registra la conexión:
 +
    procedure GetLogEvent(Sender: TSQLConnection; EventType: TDBEventType; Const Msg : String);
 +
...
 +
  procedure TMyApplication.GetLogEvent(Sender: TSQLConnection;
 +
    EventType: TDBEventType; const Msg: String);
 +
  // El procedimineto es llamado por TSQLConnection y guarda los mensajes recibidos
 +
  // en la lista de cadenas FConnectionLog
 +
  var
 +
    Source: string;
 +
  begin
 +
    // Muy bien alineado a la derecha...
 +
    case EventType of
 +
      detCustom:  Source:='Custom:  ';
 +
      detPrepare:  Source:='Prepare: ';
 +
      detExecute:  Source:='Execute: ';
 +
      detFetch:    Source:='Fetch:  ';
 +
      detCommit:  Source:='Commit:  ';
 +
      detRollBack: Source:='Rollback:';
 +
      else Source:='Evento desconocido. Corrige el código del programa.';
 +
    end;
 +
    FConnectionLog.Add(Source + ' ' + Msg);
 +
  end;
  
Another reason to use prepared statements is prevention of [http://en.wikipedia.org/wiki/SQL_injection SQL-injection], but in some cases it just simplifies coding.
+
...
 +
  // Necesitamos decirle a nuestro TSQLConnection lo que debe registrar:
 +
    FConnection.LogEvents:=LogAllEvents; //= [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack]
 +
    // ... y el procedimiento de la conexión que debe enviar los eventos:
 +
    FConnection.OnLog:=@Self.GetLogEvent;
 +
...
 +
  // Ahora podemos usar la conexión y la lista de cadenas FConnectionLog se llenará con los mensajes de registro.
 +
</syntaxhighlight>
 +
 
 +
&nbsp;&nbsp;&nbsp;También podemos utilizar ''GlobalDBLogHook'' de ''TSQLConnection'' en lugar de registrar todo desde múltiples conexiones.
 +
 
 +
&nbsp;&nbsp;&nbsp;Por último, la descripción anterior es la manera de hacer las cosas en FPC como se indica en la introducción, si se utiliza Lazarus, una forma más rápida es asignar un controlador de eventos al evento ''OnLog'' de ''TSQLConnection''.
  
 
== See also ==
 
== See also ==
 +
 
  * [[Working_With_TSQLQuery/es|Trabajando con TSQLQuery]].
 
  * [[Working_With_TSQLQuery/es|Trabajando con TSQLQuery]].
[[Category:Databases]]
 

Latest revision as of 14:10, 27 February 2020

Deutsch (de) English (en) español (es) français (fr) 日本語 (ja) Nederlands (nl) polski (pl) 中文(中国大陆)‎ (zh_CN)

Introducción

   Este texto se configura como un "cómo-hacer". Pretende responder a una serie de preguntas una por una, explicando cómo se pueden utilizar las distintas clases. Todas estas cuestiones puestas una detrás de otra forman una especie de tutoría.

   Voy a tratar de esccribir de tal manera que el texto pueda ser utilizado para Lazarus, así como FreePascal. Sin embargo, los ejemplos son para FreePascal (es decir, son aplicaciones de consola)

¿Cómo conectarse a un servidor de base de datos?

   SQLdb no se conecta a un servidor de base de datos directamente sino que utiliza el cliente correspondiente al servidor de base de datos utilizado. SQLdb envía los comandos a la librería de cliente, la cual se conecta a la base de datos y le pasa los comandos. Esto significa que una librería de cliente debe ser instalada en el equipo para establecer una conexión con una base de datos. En Windows un cliente suele ser una .dll, bajo Linux un .so y bajo OS/X una .dylib.

   Cuando la librería de cliente se ha instalado correctamente puede conectarse a un servidor de base de datos utilizando un componente TSQLConnection. Hay disponibles componentes TSQLConnection para diferentes servidores de base de datos ( ver paquete SQLdb) - siendo el listado de las disponibles el siguiente:

  • Firebird/Interbase: TIBConnection ( ver enlace)
  • MS-SQL: TMSSQLConnection (disponible desde la versión 2.6.1 de FPC,ver enlace)se puede crear una conexión con el método open. Si
  • MySQL v4.0: TMySQL40Connection (ver enlace)
  • MySQL v4.1: TMySQL41Connection (ver enlace)
  • MySQL v5.0: TMySQL50Connection (ver enlace)
  • MySQL v5.1: TMySQL51Connection (disponible desde la versión 2.5.1 de FPC,ver enlace)
  • MySQL v5.5: TMySQL55Connection (disponible desde la versión 2.?.? ver enlace)
  • ODBC: TODBCConnection (ver enlace)
  • Oracle: TOracleConnection (Oracle)
  • PostgreSQL: TPQConnection (ver enlace)
  • Sqlite3: TSQLite3Connection (disponible desde la versión 2.2.2 de FPC, ver enlace)
  • Sybase ASE: TSybaseConnection (disponible desde la versión 2.6.1 de FPC, ver enlace)


Conectores BBDD.png

   Las diferencias entre las versiones de cliente MySQL son grandes, en la medida que los clientes y las conexiones no se pueden intercambiar. Con un cliente MySQL versión 4.1 instalado, tienes que utilizar un TMySQL41Connection. Si se utiliza la misma versión de librería que de cliente probablemente con la 4.1 se podría conectar a un servidor MySQL 5.0, pero el requerimiento de correspondencia librería-conector a la misma versión es necesario.

   Aunque los detalles difieren entre las distintas base de datos, por lo general hay que establecer cuatro propiedades para conectarse a un servidor de base de datos:

  • El nombre del servidor o su dirección IP.
  • El nombre de la base de datos.
  • El usuario.
  • La contraseña.

   Cuando estas propiedades se establecen, se puede crear una conexión con el método, open. Si falla la conexión se lanza una excepción EDatabaseError. Utiliza la propiedad connected para comprobar si la conexión se ha establecido con el servidor de base de datos. Utiliza el método close para finalizar la conexión con el servidor.

Program ConectaDB
 
 var UnaConexion : TSQLConnection;
 
 Procedure CrearConexion;
 begin
   UnaConexion := TIBConnection.Create(nil);
   UnaConexion.Hostname := 'localhost';
   UnaConexion.DatabaseName := '/opt/firebird/examples/employee.fdb';
   UnaConexion.UserName := 'sysdba';
   UnaConexion.Password := 'contraseñamaestra';
 end;
 
 begin
   CrearConexion;
   UnaConexion.Open;
   if UnaConexion.Connected then
     writeln('¡Conexión realizada!')
   else
     writeln('¡Imposible!, porque si la conexión falla, '+
               'una excepción debe ser lanzada, por lo que este código no '+
                'será Ejecutado');
   UnaConexion.Close;
   UnaConexion.Free;
 end.

   Si se produce una excepción, lea atentamente el mensaje de error. Tal vez el servidor de base de datos no está funcionando, el nombre de usuario o la contraseña son incorrectos o el nombre o la dirección IP de base de datos estan escritos de forma incorrecta. Si el mensaje de error indica que la librería cliente no puede ser encontrada, comprueba si el cliente está instalado correctamente. A menudo, el mensaje de error muestra literalmente el nombre del archivo buscado. También es buena idea verificar en la documentación si alguna de estas propiedades está o no soportada para un conector concreto puesto que es posible que en algún caso deban dejarse sin rellenar (no me refiero a la documentación de la BBDD sino de la unidad que conecta).

¿Cómo ejecutar consultas directas o crear una tabla?

   SQLdb -el nombre lo dice todo- sólo funciona con servidores de base de datos que hacen uso de SQL. SQL significa Structured Query Language (Lenguaje estructurado de consulta). SQL es un lenguaje desarrollado para permitir trabajar con bases de datos relacionales. Prácticamente todos los sistemas de base de datos tiene su propio dialecto, pero un gran número de sentencias SQL son iguales en todos los sistemas de base de datos. Podemos hacer una diferencia entre las sentencias SQL que devuelven la información y sentencias que no devuelven información. Si desea utilizar la información que devuelve la sentencias SQL, tienes que utilizar el componente TSQLQuery (ver ¿Cómo leer datos de una tabla?). Si no piensas utilizar la información devuelta por la consulta SQL, entonces también puedes usar el método ExecuteDirect de un TSQLConnection.

   La mayoría de sistemas de base de datos ejecutan las sentencias SQL dentro de una transacción. Si desea que los cambios realizados dentro de una transacción estén disponible en otras transacciones, o disponer de los cambios disponible incluso después de cerrar la transacción, entonces tienes que realizar el commit de la transacción. Para soportar las operaciones SQLdb tiene el componente TSQLTransaction. Una sentencia SQL que se ejecuta por SQLdb siempre debe ser ejecutada dentro de una transacción. Incluso si el sistema de base de datos no soporta las transacciones. Además, hay sistemas de bases de datos que soportan transacciones para los que TSQLConnection no (todavía) soporta la transacción. Incluso entonces, debes utilizar el componente TSQLTransaction.

   Para utilizar TSQLConnection.ExecuteDirect para ejecutar una sentencia SQL debes especificar que Transaction se debe utilizar. A su vez, al utilizar TSQLTransaction debes especificar que TSQLConnection se debe utilizar.

   En el ejemplo siguiente se crea una tabla 'TBLNOMBRE' con los campos NOMBRE y nID e inserta dos registros. Las instrucciones SQL utilizadas no se explican. Para obtener más información acerca de las instrucciones SQL, su uso y su sintaxis, consulte la documentación del sistema de base de datos. El procedimiento CreateConnection se define en el ejemplo de código de ¿Cómo conectarse a un servidor de base de datos?.

program CreateTable;
 
 var AConnection : TSQLConnection;
     ATransaction : TSQLTransaction;
 
 procedure CreateTransaction;
 begin
   ATransaction := TSQLTransaction.Create;
   ATransaction.Database := AConnection;
 end;
 
 begin
   CreateConnection;
   CreateTransaction;
   AConnection.Transaction := ATransaction;
   AConnection.Open;
   ATransaction.StartTransaction;
   AConnection.ExecuteDirect('create table TBLNAMES (ID integer, NAME varchar(40));'); 
   
   // Some database-server types need a commit before you can use a newly created table. (Firebird)
   // With .Commit you also close the transaction
   ATransaction.Commit; 
 
   ATransaction.StartTransaction;
   AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (1,'Name1');'); 
   AConnection.ExecuteDirect('insert into TBLNAMES (ID,NAME) values (2,'Name2');'); 
   ATransaction.Commit; 
   AConnection.Close;
   AConnection.Free;
   ATransaction.Free;
 end.

¿Cómo leer datos de una tabla?

   Utiliza el componente TSQLQuery para leer datos de una tabla. Un componente TSQLQuery debe estar enlazado a un componente TSQLConnection y a un componente TSQLTransaction para hacer su trabajo. El ajuste de TSQLConnection y de TSQLTransaction se discute en ¿Cómo conectarse a un servidor de base de datos? y en ¿Cómo ejecutar consultas directas o crear una tabla?.

   Cuando TSQLConnection, TSQLTransaction y TSQLQuery están conectados, entonces TSQLQuery necesita más ajustes. TSQLQuery tiene una propiedad SQL que contiene un objeto TStrings. La propiedad 'SQL' contiene la sentencia SQL que debe ejecutarse. Si todos los datos de una tabla debe ser leídos establece la propiedad SQL a SELECT * FROM nombretabla;. Utiliza open para leer la tabla desde el servidor y poner los datos en el conjunto de datos TSQLQuery. Los datos se pueden acceder a través de TSQLQuery hasta que la consulta se cierra con close.

   TSQLQuery es una subclase de TDataset. TDataset tiene una colección Fields que contiene todas las columnas de la tabla. El TDataset también mantiene una marca del registro actual. Utiliza First, Next, Prior y Last para cambiar el registro actual. Bof devuelve true (verdadero) si se llegó al primer registro, y Eof devuelve true si se llegó al último registro. Para leer el valor de un campo en el registro actual, en primer lugar hayamos el objeto TField adecuado y luego usar 'AsString', 'AsInteger', etc.

   A continuación se muestra un ejemplo que muestra todos los valores de la tabla como se hizo en ¿Cómo ejecutar consultas directas o crear una tabla?.

Program ShowData;
 
 var AConnection : TSQLConnection;
     ATransaction : TSQLTransaction;
 
 procedure GetQuery : TSQLQuery;
 var AQuery : TSQLQuery;
 begin
   AQuery := TSQLQuery.Create;
   AQuery.Database := FConnection;
   AQuery.Transaction := FTransaction;
   Result := AQuery;
 end;
 
 var Query : TSQLQuery;
 
 begin
   CreateConnection;
   CreateTransaction;
   Query := GetQuery;
   Query.SQL.Text := 'select * from tblNames';
   AConnection.Open;
   Query.Open;
   while not Query.Eof do
     begin
     Writeln('ID: ', Query.FieldByName('Name').AsInteger, 'Name: ' +
                                   Query.FieldByName('Name').AsString);
     Query.Next;
     end;
   Query.Close;
   AConnection.Close;
   Query.Free;
   ATransaction.Free;
   AConnection.Free;
 end.

   (El código anterior, por supuesto, no está terminado, se echa de menos bloques try ... finally. Sin embargo, el código anterior tiene la intención de mostrar el código para base de datos y por lo tanto los toques finales son dejados de lado.) Ten en cuenta que TSQLTransaction.StartTransaction no se utiliza. Esto no es necesario. Cuando TSQLQuery se abre, la instrucción SQL se ejecuta y si no hay ninguna transacción está disponible, esta se inicia automáticamente. El programador no necesita iniciar la transacción explícitamente. Lo mismo se aplica para la conexión gestionada por TSQLConnection. La conexión se abre según sea necesario, la línea Aconnection.Open no es realmente necesaria.

   Si se destruye un TSQLTransaction, un rollback (deshacer) automático será ejecutado. Los posibles cambios a los datos contenidos en la transacción se perderán.

¿Por qué TSQLQuery.RecordCount siempre devuelve 10?

   Para contar los registros de un dataset, usaremos RecordCount. Sin embargo, observa que RecordCount muestra el número de registros que se ha cargado desde el servidor. SQLdb no lee todos los registros al abrir un TSQLQuery de forma predeterminada, sólo los 10 primeros. Sólo cuando se accede al undécimo registro entonces el siguiente conjunto de 10 registros se carga. Usando .Last todos los registros se cargarán.

   Si desea conocer el número real de registros en el servidor hay que llamar primero '.Last' y luego llamar a .RecordCount. Hay una alternativa disponible. El número de registros devueltos por el servidor está determinado por el valor de la propiedad PacketRecords. El valor por defecto es 10, si se pone a -1 entonces todos los registros serán cargados a la vez.

Lazarus

   Lazarus tiene diversos componentes para mostrar datos de un TDataset en un formulario. En lugar de un bucle while y declaraciones Writeln usados en el ejemplo, puedes utilizar componentes para mostrar los datos de una tabla. Coloca los adecuados componentes TSQLConnection, TSQLTransaction y TSQLQuery en un formulario, a continuación, se conectan y configuran correctamente. Además se necesita un TDataSource, ajusta la propiedad TDatasource.Dataset al componente TSQLQuery utilizado. (Nota no establecer la propiedad TSQLQuery.Datasource al componente TDataSource. La propiedad TSQLQuery.Datasource se utiliza solamente en tablas maestro/detalle) A continuación puedes poner un TDBGrid en el formulario y establece la propiedad Datasource de la rejill (grid) al componente TDataSource agregado antes.

   Para ver si funciona todo, establece la propiedad Connected del TSQLConnection a True en el IDE de Lazarus. El IDE intenta conectar con el servidor de base de datos inmediatamente. Si funciona se puede establecer la propiedad TSQLQuery.Active a 'True'. Si todo está correcto, podrás ver -en el IDE- todos los datos de la tabla inmediatamente en la pantalla.

¿Cómo cambiar los datos en una tabla?

   Para cambiar datos en un registro, el TDataset (del que se deriva TSQLQuery) debe ponerse en modo de edición. Para activar el modo de edición podemos llamar a los métodos .Edit, . Inserto .Append. Utiliza el método .Edita para modificar el registro actual. Utiliza .Insert para crear un nuevo registro antes del registro actual. Utiliza .Append paara añadir un nuevo registro al final de la tabla. En modo edición puedes cambiar el valor de los campos a través de la propiedad Fields. Utiliza Post para validar los nuevos datos, si los datos son válidos entonces se abandona el modo de edición. Si se cambia a un nuevo registro -por ejemplo, utilizando .Next- y el conjunto de datos está en modo de edición, se llamará a .Post antes. Utiliza .Cancel para descartar todos los cambios realizados desde la última llamada a .Post y termina el modo de edición.

 Query.Edit;
 Consulta.FieldByName('NOMBRE').AsString := 'Nombre editado';
 Consulta.Post;


   Lo anterior no es la historia completa todavía. TSQLQuery se deriva de TBufDataset que hace uso de actualizaciones en un buffer. Actualización en buffer significa que después de llamado Post los cambios en el conjunto de datos son visibles de inmediato, pero no se envían al servidor de base de datos. Lo que sucede es que los cambios se mantienen en un registro de cambios. Cuando se llama al método .ApplyUpdates todos los cambios en el registro de cambios se envían al servidor de base de datos. Sólo entonces el servidor de base de datos conoce todos los cambios. Los cambios se envían al servidor en una transacción de TSQLTransaction. Asegúrese de establecer correctamente la transacción antes de ApplyUpdates. Después de aplicar las actualizaciones, se debe ejecutar commit para publicar o guardar los cambios.


   El siguiente es un ejemplo de la cambio de datos en una tabla, envío de los cambios al servidor y confirmación de la transacción.

 Program EditarDatos;
 
 var unaConexion : TSQLConnection;
     unaTransaccion : TSQLTransaction;
     Consulta : TSQLQuery;
 
 begin
   CrearConexion;
   CrearTransaccion;
   unaConexion.Transaction := unaTransaccion;
   Consulta := GetQuery;
   Consulta.SQL.Text := 'select * from tblNombres';
   Consulta.Open;
   Consulta.Edit;
   Consulta.FieldByName('NOMBRE').AsString := 'Nombre editado';
   Consulta.Post;
   Consulta.UpdateMode := upWhereAll;
   Consulta.ApplyUpdates;
   AConnection.Transaction.Commit;
   Consulta.Free;
   unaTransaccion.Free;
   unaConexion.Free;
 end.


   Para una discusión de UpdateMode sigue leyendo.

¿Cómo SQLdb envia los cambios al servidor de base de datos?

   En el ejemplo de código de ¿Cómo cambiar los datos en una tabla?, se encuentra la línea.

 Consulta.UpdateMode := upWhereAll;

sin ninguna explicación de lo que hace. La mejor manera de averiguar lo que esa línea hace es quitarla. Si se omite la orden y se sigue esta guía con precisión, se recibirá el siguiente mensaje de error:

 No update query specified and failed to generate one. (No fields for inclusion in where statement found)

   Para entender lo que salió mal, debes entender cómo los cambios se envían al servidor de base de datos. La única manera de obtener datos en un servidor SQL es mediante la ejecución de consultas SQL. SQL tiene tres tipos de consultas para tres maneras diferentes de manipular un registro. Para crear un nuevo registro, cambiar o eliminar un registro las sentencias insert, update y delete se ejecutan, respectivamente. Una sentencia de actualización (update) puede ser así:

 update TBLNAMES set NAME='Edited name' where ID=1;

   Para enviar un cambio al servidor de base de datos, SQLdb debe crear una consulta de actualización. Para crearla consulta, se necesitan tres cosas:

El nombre de la tabla
El nombre de la tabla se obtiene de analizar la consulta de selección, aunque esto no siempre funciona.
Una clásula UPDATE o INSERT
Estas contienen los campos que se deben cambiar.
Una clásula WHERE
Esta contiene los campos que determinan qué registros se deben cambiar.

   Todos los campos (cada TField en Fields) tiene una propiedad ProviderFlags. Sólo los campos con pfInUpdate en ProviderFlags se utilizarán en la clásula de actualización o inserción de la consulta. Por defecto todos los campos tienen pfInUpdate puesto en su propiedad ProviderFlags.

   Qué campos se utilizan en la clásula WHERE depende de la propiedad UpdateMode de la consulta y la propiedad ProviderFlags de los campos. Los campos con pfInkey en su ProviderFlags siempre se utilizan en la clásulaWHERE. Un campo tendrá el indicador pfInKey establecido de forma automática si el campo es parte de la clave principal de la tabla y TSQLQuery.UsePrimaryKeyAsKey devuelve True.

   El valor predeterminado para UpdateMode de la consulta es upWhereKeyOnly. En este modo se actualizan los campos sólo con pfInkey en su propiedad ProviderFlags 'se utilizan en la clásula WHERE. Si ninguno de los campos tienen el indicador pfInKey establecido, entonces no hay campos disponibles para la cláusula WHERE y el mensaje de error del principio de esta sección será devuelto. Puede resolver el problema así:

  • Añadir una clave principal a la tabla y poner TSQLQuery.UsePrimaryKeyAsKey a 'True', o
  • Poner el indicador pfInkey para uno o varios campos en el código.

   La propiedad UpdateMode puede tener dos posible valores más. UpWhereAll puede usarse para agregar todos los campos con el indicador pfInWhere establecido para la cláusula WHERE. Por defecto todos los campos tienen este indicador establecido. UpWhereChanged puede usarse para agregar sólo los campos que tienen el indicador pfInWhere establecido y que se han modificado del registro actual.

¿Cómo ejecutar una consulta mediante TSQLQuery?

   Junto a las declaraciones que devuelven un conjunto de datos (ver ¿Cómo leer datos de una tabla?) SQL tiene sentencias que no devuelven datos. Por ejemplo INSERT, UPDATE y DELETE no devuelven datos. Estas sentencias se pueden ejecutar mediante TSQLConnection.ExecuteDirect , pero TSQLQuery puede utilizarse también. Si no esperas devolver datos utiliza TSQLQuery.ExecSQL en lugar de TSQLQuery.Open. Utiliza TSQLQuery.Open para abrir el conjunto de datos devuelto por la consulta SQL.

   El siguiente procedimiento crea una tabla y se insertan dos registros utilizando TSQLQuery.

procedure CrearTabla;
  
  var Consulta : TSQLConsulta;
  
  begin
    Consulta := GetConsulta;
    Consulta.SQL.Text := 'create table TBLNOMBRES (ID integer, NOMBRE varchar(40));';
    Consulta.ExecSQL;
  
    Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (1,'Nombre1');';
    Consulta.ExecSQL;
  
    Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (2,'Nombre2');';
    Consulta.ExecSQL;
  
    Consulta.Close;
    Consulta.Free;
  end;

¿Cómo utilizar parámetros en una consulta?

   En el código de ejemplo de ¿Cómo ejecutar una consulta mediante TSQLQuery? la misma consulta se utiliza dos veces, sólo difieren en los valores que se insertan. Una manera mejor de hacerlo es mediante el uso de parámetros en la consulta.

   La sintaxis de los parámetros en las consultas es diferente en cada sistema de base de datos, pero las diferencias las maneja TSQLQuery. Coloca de nuevo los valores en la consulta con dos puntos precediendo al nombre del parámetro que desea utilizar. Por ejemplo:

 Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (:ID,:NOMBRE);';

   Esta consulta crea dos parámetros: 'ID' y 'NOMBRE'. Para determinar los parámetros, la consulta se analiza en el momento en que se asigna o modifica el texto de TSQLQuery.SQL. Todos los parámetros existentes se eliminarán y los nuevos parámetros se añadirán a la propiedad TSQLQuery.Params. Asignar un valor a un parámetro es similar a asignar un valor a un campo en el conjunto de datos:

 Query.Params.ParamByName('Nombre').AsString := 'Name1';

   No se puede saber desde consulta qué tipo de datos deben ser almacenados en el parámetro. El tipo de datos del parámetro se determina en el momento en que un valor se asigna al parámetro. Al asignar un valor utilizando . AsString, el parámetro se asigna al tipo de datos ftString. Puede determinar el tipo de datos directamente mediante el establecimiento de la propiedad DataType. Si un tipo de datos incorrecto se asigna al parámetro, entonces los problemas se producirán durante la apertura o ejecución de la consulta.

   En el ejemplo siguiente se crea la misma tabla del ejemplo anterior, pero ahora se utilizan parámetros:

 procedure CrearTablaUsandoParametros;
  
  var Consulta : TSQLQuery;
  
  begin
    Consulta := GetQuery;
    Consulta.SQL.Text := 'create table TBLNOMBRES (ID integer, NOMBRE varchar(40));';
    Consulta.ExecSQL;
  
    Consulta.SQL.Text := 'insert into TBLNOMBRES (ID,NOMBRE) values (:ID,:NOMBRE);';
  
    Consulta.Params.ParamByName('ID').AsInteger := 1;
    Consulta.Params.ParamByName('NOMBRE').AsString := 'Nombre1';
    Consulta.ExecSQL;
  
    Consulta.Params.ParamByName('ID').AsInteger := 2;
    Consulta.Params.ParamByName('NOMBRE').AsString := 'Nombre2';
    Consulta.ExecSQL;
  
    Consulta.Close;
    Consulta.Free;
  end;

   Observa que este ejemplo requiere más código que el ejemplo sin parámetros. Entonces, ¿qué es el ventaja de la utilización de parámetros? La velocidad es una de las razones. El ejemplo con parámetros es más rápido porque la consulta se analiza solamente una vez. TSQLQuery sólo analiza la consulta una vez, pero también el servidor de base de datos analiza la consulta una sola vez. La mayoría de los sistemas de base de datos soportan parámetros. Siempre que una consulta se utiliza más de una vez con diferentes valores para el parámetro cada vez, entonces el servidor de base de datos sólo analiza la consulta y los planes de la consulta una sola vez haciendo la ejecución considerablemente más rápida.

   Utiliza TSQLQuery.Prepare para determinar el momento en que se analiza y se planifica la consulta por el servidor de base de datos. Utiliza TSQLQuery.UnPrepare para asegurarse de que la consulta se analiza y se planifica cada vez por el servidor de datos.

   Otra razón para usar sentencias preparadas es la prevención de inyección de SQL, pero en algunos casos únicamente simplifica la codificación.

Solución de problemas:

Registro de sucesos de TSQLConnection

   Puedes hacer que TSQLConnection registre lo que está haciendo. Esto puede ser útil para ver exactamente lo que tu programa envía a la base de datos, para depurar los propios componentes de base de datos y también para optimizar las consultas.

   Nota: si utilizas comandos preparados o consultas parametrizadas (ver la sección anterior), los parámetros son a menudo enviados en binario por el descendiente de TSQLConnection (por ejemplo, TIBConnection), por lo que no se puedes simplemente copiar o pegar el código SQL registrado en una herramienta de consulta de la base de datos.

   En cualquier caso, el registro de la activad de la conexión puede dar una gran cantidad de información sobre lo que está haciendo tu programa.

   Otras alternativas son:

  1. utilizar el depurador para recorrer el código base de datos si se ha construido el FPC o Lazarus con la depuración habilitada.
  2. si utilizas controladores ODBC (al menos en Windows) puedes habilitar la salida tracelog en el panel de control de ODBC.
  3. muchas bases de datos permiten controlar todas las ordennes que se le envían desde una determinada dirección IP o conexión.

   Para utilizar el registro de actividad de TSQLConnection, se requieren dos cosas:

  1. indicar qué tipos de eventos del TSQLConnection deben registrarse
  2. apuntar TSQLConnection a la función que recibe los eventos y los procesa (los registra en un archivo, que se imprima en la pantalla, etc)

   Esta función debe ser de tipo TDBLogNotifyEvent (ver sqldb.pp), por lo que seguirá este patrón:

 TDBLogNotifyEvent = Procedure (Sender : TSQLConnection; EventType : TDBEventType; Const Msg : String) of object;

   Este fragmento de código puede ilustrar esto:

 uses
 ...//
 TSQLConnection, //o un objeto heredero tal que TIBConnection, TMSSQLConnection
 ...//
 var
 type 
   TMyApplication = class(TCustomApplication); //esta es nuestra aplicación, la que utiliza la conexión
 ...//
   private
     // Este ejemplo guarda el registro en un stringlist:
     FConnectionLog: TStringList;
 ...//
   protected
     // Este procedimiento recibe los eventos que registra la conexión:
     procedure GetLogEvent(Sender: TSQLConnection; EventType: TDBEventType; Const Msg : String);
...
  procedure TMyApplication.GetLogEvent(Sender: TSQLConnection;
    EventType: TDBEventType; const Msg: String);
  // El procedimineto es llamado por TSQLConnection y guarda los mensajes recibidos
  // en la lista de cadenas FConnectionLog
  var
    Source: string;
  begin
    // Muy bien alineado a la derecha...
    case EventType of
      detCustom:   Source:='Custom:  ';
      detPrepare:  Source:='Prepare: ';
      detExecute:  Source:='Execute: ';
      detFetch:    Source:='Fetch:   ';
      detCommit:   Source:='Commit:  ';
      detRollBack: Source:='Rollback:';
      else Source:='Evento desconocido. Corrige el código del programa.';
    end;
    FConnectionLog.Add(Source + ' ' + Msg);
  end;

...
  // Necesitamos decirle a nuestro TSQLConnection lo que debe registrar:
    FConnection.LogEvents:=LogAllEvents; //= [detCustom, detPrepare, detExecute, detFetch, detCommit, detRollBack]
    // ... y el procedimiento de la conexión que debe enviar los eventos:
    FConnection.OnLog:=@Self.GetLogEvent;
...
  // Ahora podemos usar la conexión y la lista de cadenas FConnectionLog se llenará con los mensajes de registro.

   También podemos utilizar GlobalDBLogHook de TSQLConnection en lugar de registrar todo desde múltiples conexiones.

   Por último, la descripción anterior es la manera de hacer las cosas en FPC como se indica en la introducción, si se utiliza Lazarus, una forma más rápida es asignar un controlador de eventos al evento OnLog de TSQLConnection.

See also

* Trabajando con TSQLQuery.