Let’s create a date dimension with pure Oracle SQL

Posted: February 24th, 2009 | Author: Uli Bethke | Filed under: ETL, Oracle, SQL for Analysis | Tags: , , | 2 Comments »

The script below will create a date dimension in just one SQL statement. We don’t use performance-killer nonsense such as cursors, functions etc.

We just pick a start date and the number of days we want to create and with a bit of magic of the Connect By clause and the NUMTODSINTERVAL function we do the whole thing in 14 lines of code.

SQL> CREATE TABLE d_date AS
  2  SELECT
  3     n AS Date_ID,
  4     TO_DATE('31/12/2007','DD/MM/YYYY') + NUMTODSINTERVAL(n,'day') AS Full_Date,
  5     TO_CHAR(TO_DATE('31/12/2007','DD/MM/YYYY') + NUMTODSINTERVAL(n,'day'),'DD') AS Days,
  6     TO_CHAR(TO_DATE('31/12/2007','DD/MM/YYYY') + NUMTODSINTERVAL(n,'day'),'Mon') AS Month_Short,
  7     TO_CHAR(TO_DATE('31/12/2007','DD/MM/YYYY') + NUMTODSINTERVAL(n,'day'),'MM') AS Month_Num,
  8     TO_CHAR(TO_DATE('31/12/2007','DD/MM/YYYY') + NUMTODSINTERVAL(n,'day'),'Month') AS Month_Long,
  9     TO_CHAR(TO_DATE('31/12/2007','DD/MM/YYYY') + NUMTODSINTERVAL(n,'day'),'YYYY') AS Year
 10  FROM (
 11  select level n
 12  from dual
 13  connect by level <= 2000
 14  );

Table created.

Pretty much self-explanatory. The above will create a date dimension starting at 01/01/2008 and ending at 01/01/2008+2000 days = 22/06/2013.

If you want to read up on NUMTODSINTERVAL have a look at the documentation. Intervals are also very well explained in Tom Kyte's Expert Oracle Database Architecture. It is worth buying just for this chapter.


2 Comments on “Let’s create a date dimension with pure Oracle SQL”

  1. #1 Bob said at 10:28 pm on May 6th, 2009:

    I simplified the SQL and added week day and quarter dimensions.

    CREATE TABLE d_date AS
    SELECT
    n AS Date_ID,
    CurrDate AS Full_Date,
    TO_CHAR(CurrDate,’DD’) AS Days,
    TO_CHAR(CurrDate,’Mon’) AS Month_Short,
    TO_CHAR(CurrDate,’MM’) AS Month_Num,
    TO_CHAR(CurrDate,’Month’) AS Month_Long,
    TO_CHAR(CurrDate,’YYYY’) AS Year,
    TO_CHAR(CurrDate,’Day’) as Week_Day,
    TO_CHAR(CurrDate,’Q') AS Quarter
    FROM (
    select level n, TO_DATE(’31/12/2007′,’DD/MM/YYYY’) + NUMTODSINTERVAL(level,’day’) CurrDate
    from dual
    connect by level <= 2000)
    ;

  2. #2 Kiran said at 9:58 pm on December 9th, 2009:

    Uli Bethke,

    Excellent SQL.. very usefull..


Leave a Reply