I'm failing dismally to read a datetime from an SQLite database using Delphi 10.3 and FireDAC. As the simplest example, I create a sample database using sqlite as follows:
.open Test.db
CREATE TABLE "TABLE1" ("Name"VarChar(16), "Time" datetime);
INSERT INTO Table1 (Name,Time) VALUES("Fred",time('now'));
Then
select * from Table1
gives Fred|16:52:57 as expected.
If I generate a Delphi program with an FDConnection1 and FDQuery1 linked to a datasource and DBgrid it will read "Fred" but not the time. The value returned by FDquery1 asstring is '' and asfloat is 0. If I try the FireDAC explorer tool to look at the database it also fails to read the time value but I notice it does read datetimes from some of the example databases so it clearly can work.
Can anyone tell me what I'm missing. Thanks
Trying to construct a SQL statement as a string in Delphi code can be a bit error prone. However, you should find that the following code executes correctly
procedure TForm2.btnInsertRowClick(Sender: TObject);
const
sInsertRow = ' INSERT INTO Table1 (Name,time) VALUES(''Fred'',datetime(''now''))';
begin
FDConnection1.ExecSql(sInsertRow);
end;
Btw, in general it would be better to use a parameterised INSERT statement than a literal one like the above, but it's not really practical here as you are inserting the now
value returned by Sqlite rather than the Delphi now
function.
**Update: ** The code below is from a minimal project which creates your example table, inserts a row into it and then presents it in db-aware controls (DBGrid, DBEdit) for editing. It all works exactly as it ought to. In particular, any changes to the row data made through those controls are retained when tha app is next run. Note that the SQL which creates the table specifies a primary key on the Name column/field: this is necessary for the FDQuery1 to generate the UPDATE statements needed to save changes back to the on-disk table.
The code in the btnSelectClick
handler shows how to set the time
field's DisplayFormat and EditMask properties so that it only displays the time part of the stored DateTime data.
type
TForm2 = class(TForm)
FDConnection1: TFDConnection;
FDQuery1: TFDQuery;
DBGrid1: TDBGrid;
DBNavigator1: TDBNavigator;
DataSource1: TDataSource;
DBEdit1: TDBEdit;
btnCreateTable: TButton;
btnInsertRow: TButton;
btnSelect: TButton;
[...]
public
[...]
const
sCreateTable = 'CREATE TABLE ''TABLE1'' (''Name'' VarChar(16) primary key, ''Time'' datetime)';
sInsertRow = ' INSERT INTO Table1 (Name,time) VALUES(''Fred'',datetime(''now''))';
sSelect = 'select * from table1';
procedure TForm2.btnCreateTableClick(Sender: TObject);
begin
FDConnection1.Connected := True;
FDConnection1.ExecSql(sCreateTable);
end;
procedure TForm2.btnInsertRowClick(Sender: TObject);
const
begin
FDConnection1.ExecSql(sInsertRow);
end;
procedure TForm2.btnSelectClick(Sender: TObject);
var
AField : TDateTimeField;
begin
FDQuery1.SQL.Text := sSelect;
FDQuery1.Open;
// The following shows how to control how the time field is formatted for display
// in gui controls using the field's DisplayFormat
// and how to set up its EditMask for editing
AField := FDQuery1.FieldByName('time') as TDateTimeField;
AField.DisplayFormat := 'hh:nn:ss';
AField.EditMask := '!90:00:00;1;_';
end;
end.
.DFM file
object Form2: TForm2
[...]
object FDConnection1: TFDConnection
Params.Strings = (
'Database=D:\Delphi\Code\FireDAC\db1.sqlite'
'DriverID=SQLite')
LoginPrompt = False
end
object FDQuery1: TFDQuery
Connection = FDConnection1
end
object DataSource1: TDataSource
DataSet = FDQuery1
end
object DBGrid1: TDBGrid
DataSource = DataSource1
end
object DBNavigator1: TDBNavigator
DataSource = DataSource1
end
object DBEdit1: TDBEdit
DataField = 'Time'
DataSource = DataSource1
end
end