Delphi Delete all records from FDTable - delphi

Iam trying to delete all records in my FDTable component using ,
mytable.Delete;
but no record is getting deleted.
can any one suggest me a way to delete all records in a FdTable.
EDIT
i modified it in this way,
for i := mytable.RecordCount - 1 downto 0 do
begin
mytable.Delete;
end;
mytable.Refresh;
but it is taking lot of time because there a lot rows in my fdtable.

Try
MyTable.EmptyDataSet;
There may be a bit more to do than that, but you don't say how you are populating MyTable in the first place.

Remove all the records in the underlying database table (the best way to do that will depend on the database) and call refresh just once.
If you must do it via TFdTable, use BeginBatch, do your deletes (without refresh), EndBatch and only then Refresh.
mytable.BeginBatch;
for i := mytable.RecordCount - 1 downto 0 do
begin
mytable.Delete;
end;
mytable.EndBatch;
mytable.Refresh;

I would suggest you use a stored procedure for the job and not SQL from your application. Stored procedures are simple to make and blazing fast because they operate directly on the server.
Just create a stored procedure for your table;
sp_deleteall
and do in it a single line of sql:
delete from mytable
From your application,drop a TFDStoredProc on the form, link it to your stored procedure on the server and just call on the procedure
`
sp_deleteall.ExecProc;
To know how many records were deleted just call, after the procedure execution :
ShowMessage(IntToStr(sp_deleteall.RowsAffected) + ' records were deleted.');
Try it ...

Try
as doing delete for all the rows would hamper the performance.
If that does not work then why don you create the dataset runtime and then free the object.

Form fastest to slowest. First two are commands you execute server side.
Close the table and do a SQL DDL command TRUNCATE TABLENAME; and then reopen. This requires exclusive access to the table.
Use a SQL DML command DELETE FROM TABLENAME;. This does not require exclusive access.
Use a loop client side. A lot slower and triggers a lot of events client side.

all you need to do for delete all records on a FDMemTable is
MyTable.Active := False;

Related

Can Firedac handle conditional SQL statements

Is there a way to use Firedac to handle conditional scenarios.
Master Table has a column called INVOICESCOUNT.
When an invoice is deleted successfully, then the INVOICESCOUNT is decreased.
For example, a SQL psuedo-code statement like this:
Delete From Invoices where INVOICE=500;
Update Customers SET INVOICECOUNT=INVOICECOUNT-1 WHERE Customer=1 (if prior statement returns 1 affected row);
I need it to be embedded within the same SQL statement instead of having the Delphi source code handling executing the 2 statements separately, after the first FDQuery returns a successful execution.
Thanks for any advice.
That's fine ?
I understood, lack of attention from me, in this case I could use the information from the DBMS itself, an example, if the DBMS is SQL server.
Delete From Invoices where INVOICE=500
IF ##ROWCOUNT=1
begin
Update Customers SET INVOICECOUNT=INVOICECOUNT-1
WHERE Customer=1
end.
If your DBMS doesn't allow it, I recommend you to use a stored procedure.

TClientDataSet.ApplyUpdates() doesn't apply updates

My Delphi project has a TAdoQuery accesssing data on an MS Sql Server 2014 server, and TClientDataSet that receives the AdoQuery data via a TDataSetProvider. This is created from a Project Template I set up.
Normally, I've found this set-up to work faultlessly, but with this particular project I'm having a problem: ApplyUpdates() fails silently and the Sql Server data is not updated. In my stripped down debugging project, the only code I have, apart from a button-click handler which calls it, is:
procedure TForm1.ApplyUpdates;
var
Errors : Integer;
begin
Errors := ClientDataSet1.ApplyUpdates(0);
Caption := IntToStr(Errors) + '/' + IntToStr(ClientDataSet1.ChangeCount);
end;
After this executes, the form's caption should be 0/0 of course but what it actually says is 0/1. So on the face of it, no errors occurred but the CDSs ChangeCount hasn't been reset to zero as it should be. My q is, how can ApplyUpdates return no errors but the server dataset doesn't get updated.
Fwiw, I added the ChangeCount display as part of my effort to debug the problem. But I'm afraid I haven't been able to follow what's supposed to be going on in the details of the "conversation" between the DataSetProvider and its DataSet to apply the updates on the server.
I ran into this problem recently on a quick project I rustled up without the precaution of setting an OnReconcileError handler, as queried by #mjn.
Once I'd set up the OnReconcileError handler, it was obvious that the problem was that the provider's TSqlResolver wasn't able to identify the row to update. Iirc, the message on the ReconcileError pop-up form was words to the effect of "Unable to locate record. No key specified."
So, first thing I tried was to include this in my CDS's AfterOpen:
CDS1.Fields[0].ProviderFlags := [pfInKey];
(CDS1.Fields[0] is the PK field of the dataset)
Contrary to my expectations, that didn't fix it. After scratching my head for a while, I had a careful look on the server and discovered that the recently-recreated table I was using did not have a primary key index.
Once I'd created the primary key index on the server, the ApplyUpdates problem went away.
However, what puzzles me about this is that prompted by your q, I dropped the primary key index on my server table and the problem hasn't started occurring again (!). I'm guessing this is due to some kind of cacheing effect on my machine but I don't really want to reboot it right now to investigate.

Firedac Query Field list not updated after Schema change

I am creating a temp table in SQL and then adding a new field to it. It seems Firedac is caching the field list for this temp table.
The following code gives me "FDQuery5: Field 'Available' not found."
FDQuery5.Connection := FDConnection1;
FDConnection1.ExecSQL('Select StockNo into #Temp from Stock');
FDQuery5.SQL.Text := 'Select * From #Temp';
FDQuery5.open;
FDConnection1.ExecSQL('Alter Table #Temp add Available Char(1)');
FDQuery5.Close;
FDQuery5.open;
ShowMessage(FDQuery5.FieldByName('Available').AsString);
using XE5 with Firedac.
I have tried Connection.RefreshMetadataCache and I have removed fiMeta from FetchOptions.Cache.
I can get Firedac to recognise the new field if I modify the SQL.Text. This is undesirable as my application will need modifying in quite a few places.
The query remains prepared after you call FDQuery5.Close. That means, it caches also result set structure. To prepare the query replace FDQuery5.Close with FDQuery5.Disconnect.

SQLite External Content FTS requires rebuild every time?

I set up an external content FTS4 virtual table in my app to allow full text search of an existing database. I also set up triggers similar to the documentation, so when my main content table is updated the FTS table gets new entries as well.
CREATE TRIGGER t2_bu BEFORE UPDATE ON t2 BEGIN
DELETE FROM t3 WHERE docid=old.rowid;
END;
CREATE TRIGGER t2_bd BEFORE DELETE ON t2 BEGIN
DELETE FROM t3 WHERE docid=old.rowid;
END;
CREATE TRIGGER t2_au AFTER UPDATE ON t2 BEGIN
INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;
CREATE TRIGGER t2_ai AFTER INSERT ON t2 BEGIN
INSERT INTO t3(docid, b, c) VALUES(new.rowid, new.b, new.c);
END;
The problem is that the triggers don't seem to actually update the index. I did a simple select * from the fts_transactions table and I see the new entries with correct text and rowid, but when actually searching they don't show up. To get them to show up I have to do a full rebuild like this:
INSERT INTO fts_transactions(fts_transactions) VALUES('rebuild');
Is this how it is supposed to work? I would have figured that the insert/update/delete into the FTS table would modify the index and not require me to rebuild it every time. After rebuilding the new entries show up just fine.
If that is the case, then is it okay to just add the rebuild command to the triggers? I am just worried that adding a new item will become slow once it has to rebuild the index with a few thousand entries on and older device...it seems that there should be a better way.
Is this how it is supposed to work?
yes, I put this line in each Triger
INSERT INTO fts_transactions(fts_transactions) VALUES('rebuild');

Delphi save all values from different datasources with 1 save button

I got this form;
I want to save al of those edits with 1 save button.
But the problem is that those fields all have a different datasource.
Is there somebody who can help me out?
Simple go over all data sources involved and use DataSource.DataSet.Post (assuming the DataSets are already in dsEdit/dsInsert mode).
Note: If your DBMS supports transactions, it would be wise to group all your posts in a single transaction, so that data/relations integrity will not be compromised e.g.:
MyConnObj.BeginTrans;
try
DataSource1.DataSet.Post;
DataSource2.DataSet.Post;
DataSource3.DataSet.Post;
MyConnObj.CommitTrans;
except
MyConnObj.RollbackTrans;
raise;
end;

Resources