微軟BI 之SSAS 系列 - 自定義的日期維度設計


SSAS Date 維度基本上在所有的 Cube 設計過程中都存在,很難見到沒有時間維度的 OLAP 數據庫。但是根據不同的項目需求, Date 維度的設計可能不大相同,所以在設計時間維度的時候需要搞清楚幾個問題:

  1. 你的業務涉及到的最低的細節級別是什么?比如按季度查看報表還是按月份,或者按周,或者再甚者按天。這個細節級別需要弄清楚,比如在一些銷售數據統計,有的時候可能更多按季度或者按月來查看報表。但在有的監控一些機器運行數據的統計,可能會按照小時或者分鍾來查看報表。
  2. 你的報表所需要時間顯示的格式是什么,比如在英文系統中客戶是希望顯示月份的全稱 January 或者簡稱 Jan 或者只喜歡看到數字123 12 這種類型。包括顯示具體天的時候是希望看到 10/1/2005 還是 2005/10/01 等格式。
  3. 還有沒有一些特別的時間信息比如不僅僅需要自然年,而且還需要財年信息,以及其它是否是閏年,周末等這樣的要求。
  4. 最重要的一點是客戶喜歡按照哪一種或者哪幾種層次結構來查看報表,比如第一層是年,通過年導航到月再導航到日期;還是說通過年直接導航到周再到具體的日期。

弄清楚上面這幾方面的內容之后,心里大概知道時間屬性的范圍了,細到哪一種級別,由哪些特別的字段需要添加都在這個設計階段完成。

一般情況下,可以自己寫一個創建時間日期的數據倉庫維度表,在這個腳本里面可以根據需要自定義一些特別的日期格式。

--------------------------------------------------------------------- -- BIWORK DimDate and vDimDate Demo -- http://www.cnblogs.com/biwork  ----------------------------------------------------------------------
USE BIWORK_SSIS
GO  
SET NOCOUNT ON 

IF OBJECT_ID('DimDate','U') IS NOT NULL
DROP TABLE DimDate
GO

CREATE TABLE DimDate
(
    DateKey INT PRIMARY KEY,
    FullDate DATE NOT NULL,
    [DateName] NVARCHAR(20),
    DayNumberOfWeek TINYINT NOT NULL,
    DayNameOfWeek NVARCHAR(10) NOT NULL,
    DayNumberOfMonth TINYINT NOT NULL,
    DayNumberOfYear SMALLINT NOT NULL,
    IsWeekend BIT NOT NULL,
    IsLeapYear BIT NOT NULL,
    WeekNumberOfYear TINYINT NOT NULL,
    EnglishMonthName NVARCHAR(10) NOT NULL,
    MonthNumberOfYear TINYINT NOT NULL,
    CalendarQuarter TINYINT NOT NULL,
    CalendarSemester TINYINT NOT NULL,
    CalendarYear SMALLINT NOT NULL, 
    FiscalQuarter TINYINT NOT NULL,
    FiscalSemester TINYINT NOT NULL,
    FiscalYear SMALLINT NOT NULL 
)

DECLARE @StartDate DATETIME
DECLARE @EndDate DATETIME

SELECT @StartDate = '2005-01-01',
       @EndDate = '2013-12-31'

WHILE (@StartDate <= @EndDate)
BEGIN
    INSERT INTO DimDate 
    (
        DateKey,
        FullDate,
        [DateName],
        DayNumberOfWeek,
        DayNameOfWeek,
        DayNumberOfMonth,
        DayNumberOfYear,
        IsWeekend,
        IsLeapYear,
        WeekNumberOfYear,
        EnglishMonthName, 
        MonthNumberOfYear,
        CalendarQuarter,
        CalendarSemester,
        CalendarYear, 
        FiscalQuarter,
        FiscalSemester,
        FiscalYear 
    )
    SELECT CAST(CONVERT(VARCHAR(8),@StartDate,112) AS INT) AS DateKey,
           CONVERT(VARCHAR(10), @StartDate,20) AS FullDate,
           CONVERT(VARCHAR(20), @StartDate,106) AS [DateName],
           DATEPART(DW,@StartDate) AS DayNumberOfWeek,
           DATENAME(DW,@StartDate) AS DayNameOfWeek,
           DATENAME(DD,@StartDate) AS [DayOfMonth],
           DATENAME(DY,@StartDate) AS [DayOfYear],
           CASE WHEN DATEPART(DW,@StartDate) IN (1,7)  
                    THEN 1
                ELSE 0 
           END AS IsWeekend,
           CASE WHEN ((YEAR(@StartDate) % 4 = 0) AND (YEAR(@StartDate) % 100 != 0 OR YEAR(@StartDate) % 400 = 0))
                    THEN 1
                ELSE 0
           END AS IsLeapYear,
           DATEPART(WW,@StartDate) AS WeekNumberOfYear,
           DATENAME(MM,@StartDate) AS EnglishMonthName,
           DATEPART(MM,@StartDate) AS MonthNumberOfYear,
           DATEPART(QQ,@StartDate) AS CalendarQuarter,
           CASE WHEN DATEPART(MM,@StartDate) BETWEEN 1 AND 6
                    THEN 1
                ELSE 2
           END AS CalendarSemester,
           DATEPART(YY,@StartDate) AS CalendarYear, 
           CASE WHEN DATEPART(MM,@StartDate) BETWEEN 1 AND 6
                     THEN DATEPART(QQ,@StartDate) + 2
                ELSE DATEPART(QQ,@StartDate) - 2
           END AS FiscalQuarter,
           CASE WHEN DATEPART(MM,@StartDate) BETWEEN 1 AND 6
                    THEN 2
                ELSE 1
           END AS FiscalSemester,
           CASE WHEN DATEPART(MM,@StartDate) BETWEEN 1 AND 6
                    THEN DATEPART(YY,@StartDate) 
                ELSE DATEPART(YY,@StartDate) + 1
           END AS FiscalYear
            
    SET @StartDate = @StartDate + 1
