FDQuery Interface to Progress Bar - DELPHI - mysql

I am trying to make an interface for my insert Query, this moves a huge number of data.
DataModule2.FDQueryInsertExceed.Close;
DataModule2.FDQueryInsertExceed.Sql.Clear;
DataModule2.FDQueryInsertExceed.Sql.Add('INSERT IGNORE INTO tblLogs');
DataModule2.FDQueryInsertExceed.Sql.Add('SELECT * FROM tbllogs WHERE Datetimelog <
date_sub(NOW(), INTERVAL 1 month);');
DataModule2.FDQueryInsertExceed.ExecSQL;
Dont know where to put the progress bar, and also if you can post here a link with full manual of FD Components.

FireDAC includes the TFDEventAlerter, which allows applications to receive certain notifications
from the SQL backend, including some progress notifications. Unfortunately, it does not support
MySQL so you are going to have to devise a way of updating your ProgressBar yourself.
The main problem with doing it yourself is that after you call DataModule2.FDQueryInsertExceed.ExecSQL,
it will not return until ExecSQL has completed execution, so you can't get any opportunity
to update your ProgressBar until then and by the time that you do, the SQL backend has finished
working.
So, realistically, the best you can do is to snip your db inserted up into a series of batches and
update the ProgressBar after each one. Before you start the batches, you can do a SELECT COUNT(*)
which should tell you at least approximately how many rows will be involved overall, so that
you can calculate the percentage complete after each batch. I say "approximately"
in case new inserts are required while your ExecSQL is executing,
The simplest place to start is by determining how many of your inserts can be executed in
a few hundred milliseconds, parameterize your SQL to match that and use a TTimer to start
each batch. So your TTimers's OnTimeer wou look something like
TForm1.OnTimer1.OnTimer(Sender : TObject);
var
S : String;
begin
S := 'INSERT IGNORE INTO tblLogs SELECT * FROM tbllogs WHERE Datetimelog ... //
// complete as necessary to add a starting DateTime and an ending one for the batch
DataModule2.FDQueryInsertExceed.Sql.Text := S;
DataModule2.FDQueryInsertExceed.ExecSQL;
// Update ProgressBar here
end;
An enhancement (but a step change in difficulty) would be to call DataModule2.FDQueryInsertExceed.ExecSQL
in a background thread and, once it has executed, execute code in the main, VCL thread, not in the background thread, to update
the ProgressBar. However, exactly how to do that is way beyond the scope of this answer.

Related

How to Insert data from datagridview Rows to mysql database in vb.net using stored procedure

Im stucked. I am trying to insert data from the grid to the database.But I'm stucked.
Slugsie's comment is pertinent, but needs to go a little further:
You're actually clearing the entire parameters collection before you call the procedure. If it were a house, you went to all the effort to build the whole thing, then at the last minute you demolish it and show the customer a cleared lot
Don't clear the Parameters collection at all. Add all the parameters to it OUTSIDE the loop, then inside the loop, set the values:
'general pattern
cmd.Parameters.AddWithValue("param1", "...")
cmd.Parameters.AddWithValue("param2", "...")
cmd.Parameters.AddWithValue("param3", "...")
cmd.Parameters.AddWithValue("param4", "...")
For Each something In somethingElse
cmd.Parameters("param1").Value = something.Whatever1
cmd.Parameters("param2").Value = something.Whatever2
cmd.Parameters("param3").Value = something.Whatever3
cmd.Parameters("param4").Value = something.Whatever4
cmd.Execute...
Next something
That's the pattern you should be adopting
Though jmc also makes a useful comment; you could make your life a lot easier by
adding a DataSet type file to your project
open it, right click the surface, choose Add TableAdapter
when configuring the wizard for the adapter, say you want to use stored procedures for your select, insert, update etc
wire the procedures up to the relevant table columns
Now in code you can save data just by a single line or two:
Dim t as New WhateverTableAdapter
t.Update(yourWhateverDatatable) 'the WhateverDataTable is bound to a grid, the user has edited the rows in it by changing the grid
That Update() call will perform any necessary use of the Insert/Update/Delete procedures depending on if the datarow in the table is an Added, Modified or Deleted state

Why mongoDB takes less time for Select than Fetch time?

I have collection with 10mill rows without any index.In this case system should read whole table ?
When i use eplain statement then it shows
db.employees.find({hundreds2:{$lt:1}},{}).explain();
"nscannedObjects" : 10000000,
"n" : 105
millis" : 6027
It works fine.
But i am using java to process query . Here is code
whereQuery = new BasicDBObject();
whereQuery.put("hundreds2",new BasicDBObject("$lt", rangeQuery));
timer.start();
setupMongoDBReadQuery(arrForRange[posOfArr]);
cursor = coll.find(whereQuery);
timer.stop();
this.selectTime= timer.elapsed();
timer.start();
while (cursor.hasNext())
{
numberOfRows++;
cursor.next();
}
timer.stop();
this.fetchTime= timer.elapsed();
this.totalOfSelAndFetch=this.selectTime+this.fetchTime;
But after test result .I got this information
selTime=2 fetchTime=6350 numRows105 TotalTime6352
selTime=0 fetchTime=6290 numRows471 TotalTime6290
selTime=0 fetchTime=6365 numRows922 TotalTime6365
Why fetch time is more than select .As per my knowledge ,while loop is just printing data . Why it taking so much time to print and how mongoDB select number of rows with 0 or 2 millSec?
Same experiment i did in MySQL with similiar code and results are
selTime=6302 fetchTime=1 numRows105 TotalTime6303
selTime=6318 fetchTime=1 numRows471 TotalTime6319
selTime=6387 fetchTime=2 numRows922 TotalTime6389
MongoDB uses lazy evaluation with cursors. That means in many cases when you start a MongoDB query which returns a cursor, the query doesn't get executed yet.
The actual selection happens when you start requesting data from the cursor.
The main reason is that this allows you to call methods like sort(by), limit(n) or skip(n) on the cursor which can often be processed much more efficiently on the database before selecting any data.
So what you measure with the "fetch time" is actually also part of the selection.
When you want to force the query to execute without fetching any data yet, you could call explain() on the cursor. The database can't measure the execution time without actually performing the query. However, in actual real-world use, I would recommend you to not do this and use cursors the way they were intended.

Show MessageBox if no records for report

I already asked a Question Here.
My this question is just a step ahead to same problem.
I have a delphi code which works perfectly for calling report.
But, now I wanted to show a MessageBox before opening rpt file.
I tried to query it separately for record count and then decide for MessageBox. But, this solution is having a worst case where a aprticular report's query itself takes 3 mins to execute and then again querying while opening rpt it takes 30 sec to load (in second query it takes less time may be because of some data may present in buffer/temp place,etc.).
qPODPhy.close;
qPODPhy.SQL.clear;
qPODPhy.SQL.text :='select * from ViewName';
qPODPhy.Open;
If qPODPhy.RecordCount < 1 Then
MessageBOx('No data To Display...');
Else
Begin
crRep.Somproperties := Initialization
.
.
.
CrRep.SQLQuery := qPODPhy.SQL.text;
crRep.action := 1
End
My Question is :
How can I show a MessageBox if no record is going to present for particular view's output.
OR
Is there a method where I can open the dataset of .rpt file in delphi code and just check the count of records and make the decision? In short, is there some property of crystalreport component which can do this?
You can do a select count(*) separately, that is much faster.
Or maybe select only one record: SELECT TOP 1 ....
And, as RBA suggested, you can try putting that SELECT COUNT in a stored procedure for even more speed.
Just experiments with these methods to see if/when you've gained enough speed.
Are you pushing the data ? You can probably use ReadRecords method of the ReportDocument and check Rows.Count property. If the report is retrieving the data the you can use the NoData event of ReportDocument.

Lazarus, can't get DB Update working. How can I preview whats being submitted?

Hi I have a form setup using TMySQL51Connection, TSQLTransaction & TSQLQuery modules, it retrieves info from the DB without issue but I'm having problems with updates.
The DB is pretty large so I'm starting with just the 1st couple of rows, once they're working I'll extend the query.
My TSQLQuery.UpdateSQL is as follows
UPDATE table SET
ContactFirst = :ContactFirst,
ContactSur = :ContactSur
WHERE AccountID = :AccountID
Then I have a button in my form, the onCLick event contains:
begin
accSelect.Edit;
accSelect.Post;
accSelect.ApplyUpdates;
dbTransaction.CommitRetaining;
sqlbl1.Caption := accSelect.UpdateSQL;
end;
Clicking the buttons does precisely nothing with the DB, it generates no error messages, just updates the caption on sqlbl1. Is there anyway to preview what Lazarus is sending to the DB with values included so I can track down whats going wrong?
I tried adding a logging event to the SQLConnection but couldn't work out how to get it generating logs.
From my experience, the Edit, Post and ApplyUpdates methods are used in conjunction with a TClientDataSet. In that case you would simply assign new values to the fields in the CDS (after navigating to the record you want to Edit) then Post those changes (no need for an Update SQL statement). Something like this...
MyCDS.Edit;
MyCDS.FieldByName('ContactFirst').Value := sContactFirstName;
MyCDS.FieldByName('ContactSur').Value := sContactSurname;
MyCDS.Post;
MyCDS.ApplyUpdates;
Alternatively, you could use a Query component, write the UPDATE SQL into the SQL property, and use ExecSQL or whatever method has been implemented for that component (there are many database access components that each have their own idiosyncrasies)
Here's some code off the top of my head. Please excuse me but I'm not familiar with Lazarus specifics - it's basically Delphi code.
MySQLQuery.SQL.Clear;
MySQLQuery.SQL := 'UPDATE MyTable
SET ContactFirst = :ContactFirst,
ContactSur = :ContactSur
WHERE AccountID = :AccountID';
MySQLQuery.Params.ParamByName('ContactFirst').Value := sContactFirstName;
MySQLQuery.Params.ParamByName('ContactSur').Value := sContactSurname;
MySQLQuery.Params.ParamByName('AccountID').Value := iAccountID;
try
MySQLQuery.ExecSQL;
ShowMessage('Update succeeded');
except on e: Exception do
ShowMessage(e.Message);
end;
So it might be that you've ended up using half of both methods and neither of them completely.

Using logic within an update and returning updated fields using as few queries as possible

I'm writing a video game in javascript on a server that saves info in a mysql database and I am trying to make my first effect attached to simple healing potion item. To implement the effect I call a spells table using spell_id and it gets a field called effect containing the code to execute on my server. I use the eval() function to execute the code in the string. In order to optimize the game I want to run as few queries as possible. For this instance (and I think the answer will help me evaluate other similar effects) I want to update the 'player' table which contains a stat column like 'health' then I want it to add n which will be a decreasing number 15 then 250 ms later add 14 then 13 until that n=1 the net effect is a large jump in health then smaller and smaller accomplishing this is relatively easy if the player's health reaches his maximum allowed limit the effect will stop immediately...
but I'd like to do a single update statement for each increase rather than a select and an update every 250ms to check if health > max_health and make sure the player's health doesn't go above his max health. So to digress a bit I'd like a single update that given this data
player_id health max_health
========= ====== ==========
1 90 100
will add 15 to health unless (max_health-health) < 15... in this case it should only add 10.
An easier solution might be
if I could just return health and max health after each update I update it I don't mind doing a final
pseudo code
if health > max_health
update health set health = max health
So if anyone could explain how to return fields after an update that would help.
Or if anyone could show how to use logic within the update that would also help.
Also, If I didn't give enough information I'm sorry I'd be glad to provide more I just didn't want to make the question hard to understand.
update health
set health = least(max_health, health +<potion effect>)
where player_id = ...
EDIT
For your other question : normally, i think that update returns the number of affected rows. So if you try to update health when health is already = max_health, it should return 0.
I'd know how to do this in php, for example, but just said you where using javascript... so ?
http://dev.mysql.com/doc/refman/5.6/en/update.html
UPDATE returns the number of rows that were actually changed. The
mysql_info() C API function returns the number of rows that were
matched and updated and the number of warnings that occurred during
the UPDATE.
Use the ANSI standard CASE function, or the mysql only least function as in the other answer
UPDATE player
SET health = CASE WHEN health + [potion] > max_health
THEN max_health
ELSE health + [potion]
END CASE
WHERE player_id = [player_id]