Insert date into a SQLite database - sqlite

As a part of a parametrized query I am trying to insert date from the plannerCalendar.
Params.ParamByName('D').AsDate := JulianDateToDateTime(PlannerCalendar1.Date);
This will not work.
Any ides ?
EDIT :
Even a simpla date insert will not work:
with ClientdataSet1 do
begin
Close;
CommandText :='';
CommandText :='INSERT INTO TLOG (DATE) VALUES (:D)';
Params.ParamByName('D').Value := Plannercalendar1.Date;
Execute;
I get :
When I do this (just to test) :
CommandText :='INSERT INTO TLOG (DATE) VALUES (date(julianday("now", "LOCALTIME")))';
The date gets inserted.
When I use this (looks promising) :
Params.ParamByName('D').Value := DateTimeToJulianDate(Plannercalendar1.Date);
The date inserted in the database is OK but the cxgrid displays the date funny (bellow):
Changing of the parameter does not help either.
VALUES (julianday(:D),
If I change the DATE field to CHAR in the database then the :
DateToStr(Plannercalendar1.Date);
works properly....

I store datetime in SQL timestamps:
SomeQuery.ParamByName('PARAM').AsSQLTimeStamp := DateTimeToSQLTimeStamp(Now);
SomeDateTime := SQLTimeStampToDateTime(SomeQuery.ParamByName('PARAM').AsSQLTimeStamp);
Take a look at this functions From Data.SqlTimSt unit:
DateTimeToSQLTimeStamp
SQLTimeStampToDateTime

Related

Is there a way to INSERT Null value as a parameter using FireDAC?

I want to leave some fields empty (i.e. Null) when I insert values into table. I don't see why would I want to have a DB full of empty strings in fields.
I use Delphi 10, FireDAC and local SQLite DB.
Edit: Provided code is just an example. In my application values are provided by user input and functions, any many of them are optional. If value is empty, I would like to keep it at Null or default value. Creating multiple variants of ExecSQL and nesting If statements isn't an option too - there are too many optional fields (18, to be exact).
Test table:
CREATE TABLE "Clients" (
"Name" TEXT,
"Notes" TEXT
);
This is how I tried it:
var someName,someNote: string;
begin
{...}
someName:='Vasya';
someNote:='';
FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name,Notes) VALUES (:nameval,:notesval)',
[someName, IfThen(someNote.isEmpty, Null, somenote)]);
This raises an exception:
could not convert variant of type (Null) into type (OleStr)
I've tried to overload it and specify [ftString,ftString] and it didn't help.
Currently I have to do it like this and I hate this messy code:
FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name,Notes) VALUES ('+
IfThen(someName.isEmpty,'NULL','"'+Sanitize(someName)+'"')+','+
IfThen(someNote.isEmpty,'NULL','"'+Sanitize(someNote)+'"')+');');
Any recommendations?
Edit2: Currently I see an option of creating new row with "INSERT OR REPLACE" and then use multiple UPDATEs in a row for each non-empty value. But this looks direly ineffective. Like this:
FDConnection1.ExecSQL('INSERT OR REPLACE INTO Clients(Name) VALUES (:nameval)',[SomeName]);
id := FDConnection1.ExecSQLScalar('SELECT FROM Clients VALUES id WHERE Name=:nameval',[SomeName]);
if not SomeString.isEmpty then
FDConnection1.ExecSQL('UPDATE Clients SET Notes=:noteval WHERE id=:idval)',[SomeNote,id]);
According to Embarcadero documentation ( here ):
To set the parameter value to Null, specify the parameter data type,
then call the Clear method:
with FDQuery1.ParamByName('name') do begin
DataType := ftString;
Clear;
end;
FDQuery1.ExecSQL;
So, you have to use FDQuery to insert Null values, I suppose. Something like this:
//Assign FDConnection1 to FDQuery1's Connection property
FDQuery1.SQL.Text := 'INSERT OR REPLACE INTO Clients(Name,Notes) VALUES (:nameval,:notesval)';
with FDQuery1.ParamByName('nameval') do
begin
DataType := ftString;
Value := someName;
end;
with FDQuery1.ParamByName('notesval') do
begin
DataType := ftString;
if someNote.IsEmpty then
Clear;
else
Value := someNote;
end;
if not FDConnection1.Connected then
FDConnection.Open;
FDQuery1.ExecSql;
It's not very good idea to execute query as String without parameters because this code is vulnerable to SQL injections.
Some sources tells that it's not enough and you should do something like this:
with FDQuery1.ParamByName('name') do begin
DataType := ftString;
AsString := '';
Clear;
end;
FDQuery1.ExecSQL;
but I can't confirm it. You can try it if main example won't work.

