2009年4月14日火曜日

ACCESS で生年月日から年齢を求める

1. 「人」テーブルの定義

以下のような、「人」テーブルがあるとする。

  1. id : 主キー
  2. 名前
  3. 性別id : 01 男、02 女
  4. 生年月日

090413-001

各々の「人」に対して、次のことを知りたい。

  • 現在の年齢
  • 今年度末に何歳になるか?

 

2. 年齢を求めるための関数を定義

現在の年齢を求める関数

生年月日から年齢を求めるには、

「今年の誕生日が来ているかどうか?」

がわかればよい。

そのため、

  1. 「指定された日付に、何歳になっているか求める」関数を定義し、
  2. 現在の日付を渡すことによって、
  3. 今の年齢を求める。

関数の定義は、

  • 「データベース > モジュール」

において、新規モジュールを作成する。

日付の関数については

を参考にした。

' ある誕生日の人が、指定した日付に何歳になっているか返す。
Function Age(birthday As Date, theDate As Date) As Integer
    If AfterThisYearsBirthday(birthday, theDate) Then
        Age = Year(theDate) - Year(birthday)
    Else
        Age = Year(theDate) - Year(birthday) - 1
    End If
End Function

' 指定された日付に今年の誕生日が来ているか?
Function AfterThisYearsBirthday(birthday As Date, theDate As Date) As Boolean
    If Month(birthday) < Month(theDate) Or _
        (Month(birthday) = Month(theDate) And Day(birthday) <= Day(theDate)) Then
        AfterThisYearsBirthday = True
    Else
        AfterThisYearsBirthday = False
    End If
End Function

 

年度末における年齢を求める関数

次に、年度末に何歳になっているか知りたい。

上記と同様に「指定された日付の年度末を返す」関数を書く。

' 指定された日付の年度末の日付を返す
Function Nendomatu(theDate As Date) As Date
    Const DATE_331 = "/3/31"
    If 4 <= Month(theDate) And Month(theDate) <= 12 Then
        Nendomatu = CDate(Year(theDate) + 1 & DATE_331)
    Else
        Nendomatu = CDate(Year(theDate) & DATE_331)
    End If
End Function

 

3. クエリから関数を呼び出す

上記の関数を、クエリから呼出すようにする。

  1. 「人」テーブルを対象にしたクエリを作成し、
  2. 「年齢、年度末の年齢」を求めたい列で、右クリック > ビルド... を選択し、
  3. 式ビルダを呼出す。

左下を見ると、「関数」フォルダに、先ほど作成したモジュール名が表示され、定義した関数が属しているのがわかる。

090413-003

それぞれ以下のように定義する。

年齢: Age([生年月日],Now())
年度末の年齢: Age([生年月日],Nendomatu(Now()))

クエリの結果。今日の日付は 2009.4.13 。

090413-002

 追記(2009.4.25) : 学校の学年においては、 4/1 生まれは早生まれになるので、年度末の翌日における年齢を求める。

年度末の年齢: Age([生年月日],nendomatu(Now())+1)

(参考: 法制執務コラム集「4月1日生まれの子どもは早生まれ?」)

 

4. クエリの中だけで計算するには

生年月日から年齢を計算する方法」には、次のようなクエリが書かれていた

年齢: IIf(Right(Format([誕生日],"yyyy/mm/dd"),5)>Right(Format(Now(),
"yyyy/mm/dd"),5),DateDiff("yyyy",[誕生日],Now())-1,DateDiff("yyyy",
[誕生日],Now()))

(via 生年月日の入力によって年齢を出したい。 --Access Club 超初心者 FORUM—)

うへぇ~、一行だと読みにくい… (+_+)

そもそも、これは何だろう?

Right(Format([誕生日],"yyyy/mm/dd"),5)

関数をテストしてみる。

    Debug.Print CDate("1/1")    ‘ 2009/01/01  
    Debug.Print CDate("1")      ‘ 1899/12/31 
    Debug.Print CDate("366")    ‘ 1900/12/31 
    Debug.Print CDate("0")      ‘ 0:00:00 

CDate のヘルプを見ると、

CDate    日付型 (Date)    任意の有効な日付式

「日付式」とは、

日付として解釈可能な式。… 日付と解釈できる文字列、

結果を見ると、そこまで無理に解釈しなくても…と言いたくなるような仕様。 ^^;

日付の内、「年」を省略すると、「現在の年」と解釈されるようだ。

 

5. シンプルな計算方法

生年月日から年齢を計算する簡単な計算式:ITpro」には、次のような計算式が書かれている。

(今日の日付-誕生日)/10000の小数点以下切捨て。

なるほど、「年月日」をわざと一連の数値として扱う方法のようだ。確かに、年月だけ見れば、年月を各々二桁で表現しているなら、誕生日が来ていれば、今日の日付よりも誕生日の数値が小さくなる。

先ほどの方法でパフォーマンスが悪ければ、こちらに変更しようかな。

ただし、次の注意点が述べられている。

「誕生日の前日が終了する瞬間(すなわち誕生日をむかえる午前0時00分の直前)に1歳を加えることになる」の部分の解釈には前日に1日加えると解釈される場合と当日に1日加えると解釈される場合の2種類があるようです。特に自治体においては前者で解釈される場合が多いとのことです。

(同上より)

ん?これは自治体の特殊ルールで、「年齢」と「年齢をどう解釈するか」とは別の話だよねぇ。