1. 程式人生 > >維度模型資料倉庫(十二) —— 多路徑和參差不齊的層次

維度模型資料倉庫(十二) —— 多路徑和參差不齊的層次

(五)進階技術
        7. 多路徑和參差不齊的層次
        本篇討論多路徑層次,它是對單路徑層次的擴充套件。上一篇裡資料倉庫的月維度只有一條層次路徑,即年-季度-月這條路徑。在本篇中加一個新的級別,推廣期,並且加一個新的年-推廣期-月的層次路徑。這時月維度將有兩條層次路徑,因此具有多路徑層次。本篇討論的另一個主題是不完全層次,這種層次在它的一個或多個級別上沒有資料。

        增加一個層次
        執行清單(五)- 7-1裡的指令碼給month_dim表新增一個叫做campaign_session的新列,並建立campaign_session_stg過渡表。圖(五)- 7-1顯示新增後的模式。
USE dw;

-- 增加促銷期列
ALTER TABLE month_dim ADD campaign_session CHAR (30) AFTER month;

-- 建立促銷期過渡表
CREATE TABLE campaign_session_stg (
    campaign_session CHAR(30),
    month CHAR(9),
    year INT(4)
);
清單(五)- 7-1
圖(五)- 7-1
        為了理解推廣期如何工作,看一下表(五)- 7-1的推廣期示例。

Campaign Session

Month

2005 First Campaign

January-April

2005 Second Campaign

May-July

2005 Third Campaign

August-August

2005 Last Campaign

September-December

 表(五)- 7-1


        每個推廣期有一個或多個月。一個推廣期也許並不是正好一個季度。也就是說,推廣期級別不能上捲到季度(推廣期的上一個級別)。但是推廣期可以上卷至年級別。
        2014年推廣期的資料如下,並儲存在/root/data-integration/campaign_session.csv檔案中。
CAMPAIGN SESSION,MONTH,YEAR
2014 First Campaign,1,2014
2014 First Campaign,2,2014
2014 First Campaign,3,2014
2014 First Campaign,4,2014
2014 Second Campaign,5,2014
2014 Second Campaign,6,2014
2014 Second Campaign,7,2014
2014 Third Campaign,8,2014
2014 Last Campaign,9,2014
2014 Last Campaign,10,2014
2014 Last Campaign,11,2014
2014 Last Campaign,12,2014

        通常不會從一個文字檔案直接向資料倉庫表裝載資料,而是使用一個過渡表。清單(五)- 7-1裡包含了建立campaign_session_stg表的指令碼。
        現在可以執行清單(五)- 7-2裡的指令碼把2014年的推廣期資料裝載進月維度。使用圖(五)- 7-2到圖(五)- 7-6所示的Kettle步驟也可完成同樣的裝載。
USE dw;

TRUNCATE TABLE campaign_session_stg;

LOAD DATA INFILE '/root/data-integration/campaign_session.csv'
INTO TABLE campaign_session_stg
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY ""
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(
  campaign_session
, month
, year
);

UPDATE month_dim a,
    campaign_session_stg b 
SET 
    a.campaign_session = b.campaign_session
WHERE
    a.month = b.month AND a.year = b.year;

COMMIT;
清單(五)- 7-2
圖(五)- 7-2
圖(五)- 7-3
圖(五)- 7-4
圖(五)- 7-5
圖(五)- 7-6
        使用下面的查詢語句確認month_dim表裝載正確。
mysql> select month_sk, month_name, year, campaign_session
    ->   from month_dim
    ->  where year = 2014;
+----------+------------+------+----------------------+
| month_sk | month_name | year | campaign_session     |
+----------+------------+------+----------------------+
|      169 | January    | 2014 | 2014 First Campaign  |
|      170 | February   | 2014 | 2014 First Campaign  |
|      171 | March      | 2014 | 2014 First Campaign  |
|      172 | April      | 2014 | 2014 First Campaign  |
|      173 | May        | 2014 | 2014 Second Campaign |
|      174 | June       | 2014 | 2014 Second Campaign |
|      175 | July       | 2014 | 2014 Second Campaign |
|      176 | August     | 2014 | 2014 Third Campaign  |
|      177 | September  | 2014 | 2014 Last Campaign   |
|      178 | October    | 2014 | 2014 Last Campaign   |
|      179 | November   | 2014 | 2014 Last Campaign   |
|      180 | December   | 2014 | 2014 Last Campaign   |
+----------+------------+------+----------------------+
12 rows in set (0.36 sec)

