barnarp
asked on
TQuery EOF/BOF
Hi,
How do I know if the current record in a dataset is the first record, the last record, or somewhere in between?
I need to implement a previous / next button scenario for a dataset and need to disable the previous button if the dataset is on the first record, and similarly disable the next button if the recordset is on the last record.
Regards
How do I know if the current record in a dataset is the first record, the last record, or somewhere in between?
I need to implement a previous / next button scenario for a dataset and need to disable the previous button if the dataset is on the first record, and similarly disable the next button if the recordset is on the last record.
Regards
ASKER
The EOF BOF does notr seem to work, or maybe I am implementing it incorrectly;
If my TQuery dataset only returns one record, and the datasetis on the current record, then according to Delphi BOF and EOF is false.
If my TQuery dataset only returns one record, and the datasetis on the current record, then according to Delphi BOF and EOF is false.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Meikl is right. The dataset does need to move one step in either direction to determine if it's at the beginning or the end. Basically, since it's a SET, it technically doesn't even have a beginning and an end. But okay, recordsets are always ordered in some way and this ordered list can have a begin and end. But Delphi only knows about this once it tries to move past the begin or the end. Otherwise, it is assumed that you're just somewhere in the set.
Some databases support a recordcounter, that you might check. You could check if (YourQuery.RecNo=0) to check for the beginning or (YourQuery.RecNo=Pred(Your Query.Reco rdCount)) for checking the end of the set. But not all databases will support these methods, thus you could end up with -1 as value for YourQuery.RecNo, indicating that recordnumbers are NOT supported.
Some databases support a recordcounter, that you might check. You could check if (YourQuery.RecNo=0) to check for the beginning or (YourQuery.RecNo=Pred(Your
ASKER
I am using Oracle as a backend and will check out the counter.
If the query is first opened and i use:
First;
then BOF is true, but that doesnt help much because I dont know if it is also the last record in the set if there are only one record because EOF is false, even after I did move a step (first method)
If the query is first opened and i use:
First;
then BOF is true, but that doesnt help much because I dont know if it is also the last record in the set if there are only one record because EOF is false, even after I did move a step (first method)
in case of oracle u can include rownum into your select like
select t.*, rownum from table t
meikl ;-)
select t.*, rownum from table t
meikl ;-)
He could include rownum in his query but he still won't know if a row is the last row or not. Even worse, if he uses ADO to connect to the database then he could change the sorting order of the recordset and thus invalidate the rownum.
ASKER
using BDE
Wouldnt RecordCount work?
>Wouldnt RecordCount work?
not on a query, except you scroll to the end of the dataset,
which causes that all records will be fetched
not on a query, except you scroll to the end of the dataset,
which causes that all records will be fetched
Hi
>>I need to implement a previous / next button scenario for a dataset and need to disable the previous button if the dataset is on the first record, and similarly disable the next button if the recordset is on the last record.
do a move previous - if there is an error disable the button in your try exept?
Try
MyRecset.previous;
Except
On E: do
cmdPrevious.enabled:=false ;
End;
Likewise for the next button - Just an idea.
Also, even if there is no record count you can usually check for recordCount>0 (you cant tell how many recs there are as recordcount will often only return 0 or 1 - this is the case with SQLServer and other bigger databases as there is too much overhead/impractical to count the recs).
if Myrecset.recordcount>0 then
Begin
cmdPrevoius.enabled:=true;
cmdNext.enabled:=true;
end
else
Begin
cmdPrevoius.enabled:=false ;
cmdNext.enabled:=false;
End;
Just an idea..
Voodooman
>>I need to implement a previous / next button scenario for a dataset and need to disable the previous button if the dataset is on the first record, and similarly disable the next button if the recordset is on the last record.
do a move previous - if there is an error disable the button in your try exept?
Try
MyRecset.previous;
Except
On E: do
cmdPrevious.enabled:=false
End;
Likewise for the next button - Just an idea.
Also, even if there is no record count you can usually check for recordCount>0 (you cant tell how many recs there are as recordcount will often only return 0 or 1 - this is the case with SQLServer and other bigger databases as there is too much overhead/impractical to count the recs).
if Myrecset.recordcount>0 then
Begin
cmdPrevoius.enabled:=true;
cmdNext.enabled:=true;
end
else
Begin
cmdPrevoius.enabled:=false
cmdNext.enabled:=false;
End;
Just an idea..
Voodooman
ASKER
Hi,
I am tried all methods I know of using Delphi to find if the next/previous record exist from the position where I am in the recordset. These include solutions from all of you. I have tried the try except block for Prior and Next (cannot find previous method), as well as findnext/findprevious methods.
The only solution I can think of will be to use the TQuery.Recordset with a rownum field as part od the query as per kretzschmar's comment: select t.*, rownum from table t
The code:
Previous.Enabled := True;
Next.Enabled := True;
rownum := FieldByName('rownum').AsIn teger;
rowtot := RecordCount;
if rowtot = 1 then
begin
Next.Enabled := False;
Previous.Enabled := False;
end else
if rowtot = rownum then
begin
Next.Enabled := False;
end;
This works 100% for my query without an order by. But I need to use an order by in the query.
I thought that the rownum field would always assign '1' to the first row it fetched regardless of an order by or not.
Any ideas?
I am tried all methods I know of using Delphi to find if the next/previous record exist from the position where I am in the recordset. These include solutions from all of you. I have tried the try except block for Prior and Next (cannot find previous method), as well as findnext/findprevious methods.
The only solution I can think of will be to use the TQuery.Recordset with a rownum field as part od the query as per kretzschmar's comment: select t.*, rownum from table t
The code:
Previous.Enabled := True;
Next.Enabled := True;
rownum := FieldByName('rownum').AsIn
rowtot := RecordCount;
if rowtot = 1 then
begin
Next.Enabled := False;
Previous.Enabled := False;
end else
if rowtot = rownum then
begin
Next.Enabled := False;
end;
This works 100% for my query without an order by. But I need to use an order by in the query.
I thought that the rownum field would always assign '1' to the first row it fetched regardless of an order by or not.
Any ideas?
usual the rownum is given on the fetch by oracle after oracle has ordered it,
so it should doesn't matter if the result is sorted or not, except the client does the sort
did you tried an order by clause?
so it should doesn't matter if the result is sorted or not, except the client does the sort
did you tried an order by clause?
ASKER
I tried the order by clause,and instead of getting rownums:
1
2
3
I get
3
1
2
if the order by is used. I am using Oracle 806
No order by:
SELECT ROWNUM,c.*,l.* FROM
control_plant_state_change c,LOCATIONS l
WHERE c.INCIDENT_ID = 8501
AND c.PLANT_SLOT_ID = l.location (+)
works fine but if I put order by at the end of the statement:
ORDER BY l.description,c.advance,c. advancetot al
the rownum is mixed up
1
2
3
I get
3
1
2
if the order by is used. I am using Oracle 806
No order by:
SELECT ROWNUM,c.*,l.* FROM
control_plant_state_change
WHERE c.INCIDENT_ID = 8501
AND c.PLANT_SLOT_ID = l.location (+)
works fine but if I put order by at the end of the statement:
ORDER BY l.description,c.advance,c.
the rownum is mixed up
Yep. Order by will mess up the rownum in Oracle. Which is why it isn't a reliable solution...
The problem is that Delphi never knows that it's at the first or last record of a table unless you ask it to get past one of those borders...
About RecNo... Dataset types have a function IsSequenced of type boolean that tells if RecNo is supported or not. BDE-related datasets don't support this unless you use Paradox. ADO-based datasets do support RecNo, if the database driver used also supports it. (But it's not supported again when the dataset is filtered.)
I know it's a bit troublesome that Delphi just can't determine that easily if it's pointing to the first or last record or somewhere in the middle. There's no simple solution for this, though. But from experience I know that many users aren't bothered by it.
The problem is that Delphi never knows that it's at the first or last record of a table unless you ask it to get past one of those borders...
About RecNo... Dataset types have a function IsSequenced of type boolean that tells if RecNo is supported or not. BDE-related datasets don't support this unless you use Paradox. ADO-based datasets do support RecNo, if the database driver used also supports it. (But it's not supported again when the dataset is filtered.)
I know it's a bit troublesome that Delphi just can't determine that easily if it's pointing to the first or last record or somewhere in the middle. There's no simple solution for this, though. But from experience I know that many users aren't bothered by it.
ASKER
Thanks,
I need to find a solution somehow. I was thinking of keeping an array in sync with the recordset which keeps a primary key of the record I am currently on and a counter.
the problem is I have to keep the array in sync all the time as the user moves through the dataset which doesnt seem like a good solution.
I just cannot think of anything else. Even if I try to move the current record previous or next to test for the last record, it doesnt seem to work, it doesnt return a error if the next record is not found, it just stays on the same record. Maybe a BDE issue.
I need to find a solution somehow. I was thinking of keeping an array in sync with the recordset which keeps a primary key of the record I am currently on and a counter.
the problem is I have to keep the array in sync all the time as the user moves through the dataset which doesnt seem like a good solution.
I just cannot think of anything else. Even if I try to move the current record previous or next to test for the last record, it doesnt seem to work, it doesnt return a error if the next record is not found, it just stays on the same record. Maybe a BDE issue.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
One option could be that after you've opened the query then you first go to the first record and get a bookmark. Then move to the last record and get a second bookmark. Then, while you walk through the recordset you could check if you've hit one of those bookmarks. But personally I just dislike this method. I prefer to just use the TActionManager, add a TDataSetFirst, TDataSetPrior, TDataSetNext and TDataSetLast and just use these actions for the navigation. They will keep themselves completely up-to-date but with the same flaw as you noticed. When tou move to the last record, TDataSetNext and TDataSetLast will only be disabled when you try to get past this last record. Then link a button to this action and you're done...
ASKER
Thanks Voodooman, this sounds great. Will try it out.
Alex, I am not familiar with the TActionmanager, aslo sounds like a workable solution.
Regards
Alex, I am not familiar with the TActionmanager, aslo sounds like a workable solution.
Regards
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
However, remember that these are recordSETs... The first and last record is just meaningless for recordsets since it just depends on the order of the records. It's a SET, not a list.
BtnPrevious.Enabled := not YourQuery.BOF;
BtnNext.Enabled := not YourQuery.EOF;
Preferably you validate this by using an actionlist, but if you use an actionlist, you could just as well use the TDataSetNext and TDataSetPrior actions in the actionlist and connect them to your buttons and query. Then the whole system will manage itself.