END
GO

--------------------------------------------------------------------- -- 加上視圖的作用是因為在實際的項目開發中,SSAS 的數據源視圖所有的表對象 -- 應該都引用視圖,這樣當數據倉庫中維度表或者事實表有小的改動就可以直接在 -- 視圖中修改,而可以避免修改 SSAS 項目。 -- 這一點在 SSIS 開發中同樣適用,所有在 SSIS 中配置的 SQL 語句都封裝在存儲 -- 過程中,表封裝在視圖中。邏輯的修改直接體現在存儲過程中,而不會修改 SSIS。 ----------------------------------------------------------------------
IF OBJECT_ID('vDimDate','V') IS NOT NULL
DROP VIEW vDimDate
GO

CREATE VIEW vDimDate
AS
  -- 可以根據需要實現一些計算列,這些計算列通常也可以在 SSAS 視圖中添加。
SELECT DateKey AS 'DateKey',
       FullDate AS 'FullDate',
       [DateName] AS 'DateName',
       CONVERT(VARCHAR(2),DayNumberOfMonth) + ' ' + EnglishMonthName + ' ' + CONVERT(CHAR(4), CalendarYear) AS 'FullDateName', -- 1 July 2005 
       DayNumberOfWeek AS 'DayNumberOfWeek',
       DayNameOfWeek AS 'DayNameOfWeek',
       DayNumberOfMonth AS 'DayNumberOfMonth',
       DayNumberOfYear AS 'DayNumberOfYear',
       CASE WHEN IsWeekend = 1 THEN 'Weekend' 
            ELSE 'Weekday'
       END AS 'WeekdayWeekend',
       IsLeapYear AS 'IsLeapYear',
       WeekNumberOfYear AS 'WeekNumberOfYear',
       EnglishMonthName AS 'EnglishMonthName',
       EnglishMonthName + ' ' + CONVERT(CHAR(4),CalendarYear) AS 'MonthName',  -- July 2005
       CalendarYear * 100 + MonthNumberOfYear AS 'MonthKey', -- 200507
       MonthNumberOfYear AS 'MonthNumberOfYear',
       CalendarQuarter AS 'CalendarQuarter',
       CalendarSemester AS 'CalendarSemester',
       CalendarYear AS 'CalendarYear',  
       CalendarYear * 100 + CalendarQuarter AS 'CalendarQuarterKey',  -- 200503
       'CY ' + CONVERT(CHAR(4),CalendarYear) AS 'CalendarYearName', -- CY 2005
       'CY ' + CONVERT(CHAR(4),CalendarYear) 
             + ' Qtr ' 
             + CONVERT(CHAR(1), CalendarQuarter) AS 'CalendarQuarterName', -- CY 2005 Qtr 3 
       FiscalQuarter AS 'FiscalQuarter',
       FiscalSemester AS 'FiscalSemester',
       FiscalYear AS 'FiscalYear', 
       FiscalYear * 100 + FiscalQuarter AS 'FiscalQuarterKey', -- 200601
       'FY ' + CONVERT(CHAR(4), FiscalYear) AS 'FiscalYearName',  -- FY 2006
       'FY ' + CONVERT(Char(4), FiscalYear) + ' Qtr ' + Convert(Char(1), FiscalQuarter) AS 'FiscalQuarterName' -- FY 2006 Qtr 1
FROM DimDate
GO

在我的這個示例中,財年是以微軟的財年為例子的。比如20087是自然月,但是財年就被稱為 2009財年的1月,它是從每年的7月開始算的。 下面的這幅圖主要是展示了各個字段上時間日期的格式是以及字段類型等。並且在后面設計維度的時候,我們往往選擇 Key 會考慮使用整形數據字段,但是在 Name Column 的時候就會使用具體的描述內容。 Attribute Type 后面也能看得到,它的主要作用是為具體的時間日期字段指定日期屬性。日期屬性的指定能夠讓 SSAS Cube 在內部聚合的時候知道某個字段的含義,這個字段是描述日期,還是年還是月。在 MDX 的時間相關的層級導航或者查詢中,比如說 YTD() 函數的使用就跟設置屬性為 Year 相關的維度屬性相關,可以參考我的這篇 MDX筆記

