views:

237

answers:

3

I have faced a very strange situation here. I am accessing database (MDB) through JET. I use DBGrid and DBNavigator to allow user access it. Dataset is created using TADOQuery component, with the following query:

SELECT *, (DateDiff ('y',[Birth Date], Now())) AS [Age] FROM TableName

It works fine. But whenever I press Refresh button on DBNavigator the result of this calculated field becomes wrong. For example, if normally I have 7 shown on Age column, after I press Refresh it becomes 40149, 7 changes to 40149, 6 changes to 40150, 0 to 40156 etc. In order to view correct result I need to reopen query again.

Anybody can help?

A: 

Try this interval parameter instead :

SELECT *, (DateDiff ('yyyy',[Birth Date], Now())) AS [Age] FROM TableName

Here's what "intervals" stands for :

yyyy    Year
q   Quarter
m   Month
y   Day of Year
d   Day
w   Weekday
ww  Week
h   Hour
n   Minute
s   Second
Pmax
I need to calculate age in days
Tofig Hasanov
A: 

I did a test with your previous comment, and I also have the same error.

I think it's a bug somewhere in the Navigator or in jet.

When you hit refresh on the nav. the 40149 shown is the date representation as a double without the calculated stuff. It seem to use only the first column found and to display it.

If you try to cast it to a string, the displayed data is still a datetime.

Select *, ' ' & DateDiff(.......) as [Age] From table1;

When I use a column of type String or Number first in the calculated field, the result is displayed as it should. You can try :

SELECT *,  mid(id & (DateDiff ('y',[madate], Now())), len(id) + 1) AS [Age] FROM Table1

Or :

SELECT *,  (id-id) + (DateDiff ('y',[madate], Now()))  AS [Age] FROM Table1

This is pretty ugly, but it does the trick..

Pmax
+3  A: 

Try the following, which will return the age in days.

SELECT *, CINT(Now()-[Birth Date]) as AGE FROM TableName

For age in years use:

SELECT *, INT((Now()-[Birth Date]) / 365.242199) as AGEYRS from TableName

(note, CINT rounds, INT doesn't)

The reason that this works is that ACCESS stores its date/time in a similar method as Delphi, as a float where the integer portion is the number of days since a specific day and the fractional part as the fractional portion of that day ( 0.25 = 6 am, 0.50 = noon, etc). Thus if you want to know the differences between two days, just take the differences between the day numbers... for number of years, divide this by the number of days in a year.

EDIT

Another option here would be to create a calculated field in Delphi and perform the logic there. In your onCalculated event you would code something like the following:

procedure TForm1.ds1CalcFields(DataSet: TDataSet);
begin
  DataSet.FieldByName('CALCDATE').AsInteger := 
    Trunc((Date - DataSet.FieldByName('BIRTH DATE').AsDateTime) / 365.242199);
end;

EDIT

And yet a third method. Rather than allow the refresh to work as it currently does, override the behavior and force a close/reopen of the dataset by using the onClick of the navigator:

procedure TForm1.dbnvgr1Click(Sender: TObject; Button: TNavigateBtn);
begin
  if Button = nbRefresh then
    begin
      ds1.Close;
      ds1.Open;
    end;
end;
skamradt
This is what I first thought and I've tried that. It didn't work. ADO throw and error when you use CINT when you refresh with the dbnavigator. And the INT function does nothing because 40149 is a INT...
Pmax
Only because the date was entered without a time. The internal structure is still a float, so the int is needed. I edited my answer and added an alternate way using a Delphi calculated field which works properly.
skamradt