1 (edited by joshuA 2021-10-22 23:49:13)

Topic: Advice: a cfField V.S. an SQLExecute on forms

I am leading up to the subject of this topic, but I ran into another issue along the way...
.
I feel like someone has pointed this out to me before, but I skimmed my posted topics and none of them revealed anything.  So, it may have been in another thread.  Forgive me for asking this again (in that case), but I couldn't find it.
.
So a brief description of this project:  I'm tracking attendance records for employees.  I left out the details from my last posted topic, but I have those in place already.
.
The issue I'm currently having is getting the calculated field cfVacEarned to return the same values I get from the SQL query in my external browser.  I have included the screenshot which is what I'm expecting to see in MVD.  It appears that MVD is using the same value from the first record for all the other records.  What's the best way to fix this?
.
I could use some help with this part to get to my next question lol
.
I also wanted to point out this project as well because it has given me additional ideas for the one I'm working on.

Post's attachments

Attachment icon cfField-vs-SQLExecute.zip 340.07 kb, 211 downloads since 2021-10-23 

"Energy and persistence conquer all things."

2 (edited by derek 2021-10-23 00:52:20)

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi Joshua,
I've changed your calculated field to fix the problem (see attachment).
As the calculated field is held against the employee table and the fields used in the calculation are also on the employee table, you don't need to do a 'select' nor specify the table.
Derek.

Post's attachments

Attachment icon cfField-vs-SQLExecute fixed.zip 351.5 kb, 240 downloads since 2021-10-23 

3 (edited by sparrow 2021-10-23 09:04:02)

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi Derec, Joshua
Yes, Derec offered the simplest and most beautiful solution. Sometimes there are situations when a subquery is needed.


Let me explain briefly.
Calc. field - (SELECT strftime ('% Y', date ('now')) - strftime ('% Y', employee.dateHire) FROM employee)
In a normal query, it will print all values. What you yourself have seen.
But ... If we put it in the query as a calculated field (subquery)
SELECT empName, (SELECT strftime ('% Y', date ('now')) - strftime ('% Y', employee.dateHire) FROM employee) FROM employee
The result is not what we expect. You can also try it yourself.
As a calculated field (subquery), such a query can display ONLY ONE value. In this case, it is 6 which was calculated first.
In MySQL, such a query would throw an error (> Subquery returns more than 1 row).


But you can also bring an existing request to a working state.
Calc. field - (SELECT strftime ('% Y', date ('now')) - strftime ('% Y', employee.dateHire) FROM employee AS e WHERE e.id = employee.id)
Highlighted what needs to be added.
Each time it receives an id from the main request, the subquery does the calculation for it (one value).

4 (edited by joshuA 2021-10-24 02:17:17)

Re: Advice: a cfField V.S. an SQLExecute on forms

Greetings derek and sparrow,
.
Thank you both for these quick responses, and especially for the added explanations!
.
I believe I was heading in the direction that sparrow provided, but as he put it: derek has a much nicer solution for this problem.


I'm going back to the drawing board on this design because I'm having trouble deciding which fields should be stored and which only need to be calculated...
.
My thinking is that since these values are reset annually- they don't need be stored, but this is where I'm confused.  Should this be a deciding factor?
.
I guess the values could be (just as easily) reset at the beginning of each year.
.
How would you more experienced folks handle this? wink

Post's attachments

Attachment icon schema-question.png 13.29 kb, 94 downloads since 2021-10-24 

"Energy and persistence conquer all things."

5 (edited by derek 2021-10-24 15:34:24)

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi Joshua,
Ask 10 people and you'll get 10 different answers!
For me, I use calculated fields in scenarios such as:
1.  To avoid data redundancy (ie if you store 'price' and 'quantity', there is no need to store 'value' as it can be calculated (price * quantity).
2.  To update date/time dependent data automatically;  'days outstanding' ('now' - invoice_date) changes daily and if stored won't be correct until you run an update routine.
3.  Likewise, things such as 'the highest', the 'lowest', the 'most recent', 'next due on' etc seem ideally suited to calculated fields.
4.  To re-format data columns as you want them to display (for example, in conjunction with 'strftime' and 'printf' commands).
5.  To concatenate fields - for example,  'Mr', 'John' and 'Doe' to give 'Mr John Doe' (perhaps you're doing a mail-shot).
6.  Calculated fields can be used in FastReport and I find it simpler to re-format information in MVD (but that's just because I struggle with FastReport!).
Possible downsides are
1.  sometimes you need to add a 'tablegrid.dbupdate' statement in a script to refresh informaition.
2.  on 'maintenance forms', calculated fields are not calculated 'real-time' but only after the record is saved so you might need to do this independently via script if you want to see the result (ie price * qty) instantly.
Provided you get the functionality you need, then I'd go with what you find easiest!
Derek.

Re: Advice: a cfField V.S. an SQLExecute on forms

Hey Derek,
.
I was afraid that was an open, subjective question there.  But your response has given me some confidence in what I have going so far.  The project I have is working fine, but noticed those last two (unaddressed) items you mentioned.  This may have started my second guessing.
.
Thanks a lot for giving those different examples too!
.
Going back to this secondary project example, I added the month/year filter similar to the one from my other post.  I cannot get the dateTimePicker to start auto-checked in this project.
.
I have set and unset both checked and default checked properties, but this doesn't seem to do anything.  So, I tried writing it in a script to check it.  When I do this, the box is checked, but the tablegrid isn't filtered. (it is followed with searchButton.click too)
.
Not sure what's causing this, because it's working fine in my other main project so this is kinda minor...
.
But it leads to another (more important) request I have: while the dateTime filter is checked, when a new record is created, it removes the filter and shows all the records (even though it is still checked).
.
How can I keep the filter in place and prevent this from happening?  You can observe it with this project.

Post's attachments

Attachment icon cfField-vs-SQLExecute-v2.zip 332.46 kb, 193 downloads since 2021-10-25 

"Energy and persistence conquer all things."

7 (edited by sparrow 2021-10-25 10:53:21)

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi JoshuA, Derek.


JoshuA, the reason for this behavior is that records are filtered by the Search button and when the table is updated (adding a record),
the filter in the tablegrid does not exist.
To remember the filter, we will use the TableGrid.dbFilter property. Comments in the script.

With this solution, the tbFilterMonth Button can be removed from the search components in the Search button on the frmEmp form.

Post's attachments

Attachment icon cfF-vs-SQLEx-v2.1.zip 341.11 kb, 216 downloads since 2021-10-25 

Re: Advice: a cfField V.S. an SQLExecute on forms

Hey sparrow,
.
This works nicely, and I appreciate the example.  There are so many tricks- I have so much to learn with MVD!
.
Thanks again to you and derek.

"Energy and persistence conquer all things."

9 (edited by joshuA 2021-11-10 00:30:54)

Re: Advice: a cfField V.S. an SQLExecute on forms

Sub-thread title: Add child records to parent records listed in the TableGrid


Hi folks,
.
Instead of creating another thread, I'm continuing this one since it uses the same project.
.
So, I'm progressing a little further with it, but I could use some more advice before I implement it into the working project...
.
The interface is working as desired:

  • Once a department group is selected, then the Apply to Group button allows for a mass update of attendance records for each one in that group.

  • The cyan textbox is showing the parent IDs to add new child records for.

  • I'm not sure if it's necessary to create a separate (identical) form for this case, but I did.

  • The MessageBoxes are temporarily shown, of course, as an example.

.
I don't recall anyone else on the forum doing or requesting this.  But as of right now, I'm thinking of using a script to loop a SQLExecute for each ID in the tableGrid to create the appropriate child records.
.
This is my idea for how to approach it, but I wanted to get some outside opinions first.  Is this a good way (notice any flaws?), or suggest a better (more simple) approach?
.
Thanks!

Post's attachments

Attachment icon cfField-vs-SQLExecute_v4.1.zip 341.6 kb, 222 downloads since 2021-11-10 

"Energy and persistence conquer all things."

10 (edited by derek 2021-11-10 13:39:37)

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi Joshua,
Had a very quick look and there are a couple of things.
1.  I'm not sure why you are building a tstringlist of employee ids.  Why don't you simply loop through the ids in frmmain.tablegrid1 as they are already there?  Please see the attachment.
2.  I don't know how many updates you'll be doing when your program is live, but if there are a lot, then you might want to use 'beginsqlitetransaction / commitsqlitetransaction' as part of your update procedure as it will be appreciably faster.
3.  I probably wouldn't bother with a separate form for the updates - it's basically the rows in frmmain.tablegrid that drives it and it would keep your application that bit tighter - but it's marginal.
Derek.

Post's attachments

Attachment icon josh.zip 352.9 kb, 209 downloads since 2021-11-10 

11 (edited by joshuA 2021-11-13 00:16:48)

Re: Advice: a cfField V.S. an SQLExecute on forms

Awesome.  I really appreciate that master derek!
.
Well I was experimenting with the tstrings.  I know it was an overkill, but it helped me demonstrate my example too.  Still learning the MVD ropes.  [edit]I forgot to mention that, your example showed me how to do it the right way. wink[/edit]
.
I found some examples using the sqltransaction commands, and they were updating 1000+ records at a time.  I don't foresee that many for this project, but thank you for mentioning it.
.
Another thing I notice in your example- you remove the public empID integer.  I tend to do this in most of my projects (I'm guessing it's unnecessary tho).  Whenever I go between forms, it is how I reference which parent ID was selected.  And sometimes I use the cfID=id method too.
.
Thank you again!

"Energy and persistence conquer all things."

Re: Advice: a cfField V.S. an SQLExecute on forms

Okay, so moving forward.  I'm starting to build multiple save buttons depending on where the frmAtt (is called) originated from.  What's the best way to handle this scenario?
.
I found this post doing a similar thing with labels, but I'm stepping into unfamiliar territory here...
.
Depending on where the form is called, I want to hide certain controls because they're not applicable.  The project I've attached is a simple example using ShowMessages to demonstrate my idea.
.
Currently, I have two different places where the button is called, and I need to hide (or do something special) for each case.  The Apply To Group button is one instance. When the new record button is called from the frmEmp it needs to do something different.
.
To me, this seems like I may be over-complicating things, and I feel like there might be a better way to approach this.  Would someone offer extra advice here?  I would appreciate it.  Any thoughts or ideas?

Post's attachments

Attachment icon cfField-vs-SQLExecute_v5.zip 346.97 kb, 210 downloads since 2021-11-17 

"Energy and persistence conquer all things."

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi joshuA, Hi Derek

Your option has the right to life.
But each button has events:
- OnClick
- OnAfterClick
That allows you to customize the execution of the called form (hide elements, block input, enter values ...) and, after execution,
return the default values.

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi Joshua, Hi Sparrow,
If you want REALLY simple (which I always do - LOL!), the easiest way is just to use two forms (see the attachment).
So in your example, frmmain.button5 calls frmatt-1 and frmemp.button2 calls frmatt-2.(or whatever you want to call them).
It's very 'clean' and means that you don't have to switch certain options on or off, make certain fields / buttons visible or not etc (so no script required).  It also means that you don't have to remember to 're-set' everything when you leave either.
Creating a 'duplicate' form is pretty easy and takes about 20 seconds.  I usually:
1.  note the height and width of the 'source' form
2.  right-click and 'select all' and then 'copy'
3.  create a new, empty form
4.  set the height and width equal to the size of the 'source' form
5.  right-click and select paste.
n.b:  if you do it this way, it will also copy procedures (if any) associated with objects on the 'source' form - so be sure to remove them from the new form.
Derek.

Post's attachments

Attachment icon v5.1.zip 359.63 kb, 213 downloads since 2021-11-17 

15 (edited by joshuA 2021-11-19 21:24:56)

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi sparrow, derek
.
I appreciate both inputs!
.
derek:
Your answer is where I was headed in the earlier project when you suggested not using a separate form.  big_smile  I realize that you were not aware of where I was heading with the project at the time, but I'm appeased that you are now confirming my original direction for it.  And as always, for your example project.
.

If you want REALLY simple...

[edit]
I too am always seeking the simplest way.  The amount of scripting that it takes to hide and show form components during different stages is what prompted me to ask this question.  I start to loose focus on what is happening mad and get bogged down.
.
Thanks also to for stepping through your thought process for this method.
[/edit]

"Energy and persistence conquer all things."

Re: Advice: a cfField V.S. an SQLExecute on forms

Okay- I may be back-stepping a little bit here...
.
So I'm wondering if it would be more simple, since I'm already using a DateTime field to represent both Date (and optional Time) together, using a single tableGrid column...  In a previous post, I was trying to separate these two.  And it is working perfectly, BTW.
.
The new column format is set to:

TNxdateColumn(frmEmp.TableGrid1.Columns[0]).FormatMask := 'mm/dd/yyyy HH:MM';

.
I don't care about seconds (which shows by default) so I would like to eliminate that part.  Is there a way to conditionally format this further to only include a range of times?  I'm only interested in showing the times within a window. Specifically between 06:00 and 18:00, otherwise I only wish to show the date (and exclude the time portion if possible) from the column.  Which in the case for this project, the time is set to 00:00 when it's not needed.
.
Example:
Date  /  Time   Column
11/02/2021
11/05/2021 06:12
11/10/2021 13:00
11/13/2021
11/16/2021 15:00
11/20/2021
.
Is there an easy way to achieve this, or should I just keep them separated?

"Energy and persistence conquer all things."

Re: Advice: a cfField V.S. an SQLExecute on forms

Hello Joshua,
There's possible advantages to doing it either way.  Personally (but without knowing the details of your project), I'd keep them separate for a couple of reasons.
1.
It's already working!
2.
If you use a datetime field, I think there is an issue with being able to format the datetime field on the edit screen to only show hours and minutes (dd/MM/yyyy  HH:mm doesn't display correctly for me when you run it).  That then means that you have an inconsistency with how you want to display it in the tablegrid, so not so user-friendly.
Formatted as separate fields, the 'date' can be formatted on the edit screen (dd/MM/yyyy) and the 'time' can be formatted on the edit screen as HH:mm correctly - and it's then consistent with the display in the tablegrid..
3.
It may also be useful in case you need to do any analysis.  For example, what are my busiest times?   With the time held separately, you can simply sort the grid by time to see how the frequency is spread (whereas if held as a datetime, it would sort by date and then time).
With regard to showing just the date if the time is out of your specified window (06.00 - 18.00 and the time has been set to 00:00), I'd simply use a calculated field (no big surprise there - LOL!).
Please see the attached as a suggestion.
Derek.

Post's attachments

Attachment icon datetime.zip 336.62 kb, 199 downloads since 2021-11-25 

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi derek,
.
Just to recap on my latest post in here.  I'm not loosing my mind (yet).  I had this figured out already.  But now my users are asking for date and time ranges, so I had to revisit some past posts here too.  That's the reason for the seemingly revisit to this issue (again).
.
I experimented with your solution some, and it is possible to use a cfField to do what I needed (thanks to your example). However, one thing I noticed with my second requirement mentioned below; you cannot share form controls being used for the Date/Time field when the date and time are being used separately.
.
So I come to this conclusion (guideline):

  • When there will always be a date with an optional time, it can be done using a single date/time database field.

  • When both date and time are optional, this requires the date field and time field separately in the database.

  • There probably are some other cases to be included here too...

.
I wasn't aware of these, and it always bugs me when I open the database externally and see a perfectly good date/time combination using any of the three MVD fields: date/time, date, or time.  I'll just have to mentally ignore my OCD here. lol
.
Anyways, my apologies for stating the obvious to those more experienced.  And as always derek, I appreciate your examples and advice.

"Energy and persistence conquer all things."

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi again,
Is there a way, by scripting, to invoke that MVD tool tip that shows for the not null fields?

This field is required. Please enter a value for the field.

I found threads describing how to translate the message and other alternatives for indicating required fields.  But I would like to keep it consistent with the other buttons that use the button Save action if possible.
.
Thanks!

Post's attachments

Attachment icon 7811_show-not-null-tooltip.zip 354.08 kb, 199 downloads since 2021-11-30 

"Energy and persistence conquer all things."

20 (edited by sparrow 2021-11-30 13:31:08)

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi Derek, joshuA


If you are talking about a pop-up window then:
ShowHint (Form2.Edit1, 'This is a required field');
or
ShowHint(Form2.Edit1,'This is a required field',-1,-1,5000) -where 5000 Hide after time
And you can do the field check yourself. )))

Re: Advice: a cfField V.S. an SQLExecute on forms

Thank you sparrow, that's precisely what I am after.  I'm glad this can be done. big_smile

"Energy and persistence conquer all things."

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi all,
.
I wasn't planning to check for duplicates on the groups, but I wanted to see how far I could go... not very far neutral
.
The other duplicate checking examples that I found were dealing with a single table.  And this takes it a bit further, or either I'm over-complicating it.
.
I started the code, but this may not be the ideal approach.
.
Thanks in advance for having a look.

Post's attachments

Attachment icon v6.0.zip 348.24 kb, 181 downloads since 2021-12-03 

"Energy and persistence conquer all things."

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi all
Your project is growing and it will be more and more difficult to deal with your code and thoughts,
And it takes time. I started ... and you find, guess, add.
Be specific about your question.


for i := 0 to frmmain.tablegrid1.rowcount -1 do
  begin
    if (SQLExecute('SELECT count(id) FROM attendance WHERE id_employee = '''+frmmain.tablegrid1.Cells[0,i]+''' and aDate = ... and id_attCode = ...)  = 0 then
      SQLExecute('INSERT INTO attendance (aDate, ....
  end;

Re: Advice: a cfField V.S. an SQLExecute on forms

Hi sparrow,
.
Thanks for responding.  Sorry for not being more specific in my last post.
.
There are two cases for creating attendance records:
1. A single employee with one or multiple dates
2. A group of employees with a single date (filtered by Department)
.
Everything is working fine so far.  But I'm attempting to check for duplicates prior to creating any records when it applies to multiple employees.
.
This is declaration and field checking portion:

procedure frmAtt_Button2_OnClick (Sender: TObject; var Cancel: boolean);
var
    i, j : integer;
    isDuplicate : boolean;
begin                                                     
    // Check that the attendance code has been selected
    if frmAtt.ComboBox1.Text = '' then
    begin
        ShowHint(frmAtt.ComboBox1,'This field is required. Please enter a value for the field.');
        Exit;
    end;

Looping through each employee that has been filtered (in the tableGrid)

    
    for i := 0 to frmmain.tablegrid1.rowcount -1 do
    begin
        isDuplicate := False;

       
Now I'm attempting to check all attendance records for each employee's for duplicate fields

        for j := 0 to SQLExecute('SELECT count(*) FROM attendance WHERE id_employee = '+inttostr(frmmain.tablegrid1.dbindextoid(i))) do
        begin

       
This is where I get lost because I'm not sure how to construct a query that will pull out the pieces for each attendance record.  Because any query that I can come up with returns all the results at once.  I don't know how to control this.  And the ID's don't match the loop counter either, so it's hard to specify which record to use for testing.  And I don't know how to control the flow from SQL.

            
            // This doesn't work, but it's an example of the pieces that I need to test against on the entry form.

            //if (SQLExecute('SELECT aDate, id_attCode FROM attendance WHERE id_employee = '+inttostr(frmmain.tablegrid1.dbindextoid(i))) = frmAtt.dtpDate.sqlDate) then

            // How to check for duplicates on frmAtt.dtpDate, frmAtt.tbAttCode
            // IF THEY EXIST, SIMPLY SKIP THEM...
            // isDuplicate := True;

        end;

After testing for duplicates, then insert the new fields ONLY if none of them were duplicated

        if not isDuplicate then
           //SQLExecute('INSERT INTO attendance (aDate, aTime, aTime2, attNote, id_attCode, id_employee) VALUES('+frmAtt.dtpDate.sqlDate+', '+frmAtt.dtpTime.sqlTime+', '+frmAtt.dtpTime2.sqlTime+', "'+frmAtt.Memo1.Text+'", "'+frmAtt.tbAttCode.Text+'", "'+inttostr(frmmain.tablegrid1.dbindextoid(i))+'")');
    end;
    frmAtt.Close;
    frmEmp.TableGrid1.dbUpdate;
end;

.
I've created a loop inside a loop to filter (and test) each attendance record for each employee in the group (tableGrid list).  At least that's the idea.  It might not be the ideal way for doing this in MVD.  So this is where I'm getting stuck.
.
This is a bit fragmented, but it's hard to highlight code sections unless I just rely on comments.
.
Many thanks!

"Energy and persistence conquer all things."

25 (edited by sparrow 2021-12-03 14:27:01)

Re: Advice: a cfField V.S. an SQLExecute on forms

I wrote you a start example. )
That's all you need for On_Click

for i := 0 to frmmain.tablegrid1.rowcount -1 do
  begin
    if (SQLExecute('SELECT count(id) 
    FROM attendance 
    WHERE id_employee = '''+frmmain.tablegrid1.Cells[0,i]+''' 
    and aDate = (verified date )
    and id_attCode = (verified code))  = 0 THEN
      SQLExecute('INSERT INTO attendance (aDate, ....
  end;

For - Loop through the TableGrid lines
If - condition
WHERE id_employee = '''+frmmain.tablegrid1.Cells[0,i]+''' and aDate = ... and id_attCode = ... - a condition to search for a record (ID empl) with such data and code
If count(id)=0 - (no entries) THEN - SQLExecute('INSERT INTO attendance (aDate, ....


The SQLExecute function can only return one value.
In an SQL query, all that needs to be checked is entered into WHERE,
and if such a record exists, you get count (id) -the number of records.
It is convenient that you do not get a NULL answer.