新建一個 SSAS 項目並創建好數據源和數據源視圖,數據源視圖中就是上面創建的視圖。

創建一個簡單的時間維度,選擇 vDimDate,並在 Key Column 中選擇 DateKey, Name Column 選擇 FullDateName。實際上,這里就一個屬性,但是這個屬性是由兩部分組成的,一個是 KEY 一個是 NAME。

然后選擇其它的相應的屬性,這里面基本上都是選擇的數值類型的屬性,因為我們一會還要修改它們,為他們配置相應的 Name Column - 提供信息標簽。我們同時為這些屬性選擇好相應的 Attribute Type,如下圖所示。

修改維度名稱 Date ,那么保存后就可以看到一個維度和它的維度屬性了。

Date 維度它的類型會自動設置為 Time 的,不是 Time 類型的維度在 MDX 的查詢中有很多時間函數可能就無法使用了。並且在 SSAS Cube 的處理過程中,就不會把這個維度當作特殊的時間維度去考慮,因此這里會自動設置為 Time 類型。

這樣的結構就是一個維度和它下面的維度屬性,如果僅這樣部署到 SSAS 分析服務中,我們將看到的是一堆數字 KEY 表示的信息,那么這些數據就失去了"信息"的意義。

因此我們需要按照這個圖來修改每一個屬性,為它們指定相應的 NAME Column,這樣相當於為這個數字添上了一個標簽。

如上圖所示,下圖中的 CalendarYear 這個屬性,它的 Key Column 就是 CalendarYear ,它的 Attribute Type 是 Year, 它的 Name Column 是 Calendar Year Name。

按照上面的配置修改完維度屬性之后,也將名字改的簡單一些。

部署之后可以看到每一個維度屬性的 Name Column 展示出來的信息了,並且注意在 SSAS 中有這樣的一個概念 - 維度中的屬性實際上指的屬性層次結構,每一個屬性層次結構都包含兩層。第一層是以 ALL 為代表的成員,第二層是以各個屬性值表示的成員。ALL 表示的就是對下面所有屬性的一個聚合,在和度量值結合起來看就會很容易理解的。

維度其實就是屬性和層次結構組成的,但是除了上面的屬性層次結構之外,還包括下面的用戶自定義層次結構。那么這種主要是根據用戶的需求來決定的,比如用戶通常會根據年來聚合,或者再細看季度方面的數據,然后再是月或者天。因此下面創建兩個日期自定義層次結構,一個是自然年度的,一個是財年年度的層次結構。

默認情況下,各個屬性是和維度主 KEY 關聯的,那么這樣在層次結構關系中可能每次的上下次層次聚合都需要通過 Date Key 來進行關聯,比如說不能通過 Month 來直接找到季度方面的成員,也不能通過年來找到具體季度的成員,因此需要對屬性之間的關系做出一定的調整,提高 SSAS 處理屬性聚合時的效率。

修改完了之后的屬性關系就更加合理一些。

創建好的自定義屬性層級關系,它的導航結構和上圖的設計是一致的,注意到它也有一個 ALL 級別。

實際上剛才我們設計的這些個屬性我們之前也一直強調過,是由兩部分組成的,一部分是自身的 KEY,另一部分是 NAME 來增強了對它們自身的解釋。下面描述了這些屬性的 NAME 匹配關系。

這個是財年層次結構的展開效果。

財年 KEY 和 NAME 的對應關系。

但是在自然的屬性層次結構中,我們看到 MONTH NAME 下面的成員順序不正確,一月份應該是 January ,但是 April 卻排到最前面去了。雖然這里的成員順序不會影響我們數據分析,但是人們更加希望能夠按照約定俗成的方式更自然的方式來展現,這樣更符合我們的習慣。

因此需要編輯屬性關系,我們之前偷偷加了一個屬性 Month Number Of Year 但是一直沒有用到,但是在這里就可以用上了。

綁定的屬性關系中,可以看到 Month Name 又將 Month Number Of Year 這個屬性關聯成它自己的一種屬性了。

Month Name 排序之前按照 Key 排序,Key 就是 Month Name 自身的英語月的排序,那么 April 肯定是顯示在第一個的位置了。

注意這里要使用 Attribute Key 排序,選擇 Month Number Of Year。

由於 Month Number Of Year 這個屬性只是用來做排序用的,因此這個屬性層次結構是沒有必要展示在客戶端的,也沒有必要作為一個屬性出現,因此禁用瀏覽,也禁用變成層次結構。

部署完畢之后就可以看到一個正常的月份順序了。

下面是對應關系。

如果按照 Attribute Name 排序會出現什么問題?

可以看這幅圖,如果按照 Attribute Name 來排序的話,就會看到順序會變成 1,10,11,12 然后才是 2,3,4 ...9 。

 


更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server)

如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM