Automatically update ages in Access

J

James Robinson

I need to create a list of approximately 200 contacts. These contacts need
to be arranged in age order. I wanted to know whether it is possible, in
Access to create a database contain my contacts dates of birth, that will
automatically update their age, as the year goes by. Any help welcomed.

Thanks in advance

James
 
G

Guest

Hi, James.

As you've noticed, updating ages becomes a tedius task if this value were to
be stored in the database for each record. That's why it's better to use a
"calculated value" to display this value in a form or report, instead.

If you were to store each contact's date of birth in a field named DOB, and
you created a bound form to display the age with a text box named "txtAge,"
then the following code would display the correct age for you:

Me!txtAge.Value = DateDiff("yyyy", DOB, Date()) + Int(Format(Date(), "mmdd") <
Format(DOB, "mmdd"))

To display all of the contacts sorted by age, try a query such as the
following:

SELECT *
FROM Contacts
WHERE (DateDiff("yyyy", DOB, Date()) + Int(Format(Date(), "mmdd") <
Format(DOB, "mmdd")))
ORDER BY DOB;

.... where Contacts is the name of the table.

HTH.

Gunny

See http://www.QBuilt.com for all your database needs.
See http://www.Access.QBuilt.com for Microsoft Access tips.

(Please remove ZERO_SPAM from my reply E-mail address, so that a message
will be forwarded to me.)

- - -
When you see correct answers to your question posted in Microsoft's Online
Community, please sign in to the Community and mark these posts, so that all
may benefit by filtering on "Answered questions" and quickly finding the
right answers to similar questions. Remember that the best answers are often
given to those who have a history of rewarding the contributors who have
taken the time to answer questions correctly.
 
O

onedaywhen

'69 Camaro said:
the following code would display the correct age for you:

Me!txtAge.Value = DateDiff("yyyy", DOB, Date()) + Int(Format(Date(), "mmdd") <
Format(DOB, "mmdd"))

Do you realize you are converting two DATETIME values to String,
comparing them and returning a Boolean, converting to an Integer then
adding to a Long? Here is a suggested alternative:

DateDiff("yyyy", DOB, Date())
+ CLng(DateSerial(Year(Date()), Month(DOB), Day(DOB)) > Date())
To display all of the contacts sorted by age, try a query such as the
following:

SELECT *
FROM Contacts
WHERE (DateDiff("yyyy", DOB, Date()) + Int(Format(Date(), "mmdd") <
Format(DOB, "mmdd")))
ORDER BY DOB;

Simply:

SELECT *
FROM Contacts
ORDER BY DOB;

Jamie.

--
 
G

Guest

Dont understand why you even need to calculate age. you can just sort
descending on the date of birth.
 
G

Guest

Hi, Jamie.
Do you realize you are converting two DATETIME values to String,
comparing them and returning a Boolean, converting to an Integer then
adding to a Long? Here is a suggested alternative:

I think you want to make a mountain out of a molehill. These are two
different ways to accomplish the same task. Each is about as efficient as
the other. Yours takes slightly longer to type, because it has more
characters. Apparently, you'd like to break each method down into pieces and
compare the merits. For what that's worth:
Do you realize you are converting two DATETIME values to String

It's not the whole nine yards. It's just an 8-byte string -- the
representation of four characters, "mmdd" " And yes, there are two values of
eight bytes each.
comparing them and returning a Boolean

Two operands of the same data type (the 8-byte strings) and a relational
operator yields a boolean value. I agree.
converting to an Integer

A VB boolean data type is represented by 0 and -1 in memory. The Int( )
function returns the integer portion of a number, so these 0 and -1 values
are being converted to four bytes that equal 0 and -1, respectively. Not a
huge undertaking in terms of CPU resources.
then adding to a Long?

A 4-byte integer added to a 4-byte long isn't as time-consuming an operation
as it was before 32-bit operating systems hit the market, when (short)
integers where generally two bytes. It took extra fetch and execute cycles
on the 8-bit and 16-bit operating systems, but adding a 4-byte integer to a
4-byte long these days takes the same number of cycles as adding two 4-byte
longs.

As for your method of calculating age, the DateSerial( ) function returns a
Variant of Date subtype. It also uses two operands (the 8-byte Dates) and a
relational operator to yield a boolean value. It also converts the VB
boolean data type to a 4-byte long. It also adds this to a Variant of long
subtype.

The major difference between the methods is that yours uses the DateSerial(
) function to build a date from three components and mine uses the format
function on two values. So how do they compare? To find out, I used the
method described on the following Web page:

http://support.microsoft.com/default.aspx?id=172338

Since the first time through the test loop generally takes longer than the
second, I ran through the loop twice for each method of determining age to
get an average (or to show a comparison, as you'll see further down). Since
the fraction of a second it took to execute the loop 100 times is so small, I
iterated through the loop 1,000,000 times. I used the following code for
each test:

String Test (to demonstrate how much time it takes to convert two Date/Time
data types to string, instead of just the month and day, even though this
would give an incorrect result):

age = DateDiff("yyyy", DOB, Date) + Int(CStr(Date) < CStr(DOB))

Mine:

age = DateDiff("yyyy", DOB, Date) + Int(Format(Date, "mmdd") < Format(DOB,
"mmdd"))

Yours:

age = DateDiff("yyyy", DOB, Date) + _
CLng(DateSerial(Year(Date), Month(DOB), Day(DOB)) > Date)

I ran the tests several times and found that your method was generally about
2% faster than the one I suggested:

String Test took 8.06158995067809 seconds
String Test took 7.75841929630721 seconds
Mine took 7.45051088895376 seconds
Mine took 7.48338992804951 seconds
Jamie's took 7.40612535950798 seconds
Jamie's took 7.39910686972786 seconds

So it's a tradeoff: faster to type (mine) or faster to execute (yours).
The break-even point for the average typist on a 2.5 GHz PC is about
25,000,000 executions. Higher than that and your method saves time, at a
rate of about 2%. Perhaps you come across tasks where 25,000,000 people (or
any group of items, for that matter) need to have their ages calculated, but
most of us don't fall into this category.

The bottom line is that it's hard to argue that such a tiny fraction of a
second in efficiency is really essential for the vast majority of
programmers. For most of us, it just doesn't matter one way or the other.
Pick one and move on to solve the next problem that really _can_ make a
significant difference in efficiency or cost.
Simply:

SELECT *
FROM Contacts
ORDER BY DOB;

Thanks for that. I need to do a better job editing out the irrelevant parts
when I copy/paste from one of my previous posts on a similar subject. Sorry
for any confusion to anyone reading that post of mine.

Since one good turn deserves another, may I suggest that you return to
another thread where you admonished someone's analogy of a bucket o' fish for
a table that holds records in an unsorted order, instead of calling it a
heap, which indicates a table without a clustered index. While you were
espousing the merits of Jet's use of clustered indexes and how Jet handles
them, you neglected to mention that Jet doesn't even support clustered
indexes.

P.S. I think far more people who ask questions in this newsgroup can relate
to a "bucket o' fish" than to a "heap" for an unordered set.

HTH.

Gunny

See http://www.QBuilt.com for all your database needs.
See http://www.Access.QBuilt.com for Microsoft Access tips.

(Please remove ZERO_SPAM from my reply E-mail address, so that a message
will be forwarded to me.)

- - -
When you see correct answers to your question posted in Microsoft's Online
Community, please sign in to the Community and mark these posts, so that all
may benefit by filtering on "Answered questions" and quickly finding the
right answers to similar questions. Remember that the best answers are often
given to those who have a history of rewarding the contributors who have
taken the time to answer questions correctly.
 
O

onedaywhen

'69 Camaro said:
These are two
different ways to accomplish the same task. Each is about as efficient as
the other.
Agreed.

Yours takes slightly longer to type, because it has more
characters.

I sorry but that's the worst defence I've heard in a long time!
Apparently, you'd like to break each method down into pieces and
compare the merits.

Thanks for the analysis, I appreciate your efforts. However, you
misunderstood me. I wasn't saying your approach was less efficient than
mine. I long ago gave up trying to write the most efficient VBA code in
performance terms, having discovered that 'logical correctness' and
maintainability are far more important. I was implying that the
numerous conversions in your code was hard for me to follow, making for
a counterintuitive approach, IMO. As I said, I was merely posting a
suggested alternative, one which I find more readable and intuitive.
Pick one and move on to solve the next problem that really _can_ make
a significant difference in efficiency or cost.

I disagree on the grounds of maintainability. I like to think of the
poor developer who will inherit my code to maintain.
Since one good turn deserves another, may I suggest that you return to
another thread <<snipped>>

Please, then, post your comments to the relevant thread so they can be
considered in context.

Jamie.

--
 
G

Guest

Hi, Jamie.
I sorry but that's the worst defence I've heard in a long time!

Obviously, I'm not a very good guesser about what prompted such a bizarre
post from you. I was trying to think of a logical explanation of why you
would specifically point out that my suggested code converts values to
strings and to integers, compares values with a logical operator, and adds
values to longs. For the life of me, the only thing that I could come up
with to explain such bizarreness is that you must think my suggested code is
inferior to your suggested code for each of the reasons you pointed out,
possibly due to perceived inefficiency of execution and coding, because you
didn't specifically mention or imply any other reason.
I long ago gave up trying to write the most efficient VBA code in
performance terms, having discovered that 'logical correctness' and
maintainability are far more important.

I assure you that the algorithm is logically correct. As for
maintainability, how many times have you or anyone else made even one change
to your algorithm that calculates age in years? Once it works and has been
through the design review and code walkthrough, no one has time to go back
and make changes that could possibly introduce new bugs, which would then
have to be tracked down. The likely maintainence to anticipate in that sense
would be if the name of the field "DOB" were changed. In that case, a global
search and replace with the new field name could make the necessary changes,
and no programmer would need to touch your code.

A valuable side effect of code maintainability is portability. Algorithms
that work well in one programming language are commonly ported to other
programming languages, as long as it doesn't require too much effort. Your
CLng( ), DateSerial( ), Year( ), Month( ), and Day( ) functions (or their
equivalents) -- as a group -- aren't nearly as common in other programming
languages as Int( ) and Format( ) (or their equivalents) are, so it would be
easier to port to and from other programming languages with minimal, if any,
effort with the code I suggested.
I was implying that the numerous conversions in your code was
hard for me to follow, making for a counterintuitive approach, IMO.

If you are following each conversion of a value, then I suggest you step
back from the trees. The forest is right in front of you. As for
"numerous," the code you suggested has one more conversion than the code I
suggested, or are you not counting the conversion of Date( ), an 8-byte data
type, to the year component of a date, the conversion of DOB, another 8-byte
data type, to the month component of a date, and the conversion of DOB to the
day component of a date? It's easy to overlook the trees (components) when
one looks at the forest (DateSerial( )).
As I said, I was merely posting a suggested alternative, one
which I find more readable and intuitive.

You would have written something more along the lines of "Here's another
method to calculate the age, which is easy for me to remember and may be even
easier to maintain," instead of words that came across as "Do you realize
your fly is open in front of the entire audience?!!" and then gave the
audience something else to gaze at to hide the embarassment that you
apparently think I should be feeling.
I disagree on the grounds of maintainability. I like to think of the
poor developer who will inherit my code to maintain.

Beauty is in the eyes of the beholder (i.e., a matter of opinion). C++ is
very easy to maintain for a C++ coder, but unreadable and unmaintainable by
many VB coders. The code I suggested is so maintainable that it's ported
code from nearly 30 years ago, which is older than VB and your suggested
code. That isn't to imply that it's any better. It's just evidence that
there are other people who came long before I did who thought it was
readable, maintainable and intuitive, and made sure it lives on. I was one
of the inheritors, and I found that it's readable and intuitive enough for
me, too. I've never had to make an effort to maintain this code because it
already works.
Please, then, post your comments to the relevant thread so they
can be considered in context.

My contributions are unnecessary, since the author of the analogy you
responded to with your indication that Jet uses clustered indexes -- even
though Jet doesn't support clustered indexes -- is more than up to the task
and has already posted an appropriate response to yours. Anything I add to
the thread would be akin to "You took the words right out of my mouth!" which
would be redundant.

We will be more productive assisting folks who need help with their
databases, rather than focus our efforts on people who would rather argue
about the most picayune thoughts than to help people.

HTH.

Gunny

See http://www.QBuilt.com for all your database needs.
See http://www.Access.QBuilt.com for Microsoft Access tips.

(Please remove ZERO_SPAM from my reply E-mail address, so that a message
will be forwarded to me.)

- - -
When you see correct answers to your question posted in Microsoft's Online
Community, please sign in to the Community and mark these posts, so that all
may benefit by filtering on "Answered questions" and quickly finding the
right answers to similar questions. Remember that the best answers are often
given to those who have a history of rewarding the contributors who have
taken the time to answer questions correctly.
 
J

James Robinson

Thanks all for your help on this. I will try it out today at work and let
you know finding.

James
 
O

onedaywhen

Hello again,
I'm not a very good guesser
I was trying to think of a logical explanation of why you
would specifically point out that my suggested code converts values to
strings and to integers, compares values with a logical operator, and adds
values to longs.

Don't presume, just ask. I'll share my thought process:

1. I read this:

SELECT *
FROM Contacts
WHERE (DateDiff("yyyy", DOB, Date()) + Int(Format(Date(), "mmdd") <
Format(DOB, "mmdd")))
ORDER BY DOB;

2. I thought, 'What the <expletive> is that supposed to do?'

3. I took a closer look.

4. You know the rest.
the only thing that I could come up
with to explain such bizarreness is that you must think my suggested code is
inferior

I've already made it clear that I did not think this and I and happy to
do so again. Consider this: if you hadn't posted such bizarre SQL, I
wouldn't have posted to this thread at all.
You would have written something more along the lines of "Here's another
method to calculate the age, which is easy for me to remember and may be even
easier to maintain,"

I suppose I could have, but it takes it slightly longer to type because
it has more characters said:
My contributions are unnecessary, since the author of the analogy
has already posted an appropriate response

I've since replied in that thread, suggesting a concept of clustered
indexes does exist for Jet tables based on terminology used by
Microsoft. The analogy's author has yet to post back so there is an
opportunity for you to get involved. I appealed for a consensus on 'Jet
tables support the equivalent of clustered indexes' and for suggestions
for a non-contentious term to refer to this concept, another
opportunity for you.

I enjoy discussion but to be productive one must be prepared for a bit
of give and take.

Jamie.

--
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top