Reading 'bad' Sqlite data with FireDAC

I just learned that the Sqlite Manager plug-in for Firefox will go away in November, so I've been trying to recreate its functionality in Delphi: open Sqlite databases, enter SQL queries. I'm running Tokyo.
My problem comes with Sqlite fields defined as 'date.' While Sqlite allows specification of data types, it allows pretty much anything to be put in any field. FireDAC handles bad entries in integer or float fields ('bar' becomes 0, '32foo' becomes 32), but it hiccups on fields described as 'date.'
For example, I have a table:
CREATE TABLE "someTable" ("id" INTEGER, "s" text(10), "d" date)
With this data:
INSERT INTO "someTable" VALUES ("1","good date","2017-09-09");
INSERT INTO "someTable" VALUES ("2","bad date","2017-09-0b");
INSERT INTO "someTable" VALUES ("3","empty d","");
INSERT INTO "someTable" VALUES ("4","null date",null);
Opening FDQuery q1 with SQL = "select * from someTable", a bad date (such as the second record) raises an EConvertError ("Invalid argument to date encode"). I tried to get around it by adding a maprule (q1 is a FDQuery):
with q1.FormatOptions do begin
OwnMapRules := True;
with MapRules.Add do begin
SourceDataType := dtDate;
TargetDataType := dtAnsiString;
sizemin := 10;
sizemax := 256;
PrecMin := -1;
PrecMax := -1;
ScaleMin := -1;
ScaleMax := -1;
end;
end;
However, that raises an EFDException:
[FireDAC][DatS]-32. Variable length column overflow. Value length - [10], column maximum length - [0].
What am I missing?
Why do I get "Invalid argument to date encode" exception when fetching tuple containing invalid DATE type field value?
The problem is that FireDAC expects DATE data type values represented as a string in fixed format YYYY-MM-DD where all members must be integers. Internally used FDStr2Int function doesn't use any detection of invalid input and works directly with ASCII ordinary values shifted by the 0 char, so input like e.g. GHIJ-KL-MN results in year 25676, month 298, day 320 after parsing. And just these misinterpreted values are then passed to the EncodeDate function, which fails for such values with the exception you've mentioned:
Invalid argument to date encode
The above happens inside the GetData method (ParseDate nested function). One possible way for fixing this issue on FireDAC's side could be using safer function TryEncodeDate instead of a direct encoding attempt. Similar problem is with TIME data type string value.

Delphi SqLite Date load to TDateEdit error

I using SQlite database im my Firemonkey Android application and there is no native DateTime type.
I storing date as text type
insert command:
insert into table (value,date_of_change)
values (:val,date('now'));
it works fine, date is correct stored, order by date works fine but if I want load this date into TDate edit
query:
select id,value,date_of_change
from table
where id = :MyID
code:
FDQuery1.Close;
FDQuery1.ParamByName('MyID').Value:= myid;
FDQuery1.OpenOrExecute;
FDQuery1.First;
NumberBox1.Value:=FDQuery1.FieldByName('suma').AsFloat;
DateEdit1.Date:=FDQuery1.FieldByName('date_of_change').AsDateTime;
I get error 2016-10-16 is not valid date and time but in Date edit I can see correct date !
Do anybody knows correct solution of this problem ?
Since you store the date as a string FireDAC fails to parse the format properly. You need to change the way the string value in the database column date_of_change is parsed using the correct date format.
So, instead of doing this:
DateEdit1.Date:=FDQuery1.FieldByName('date_of_change').AsDateTime;
You should do this:
function ParseDateFromDB(const DateStr: String): TDateTime;
var
FormatSettings: TFormatSettings;
begin
FormatSettings.DateSeparator := '-';
FormatSettings.ShortDateFormat := 'YYYY-MM-DD';
Result := StrToDate(DateStr, FormatSettings);
end;
//[...]
DateEdit1.Date := ParseDateFromDB(FDQuery1.FieldByName('date_of_change').AsString);
FireDAC uses its own mapping to SQLite data types and adds the DATE pseudo data type for you. So as there is the SINGLE pseudo data type that you can use for storing value of that number box.
So you can create your table by FireDAC like this:
FDQuery.SQL.Text := 'CREATE TABLE MyTable (DateField DATE, SingleField SINGLE)';
FDQuery.ExecSQL;
Then you can insert data:
FDQuery.SQL.Text := 'INSERT INTO MyTable (DateField, SingleField) VALUES (:DateField, :SingleField)';
FDQuery.ParamByName('DateField').AsDate := DateEdit.Date;
FDQuery.ParamByName('SingleField').AsSingle := NumberBox.Value;
FDQuery.ExecSQL;
And read them for example this way:
FDQuery.SQL.Text := 'SELECT DateField, SingleField FROM MyTable';
FDQuery.Open;
DateEdit.Date := DateOf(FDQuery.FieldByName('DateField').AsDateTime);
NumberBox.Value := FDQuery.FieldByName('SingleField').AsSingle;

