Ayer me encontré con este problema cuando estaba ocupado escribiendo algunas pruebas de unidad con SQLLite. Mi entorno es Windows7/Delphi XE.El uso de un parámetro de fecha y hora con ADO (ODBC) pierde parte de tiempo
El uso de TADOQuery junto con un parámetro TDateTime da como resultado la pérdida de la parte de tiempo.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ADODb, DateUtils, DB;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var DbConn : TADOConnection;
Qry : TADOQuery;
DT : TDateTime;
begin
DBConn := TADOConnection.Create(nil);
DBConn.ConnectionString := 'Provider=MSDASQL.1;Extended Properties="DRIVER=SQLite3 ODBC Driver;Database=:memory:;LongNames=0;Timeout=1000;NoTXN=0;SyncPragma=NORMAL;StepAPI=0;"';
// DBConn.ConnectionString := 'Provider=MSDASQL.1;Persist Security Info=True;User ID=%0:s;Password=%1:s;Extended Properties="DRIVER={MySQL ODBC 5.1 Driver};SERVER=localhost;PORT=3306;DATABASE=test;USER=root;PASSWORD=rrr;OPTION=1048579"';
Qry := TADOQuery.Create(nil);
Qry.Connection := DbConn;
try
DBConn.Connected := True;
Qry.SQL.Text := 'CREATE TABLE test(d datetime)';
Qry.ExecSQL;
Qry.ParamCheck := True;
Qry.SQL.Text := 'INSERT INTO test (d) VALUES (:d)';
//Qry.Parameters.ParseSQL(Qry.SQL.Text, True); // not needed
TryEncodeDateTime(1999, 12, 12, 10, 59, 12, 0, DT);
Qry.Parameters.ParamByName('d').Value := DT;
Qry.Parameters.ParamByName('d').DataType := ftDateTime;
Qry.ExecSQL;
Qry.SQL.Text := 'SELECT d FROM test';
Qry.Open;
ShowMessage(FormatDateTime('MM/DD/YYYY HH:NN:SS', Qry.FieldByName('d').AsDateTime));
finally
FreeAndNil(Qry);
FreeAndNil(DbConn);
end;
end;
Lo curioso es que, cuando comento la línea Qry.Parameters.ParseSQL(Qry.SQL.Text, True);
Se trabajará muy bien. Necesito la parte ParseSQL porque estoy construyendo un mini-ORM, así que necesita saber qué parámetros deben mapearse. Algunas observaciones:
- haciendo la misma prueba con MySQL5 muestra el mismo problema (independientemente de la parte ParseSQL).
- Este código funciona con SQL Server y el controlador OLEDB.
He buscado en la red y que se encuentran algunos enlaces interesantes:
http://tracker.firebirdsql.org/browse/ODBC-27
http://embarcadero.newsgroups.archived.at/public.delphi.database.ado/201107/1107112007.html
http://bugs.mysql.com/bug.php?id=15681
El primer enlace sugiere 'fijar' ADODB.pas, algo que hago No quiero hacer Al leer el último enlace, parece que ADO mapea el valor de fecha y hora hasta la fecha.
respuesta No quiero oír: utilizar otra biblioteca/componente (como dbexpress, ZeosLib, ...)
No estoy seguro de lo que sería ser el enfoque más sensato para resolver este problema.
Como Linas y Marjan Venema sugirieron que puedo omitir la parte de ParseSQL. Entonces, el código funciona ahora con SQLlite SI omito la línea Qry.Parameters.ParamByName('d').DataType := ftDateTime;
.
Pero MySQL se niega a guardar la parte de tiempo. ¿Estoy viendo un problema de compatibilidad entre ADO y MySQL ODBC aquí?
Establecería el tipo de datos antes de establecer el valor, pero no estoy seguro de que eso suponga alguna diferencia. ¿Por qué la construcción de un mini ORM necesita ParseSQL? He construido algunas librerías de tipo ORM y nunca las necesité. IIRC Qry.SQL.Prepare también debe llenar la colección de parámetros. –
Necesito saber qué parámetros tengo en mi consulta y los valores serán mapeados desde un objeto usando rtti. te refieres a Qry.Prepared: = true; ? No hace diferencia. – whosrdaddy
@whosrdaddy No hay necesidad de llamar a ParseSQL por su cuenta. Se llama automáticamente cuando SQL.Text cambia (ParamCheck debe ser True). – Linas