注意,應該在每年的一月份裝載推廣期的CSV檔案,而且必須在裝載month_end_sales_order_fact表之前裝載。


        增加2014年的資料
        在“(五)進階技術-5. 快照”中,已經把2015年2月的資料匯入進了month_end_sales_order_fact表。現在需要執行清單(五)- 5-2裡指令碼或執行對應的Kettle轉換,新增2014年全年的資料。必須每月執行一次指令碼。別忘了把系統日期設定為每次執行前的下月1號。當裝載完這些新增的資料後(總共12次),使用下面的SQL查詢month_end_sales_order_fact表,確認它已經正確裝載。
mysql> select
    ->     month,
    ->     year,
    ->     product_name,
    ->     month_order_amount mo_amt,
    ->     month_order_quantity mo_qty
    -> from
    ->     month_end_sales_order_fact a,
    ->     month_dim b,
    ->     product_dim c
    -> where
    ->     a.order_month_sk = b.month_sk
    ->         and a.product_sk = c.product_sk
    ->         and year = 2014
    -> order BY month , year , product_name;
+-------+------+-----------------+---------+--------+
| month | year | product_name    | mo_amt  | mo_qty |
+-------+------+-----------------+---------+--------+
|     1 | 2014 | LCD Panel       | 1000.00 |   NULL |
|     2 | 2014 | Hard Disk Drive | 1000.00 |   NULL |
|     3 | 2014 | Floppy Drive    | 2000.00 |   NULL |
|     4 | 2014 | LCD Panel       | 2500.00 |   NULL |
|     5 | 2014 | Hard Disk Drive | 3000.00 |   NULL |
|     6 | 2014 | Floppy Drive    | 3500.00 |   NULL |
|     7 | 2014 | LCD Panel       | 4000.00 |   NULL |
|     8 | 2014 | Hard Disk Drive | 4500.00 |   NULL |
|     9 | 2014 | Floppy Drive    | 1000.00 |   NULL |
|    10 | 2014 | LCD Panel       | 1000.00 |   NULL |
+-------+------+-----------------+---------+--------+
10 rows in set (0.00 sec)

注意 11月和12月沒有資料。


        層次查詢
        本節的兩個查詢例子分別用於月維度的兩個層次路徑。第一個查詢如清單(五)- 7-3所示,沿年-季度-月路徑鑽取。這個查詢與上篇“維度層次”裡的鑽取查詢類似,除了這個查詢查的是month_end_sales_order_fact表,“維度層次”裡的查詢查的是sales_order_fact表(對應的Kettle轉換步驟也與上篇的類似,這裡從略)。結果如圖(五)- 7-7所示。
USE dw;
SELECT 
    product_category, time, order_amount, order_quantity
FROM
    ((SELECT 
        product_category,
            year,
            1 month,
            year time,
            1 sequence,
            SUM(month_order_amount) order_amount,
            SUM(month_order_quantity) order_quantity
    FROM
        month_end_sales_order_fact a, product_dim b, month_dim c
    WHERE
        a.product_sk = b.product_sk
            AND a.order_month_sk = c.month_sk
            AND year = 2014
    GROUP BY product_category , year) UNION ALL (SELECT 
        product_category,
            year,
            month,
            quarter time,
            2 sequence,
            SUM(month_order_amount) order_amount,
            SUM(month_order_quantity) order_quantity
    FROM
        month_end_sales_order_fact a, product_dim b, month_dim c
    WHERE
        a.product_sk = b.product_sk
            AND a.order_month_sk = c.month_sk
            AND year = 2014
    GROUP BY product_category , year , quarter) UNION ALL (SELECT 
        product_category,
            year,
            month,
            month_name time,
            3 sequence,
            SUM(month_order_amount) order_amount,
            SUM(month_order_quantity) order_quantity
    FROM
        month_end_sales_order_fact a, product_dim b, month_dim c
    WHERE
        a.product_sk = b.product_sk
            AND a.order_month_sk = c.month_sk
            AND year = 2014
    GROUP BY product_category , year , quarter , month)) x
ORDER BY product_category , year , month , sequence;
清單(五)- 7-3
圖(五)- 7-7
        第二個查詢如清單(五)- 7-4所示,鑽取推廣期的年-推廣期-月層次。此查詢和前一個有相同的結構,除了是按推廣期而不是季度分組。結果如圖(五)- 7-8所示。
USE dw;
SELECT 
    product_category, time, order_amount, order_quantity
