How to calculate a person's age "as of" a reporting date — Oracle Analytics

Oracle Analytics Cloud and Server

Welcome to the Oracle Analytics Community: Please complete your User Profile and upload your Profile Picture

How to calculate a person's age "as of" a reporting date

Received Response
1880
Views
8
Comments
SPowell42
SPowell42 Rank 5 - Community Champion

Hi everyone, I'm stuck on a problem in OBIEE that's (easily) been stumping me for 10 years, and I still don't have a decent solution. High level, I have a fact table that joins with a "date" dimension and a person dimension (along with other dims that don't play a part in this). The person dimension stores the person's birth date.

Assuming a person will turn 18 years old on Jan 15th, I need to produce a report that looks like the following:

Reporting Date          Age in Years

1/13/2016                    17

1/14/2016                    17

1/15/2016                    18

1/16/2016                    18

...

Here's what I've tried so far:

1. OBIEE function TIMESTAMPDIFF(SQL_TSI_YEAR, birth_date, reporting_date) : this returns inaccurate ages. It shows the person turning 18 way before they hit their birthdate

2. OBIEE function TIMESTAMPDIFF using any of the other SQL_TSI intervals - haven't found satisfactory solution with this that works properly for leap years, etc.

3. EVALUATE function - I tried setting up an AGE column on the employee dimension, and then using an EVALUATE function to calculate the age using database functions I know work ("trunc(months_between(birth_date, reporting_date) / 12)". This might work ok for metrics, but I couldn't get this to work properly on dimensions. OBIEE doesn't set the query to "group by age" so I get invalid SQL if for example I try to show counts of employees by age.

I'm pretty out of ideas...I've been fighting with this issue for a decade at this point but haven't found a good solution. Does anyone have any other ideas?

Thanks,

Scott

Answers

  • [Deleted User]
    [Deleted User] Rank 2 - Community Beginner

    Edit: never mind timestamdiuff rounds that way...

    StackOverflow has an answer: sql server - How to calculate age (in years) based on Date of Birth and getDate() - Stack Overflow

  • Thomas Dodds
    Thomas Dodds Rank 8 - Analytics Strategist

    Use of information drives physical design ... why not use the database (and functions you know work) to update the age attribute column in the dimension nightly in your post-load etl processing?

  • [Deleted User]
    [Deleted User] Rank 2 - Community Beginner

    I assume he meant his reporting date (point in time) is something you can choose from a prompt so calculating it physically won't work.

  • Thomas Dodds
    Thomas Dodds Rank 8 - Analytics Strategist

    "I try to show counts of employees by age" +  "haven't found satisfactory solution with this that works properly for leap years, etc."

    those statements alone beg a properly formed physical structure.  The simple approach is a snapshot fact that stores either the detailed employee & age at a snapshot date or it stores the aggregate (pre-binned) counts or both structures are built.

    The benefit of a snapshot is the ability to compare those binned counts over time

    at 1/1/2015  30% are under 20 yrs old

    at 1/1/2016  24% are under 20 yrs old

    that comparison fetches a few rows and does the lite-logical calculation to find the % Change and Variance. 

  • [Deleted User]
    [Deleted User] Rank 2 - Community Beginner

    Until we know what his needs are in detail - could be the one could be the other could be something completely different yet again with - for example - the calculation being executed on request variables passing values into the RPD

  • SPowell42
    SPowell42 Rank 5 - Community Champion

    Hi all, just to follow up on some details in my original post that seemed to be too vague:

    1. On our database, I can perfectly calculate the age as trunc(months_between(birth_date, reporting_date) / 12). I simply want OBIEE to be able to call this same function

    2. Users can select any valid date in the "reporting date" dimension to report against. This dimension is at the day level and has 10+ years of history.

    3. When a user selects a reporting date, the report needs to show the age of the employees "as of" that reporting date

    Given #2 and #3 above, I can't really store ages. We've got 60,000+ employees - trying to update a SCD type 2 dimension or something with this nightly would make our employee dimension blow up to hundreds of millions of rows. Thus my desire to have OBIEE call the calculation from the database using the EVALUATE function.

    Having said this, I've defined AGE on my employee dimension as:

    Evaluate('trunc(months_between(%1, %2) / 12)' as integer,  "Scott Test"."Dim Date"."Reporting Date",  "Scott Test"."Dim Employee Detail"."Birth Date" )

  • SPowell42
    SPowell42 Rank 5 - Community Champion

    Hi all, just to follow up on some details in my original post that seemed to be too vague:

    1. On our database, I can perfectly calculate the age as trunc(months_between(reporting_date, birth_date) / 12). I simply want OBIEE to be able to call this same function

    2. Users can select any valid date in the "reporting date" dimension to report against. This dimension is at the day level and has 10+ years of history.

    3. When a user selects a reporting date, the report needs to show the age of the employees "as of" that reporting date

    Given #2 and #3 above, I can't really store ages. We've got 60,000+ employees - trying to update a SCD type 2 dimension or something with this nightly would make our employee dimension blow up to hundreds of millions of rows. Thus my desire to have OBIEE call the calculation from the database using the EVALUATE function. (p.s. also, I've greatly simplified our issue....besides "age in years" we also need decimal age, plus there are 6 or 8 other dates we track elapsed time against that all share this same issue).

    Having said this, I defined an AGE attribute on my employee dimension as:

    Evaluate('trunc(months_between(%1, %2) / 12)' as integer,  "Scott Test"."Dim Date"."Reporting Date",  "Scott Test"."Dim Employee Detail"."Birth Date" )

    When I tested this the other day when I wrote the post, this was not working properly. Today it magically does seem to be ok. Unsure if this is due to caching (which I turned off) or something else...I'll continue to play with this and see if it works ok in all cases.

    Thanks!

    Scott

  • SPowell42
    SPowell42 Rank 5 - Community Champion

    p.s. the SQL being produced using the evaluate is correct:

    SELECT SUM(T940405.ANNUAL_PAY_RATE) AS c1,

      T939141.DIM_DATE_KEY AS c2,

      TRUNC(months_between(T939141.DIM_DATE_KEY, T938790.BIRTH_DATE) / 12) AS c3

    FROM DIM_EMPLOYEE_DETAIL T938790,

      DIM_DATE T939141,

      FCT_JOB_JED T940405 /* FCT_JOB_Day_level */

    WHERE ( T938790.EMPLOYEE_DETAIL_KEY = T940405.EMPLOYEE_DETAIL_KEY

    AND T939141.DIM_DATE_KEY            = DATE '2016-01-01'

    AND T939141.DIM_DATE_KEY BETWEEN T940405.EFF_START_DATE AND T940405.EFF_END_DATE )

    GROUP BY T939141.DIM_DATE_KEY, TRUNC(months_between(T939141.DIM_DATE_KEY, T938790.BIRTH_DATE) / 12)

    When I tried this the other day, the SQL coming out was not including the "Trunc(months_between..." part in the group by clause, causing a SQL error. Today this is working, again unsure why. Adding in additional dimensions now to see if that breaks it somehow.

    Thx,

    Scott