{"id":469,"date":"2009-11-20T17:48:09","date_gmt":"2009-11-21T00:48:09","guid":{"rendered":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/?p=469"},"modified":"2009-11-20T17:48:09","modified_gmt":"2009-11-21T00:48:09","slug":"dynamodb-time-dimension-table-with-merge","status":"publish","type":"post","link":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/2009\/11\/20\/dynamodb-time-dimension-table-with-merge\/","title":{"rendered":"DynamoDB: Time Dimension table with MERGE"},"content":{"rendered":"<p>So, even with my disclaimer note on the last blog, the DynamoDB developers slapped me around a bit for suggesting using a <a href=\"http:\/\/www.nicholasgoodman.com\/bt\/blog\/2009\/11\/20\/dynamodb-built-in-time-dimension-support\/\">view for a Time Dimension<\/a>.  The Time Dimension is the most important dimension table and should be an actual table, not a view.  Creating the table allows us to perform all kinds of optimizations like star joins, bitmap indexes on attributes, etc.  Probably wouldn&#8217;t be that big of a deal for a tiny fact table (&lt; 5million records) but you&#8217;ll want CREATE TABLE if you want good performance.<\/p>\n<p>Good news is, that we can use our exact same table function (with fiscal year offset)<\/p>\n<blockquote><p>select * from table(applib.fiscal_time_dimension (2000, 1, 1, 2009, 12, 31, 3))<\/p><\/blockquote>\n<p>to populate and keep our Time Dimension TABLE up to date.<\/p>\n<p>If you use a TABLE, it&#8217;s 2 steps:<\/p>\n<ol>\n<li>CREATE TABLE : &#8220;dim_time&#8221;<\/li>\n<li>POPULATE TABLE : &#8220;merge into dim_time&#8221;<\/li>\n<\/ol>\n<p>We&#8217;ll be using another great tool in the DynamoDB \/ LucidDB toolkit, the <a href=\"http:\/\/pub.eigenbase.org\/wiki\/LucidDbUpsert\">MERGE<\/a> statement.  The <a href=\"http:\/\/pub.eigenbase.org\/wiki\/LucidDbUpsert\">MERGE<\/a> statement is a logical UPSERT.  It checks to see if key is already present.  If it is, we UPDATE the table.  If it isn&#8217;t, we INSERT it into the table.  I&#8217;ll go into more detail at some point in the future as MERGE is crucial for keeping dimensions up to date.<\/p>\n<p>Let&#8217;s create our Time Dimension table:<\/p>\n<pre>create table dim_time (\nFISCAL_YEAR_END_DATE DATE\n, FISCAL_YEAR_START_DATE DATE\n... ABBREVIATED ...\n, TIME_KEY DATE\n, TIME_KEY_SEQ INTEGER\n,constraint dim_time_pk primary key (day_from_julian));<\/pre>\n<p>NOTE: We&#8217;ve abbreviated the statements, but all the columns are used in the actual scripts.  We also should add bitmap indexes on YR, MONTH, etc columns.<\/p>\n<p>We&#8217;ve now got a TABLE that matches the VIEW we created in the previous blog.  We&#8217;ve made day_from_julian as our PK, and we&#8217;ll use this date as our key for the MERGE statement.  We can run this query as many times as we like and it will always just keep our &#8220;dim_time&#8221; table up to date.<\/p>\n<pre>merge into dim_time using (select * from\n      table(applib.fiscal_time_dimension (2000, 1, 1, 2010, 12, 31, 3))) src\non dim_time.day_from_julian = src.day_from_julian\nwhen matched then UPDATE set\nFISCAL_YEAR_END_DATE=src.FISCAL_YEAR_END_DATE\n,FISCAL_YEAR_START_DATE=src.FISCAL_YEAR_START_DATE\n... ABBREVIATED ...\n,TIME_KEY=src.TIME_KEY\n,TIME_KEY_SEQ=src.TIME_KEY_SEQ\nwhen not matched then INSERT\n(FISCAL_YEAR_END_DATE\n , FISCAL_YEAR_START_DATE\n... ABBREVIATED ...\n , TIME_KEY\n , TIME_KEY_SEQ)\nvalues(\nsrc.FISCAL_YEAR_END_DATE\n , src.FISCAL_YEAR_START_DATE\n... ABBREVIATED ...\n , src.TIME_KEY\n , src.TIME_KEY_SEQ);<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>So, even with my disclaimer note on the last blog, the DynamoDB developers slapped me around a bit for suggesting using a view for a Time Dimension. The Time Dimension is the most important dimension table and should be an actual table, not a view. Creating the table allows us to perform all kinds of [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1],"tags":[],"_links":{"self":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts\/469"}],"collection":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/comments?post=469"}],"version-history":[{"count":0,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/posts\/469\/revisions"}],"wp:attachment":[{"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/media?parent=469"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/categories?post=469"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.nicholasgoodman.com\/bt\/blog\/wp-json\/wp\/v2\/tags?post=469"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}