FROM
    ((SELECT 
        product_category,
            year,
            1 month,
            year time,
            1 sequence,
            SUM(month_order_amount) order_amount,
            SUM(month_order_quantity) order_quantity
    FROM
        month_end_sales_order_fact a, product_dim b, month_dim c
    WHERE
        a.product_sk = b.product_sk
            AND a.order_month_sk = c.month_sk
            AND year = 2014
    GROUP BY product_category , year) UNION ALL (SELECT 
        product_category,
            year,
            month,
            campaign_session time,
            2 sequence,
            SUM(month_order_amount) order_amount,
            SUM(month_order_quantity) order_quantity
    FROM
        month_end_sales_order_fact a, product_dim b, month_dim c
    WHERE
        a.product_sk = b.product_sk
            AND a.order_month_sk = c.month_sk
            AND year = 2014
    GROUP BY product_category , year , campaign_session) UNION ALL (SELECT 
        product_category,
            year,
            month,
            month_name time,
            3 sequence,
            SUM(month_order_amount) order_amount,
            SUM(month_order_quantity) order_quantity
    FROM
        month_end_sales_order_fact a, product_dim b, month_dim c
    WHERE
        a.product_sk = b.product_sk
            AND a.order_month_sk = c.month_sk
            AND year = 2014
    GROUP BY product_category , year , quarter , month)) x
ORDER BY product_category , year , month , sequence
;
清單(五)- 7-4
圖(五)- 7-8
        不完全層次
        在一個或多個級別上沒有資料的層次稱為不完全層次。例如在特定月份沒有推廣期,那麼月維度就具有不完全推廣期層次。本節說明不完全層次,還有在推廣期上如何應用它。
        下面是一個不完全推廣期(在/root/data-integration/ragged_campaign.csv檔案裡)的例子,2014年1月、4月、9月、10月、11月和12月沒有推廣期。
CAMPAIGN SESSION,MONTH,YEAR
NULL,1,2014
2014 Early Spring Campaign,2,2014
2014 Early Spring Campaign,3,2014
NULL,4,2014
2014 Spring Campaign,5,2014
2014 Spring Campaign,6,2014
2014 Last Campaign,7,2014
2014 Last Campaign,8,2014
NULL,9,2014
NULL,10,2014
NULL,11,2014
NULL,12,2014

        先使用下面的命令把campaign_session欄位置空,然後執行清單(五)- 7-5裡的指令碼向month_dim表裝載推廣期資料。
USE dw;
UPDATE month_dim SET campaign_session = NULL ;
COMMIT ;
USE dw;

TRUNCATE TABLE campaign_session_stg;
LOAD DATA INFILE '/root/data-integration/ragged_campaign.csv'
INTO TABLE campaign_session_stg
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(
  campaign_session
, month
, year
);

UPDATE month_dim a,
    campaign_session_stg b 
SET 
    a.campaign_session = (case
        when b.campaign_session IS NOT NULL then b.campaign_session
        else a.month_name
    end)
WHERE
    a.month = b.month AND a.year = b.year;

COMMIT ;
清單(五)- 7-5         圖(五)- 7-9到圖(五)- 7-12所示為對前面Kettle步驟的修改,完成清單(五)- 7-5裡指令碼的相同裝載。
圖(五)- 7-9
圖(五)- 7-10
圖(五)- 7-11
圖(五)- 7-12
        使用下面的SQL語句查詢month_dim表以確認匯入正確。
mysql> select month_sk, month_name, year, campaign_session
    ->   from month_dim
    ->  where year = 2014;
+----------+------------+------+----------------------------+
| month_sk | month_name | year | campaign_session           |
+----------+------------+------+----------------------------+
|      169 | January    | 2014 | January                    |
|      170 | February   | 2014 | 2014 Early Spring Campaign |
|      171 | March      | 2014 | 2014 Early Spring Campaign |
|      172 | April      | 2014 | April                      |
|      173 | May        | 2014 | 2014 Spring Campaign       |
|      174 | June       | 2014 | 2014 Spring Campaign       |
|      175 | July       | 2014 | 2014 Last Campaign         |
|      176 | August     | 2014 | 2014 Last Campaign         |
|      177 | September  | 2014 | September                  |
|      178 | October    | 2014 | October                    |
|      179 | November   | 2014 | November                   |
|      180 | December   | 2014 | December                   |
+----------+------------+------+----------------------------+
12 rows in set (0.01 sec)

        再次執行清單(五)- 7-4裡的指令碼,結果如圖(五)- 7-13所示。
圖(五)- 7-13
        從查詢結果可以看出,在有推廣期月份的路徑,月級別行的彙總與推廣期級別的行相同。而對於沒有推廣期的月份,其推廣期級別的行與月級別的行相同。也就是說,在沒有推廣期級別的月份,月上捲了它們自己。例如,1月沒有推廣期,所以你在輸出看到了兩個1月的行(第2行和第3行)。第3行是月份級別的行,第2行表示是沒有推廣期的行。對於沒有推廣期的月份,推廣期行的銷售訂單金額(輸出裡的order_amount列)與月分行的相同。

        對於儲存產品,二月和三月屬於同一個名為“2014 Early Spring Campaign”的推廣期。因此,每個月有一行,並上卷至它們的推廣期;銷售訂單金額的彙總就是推廣期的金額。