Teradata SQL Assistant Date Inserts

Context is Teradata SQL Assistant
Successfully created the following table:
CREATE VOLATILE TABLE RSN_WEEKLY_TMP, NO LOG
(
EXPLICIT_DATE DATE FORMAT 'MM/DD/YYYY'
)
PRIMARY INDEX (EXPLICIT_DATE)
ON COMMIT PRESERVE ROWS;
1) The following INSERT works successfully:
INSERT INTO JOCOOPER.RSN_WEEKLY_TMP (EXPLICIT_DATE) VALUES (CURRENT_DATE);
2) The following INSERT does not work and returns with Error:INSERT Failed [26665] Invalid date.
INSERT INTO JOCOOPER.RSN_WEEKLY_TMP (EXPLICIT_DATE) VALUES (02/02/2016);
3) However, if I use a string 'date value' and CAST it as a Date it works.
INSERT INTO JOCOOPER.RSN_WEEKLY_TMP (EXPLICIT_DATE) VALUES (CAST('02/03/2016' AS DATE FORMAT 'MM/DD/YYYY') );
I need to know how to make example #2 work? Please Advise?
02/02/2016 is an INTEGER calculation, dividing 2 by 2 by 2016, results in zero, of course this is not a valid date.
CAST('02/03/2016' AS DATE FORMAT 'MM/DD/YYYY') works because it tells the parser how to convert the string to a DATE.
The only recommended (and the shortest) way is a Standard SQL DATE literal:
DATE '2016-02-03'
You never need to think about formats because there's only one: YYYY-MM-DD
Actually, this format works too
insert into table_name (datecol) select '2015/12/31';
In your example:
CREATE VOLATILE TABLE RSN_WEEKLY_TMP, NO LOG
(
--EXPLICIT_DATE DATE FORMAT 'MM/DD/YYYY'
EXPLICIT_DATE DATE
)
PRIMARY INDEX (EXPLICIT_DATE)
ON COMMIT PRESERVE ROWS;
INSERT INTO JOCOOPER.RSN_WEEKLY_TMP (EXPLICIT_DATE) select '2016/02/02';

How to insert a string into sQlite.sdb (FireDac)?

I am trying to insert some text into a sqlite database.
I am using FireDac connection and FireDac Query(FDQuery1) to connect to the sqLite database.
Here is code.
FDQuery1.SQL.Text := 'select * from Invoice where Name = :Name';
FDQuery1.ParamByName('Name').AsString := '123';
FDQuery1.Open;
LinkListControlToField1.BindLink.FillList
I seems there is a new record inserted in the database but all fields are null.
What could be the problem ?
Now i am using
NEW_NAME:='dfddf';
SQL :='INSERT INTO INVOICE (Name) VALUES (:NEW_NAME)';
fdquery1.Close;
fdquery1.SQL.Text:= SQL;
FdQuery1.Open();
FDQuery1.Insert;
//Fdquery1.ParamByName('New_Name').AsString := NEW_NAME;
//fdquery1.SQL.Text:='INSERT INTO INVOICE (Name) VALUES (:NEW_NAME)';
fdquery1.FieldByName('Name').AsString := quotedstr(NEW_NAME);
//fdquery1.ExecSQL();
fdquery1.Post;
I am getting eerror message.
FireDac, Phys,Sqlite - 308 Can not open/define command, wiich does not return result sets. Hint use Execute? ExecSql metnod for non Select commands.
As you can see from the commented code I am trying the ExecSql but same error.
While SELECT sql statements cannot insert data into a table, records can be inserted/appended through TDataset descendents that are connected to a table via a SELECT sql statement.
For example:
FDQuery1.SQL.Text := 'select * from Invoice';
FDQuery1.Open;
NEW_NAME:='dfddf';
FDQuery1.Append; // or FDQuery1.Insert;
FDQuery1.FieldByName('Name').AsString := NEW_NAME;
// set other column values as needed
FDQuery1.Post;
If you prefer to use an INSERT:
FDQuery1.SQL.Text := 'INSERT INTO INVOICE (Name) VALUES (:NEW_NAME)';
NEW_NAME := 'dfddf';
FDQuery1.ParamByName('NEW_NAME').AsString := NEW_NAME;
// you will have to define parameters for each column
FDQuery1.ExecSQL;
Replace FDQuery1.Open to FDQuery1.ExecSQL;
But you statment "Select *..." dont Insert any record in database...

Resources