簡介
Power BI Desktop -是一款由微軟發布的自助式商業智能工具,功能強大、易於使用。其中還可以通過微軟雲連多個數據源並且使用數據源來創建可視化表盤。
但是幾乎所有的BI都需要展示如何隨時間改變KPI。因此我將會介紹一個幫助我們使用事件元素來分析數據的關鍵功能。在PowerBI Desktop 中叫做“time intelligence”。應用這種時域分析法能是商業智能中基本的數據表現形式。畢竟公司想要知道的無非就是今年的業績相比去年如何以及取得了何種進步。
“Time intelligence”將需要一個日期表,花費一定的時間去創建一個成功數據模型的核心就是這個表。然后日期表必須與主數據中隨時間變化的日期字段進行關聯。需要作如下幾種事情:
- YearToDate, QuarterToDate, 和MonthToDate 的計算
- 比較之前的年、季、月
- 回滾一段時間的聚合,比如最近三個月的累加。
- 比較平行時間段,比如與之前一年相同的月份。
當使用隨時間進行的數據分析的時候,很可能要使用DAX函數。為了更好地理解,我們將介紹如何創建日期表,然后看一下幾種不同的分析時間的計算,最后加入這些類型道數據模型中。為了測試我會使用一個excel作為PowerBI Desktop 的文件數據源。
創建並且應用日期表
對於智能時間,至少需要一個包含不間斷時間范圍的日期表,並且開始時間的最小值是源數據中的最小日期,結束日期至少等於源數據中的最大值。實踐中,需要創建一個表,開始日期是最早日期的1月1日而最大日期應該是數據源日期的上一年的12月31日。一旦你創建了這個表,就能連接數據模型中的含有時間字段的表,然后拓展時間相關的分析函數。
1.創建日期表
應用時間的前提就是創建日期表。下面步驟說明使用DAX創建表的過程:
1 - 打開PowerBI Desktop文件C:\PowerBiDesktopSamples\PowerBIDataModel.Pbix.
2 - 切換左側的tab,選擇第二個Data如下圖所示。
3 - 點擊左上方的Modeling按鈕,然后點擊新建表按鈕。表達式“表=”將出現在公式欄里面,
4 - 把Table替換成DateDimension
5 - 輸入DAX函數CALENDAR("1/1/2012","31/12/2016"),然后回車或者對勾。前一個時間是dates表的開始時間,后一個時間是結束時間,公式欄內容:DateDimension = CALENDAR( "1/1/2012", "31/12/2016" ).
6 - 回車后,創建了一個單列表,表中的內容就是2012-01-01到2016-12-31,所有日期。
7 - 編輯表頭,改列名稱為DateKey,結果如下所示:
8 - 點擊添加新列按鈕或者右鍵添加新列,新列將會出現在現存列右側。
9 - 在公示欄輸入“FullYear = YEAR([DateKey])”。
10 - 再添加如下19個列公式。如下:
列標題 | 公式 | 注釋 |
ShortYear | VALUE(Right(Year([DateKey]),2)) | 取后兩位數字年 |
MonthNumberFull | FORMAT([DateKey], "MM") | 月份取兩位數,不足的前面補0 |
MonthFull | FORMAT([DateKey], "MMMM") | 月份展示名稱 |
WeekNumber | WEEKNUM([DateKey]) | 以下自行測試 |
MonthAbbr | FORMAT([DateKey], "MMM") | |
WeekNumberFull | FORMAT(Weeknum([DateKey]), "00") | |
DayOfMonth |
DAY([DateKey]) |
|
DayOfMonthFull |
FORMAT(Day([DateKey]),"00") |
|
DayOfWeek |
WEEKDAY([DateKey]) |
|
DayOfWeekFull |
FORMAT([DateKey],"dddd") |
|
DayOfWeekAbbr |
FORMAT([DateKey],"ddd") |
|
ISODate |
[FullYear] & [MonthNumberFull] & [DayOfMonthFull] |
|
FullDate |
[DayOfMonth] & " " & [MonthFull] & " " & [FullYear] |
|
QuarterFull |
"Quarter " & ROUNDDOWN(MONTH([DateKey])/4,0)+1 |
|
QuarterAbbr |
"Qtr " &ROUNDDOWN(MONTH([DateKey])/4,0)+1 |
|
Quarter |
"Q" &ROUNDDOWN(MONTH([DateKey])/4,0)+1 |
|
QuarterNumber |
ROUNDDOWN(MONTH([DateKey])/4,0)+1 |
|
QuarterAndYear |
DateDimension[Quarter] & " " & [FullYear] |
|
MonthAndYearAbbr |
DateDimension[MonthAbbr] & " " & [FullYear] |
|
QuarterAndYearNumber |
[FullYear] & [QuarterNumber] |
|
YearAndWeek |
VALUE([FullYear] &[WeekNumberFull]) |
|
YearAndMonthNumber |
Value(DateDimension[FullYear] & DateDimension[MonthNumberFull]) |
展示如下:
創建所有這些表現時間的的目的就是早晚有一天會用到這些日期來展示報表、聚合指標、展示數據。任何有時間元素的表都可以按照這個新增表中的時間轉換聚合來可視化數據。這里你不需要擔心是否需要額外的列,因為還可以動態添加你需要的時間元素。
在日期表中引入列排序
現在需要看一下如何排序。典型的例子就是月份排序。如果你打算展示MonthFull 或者MonthAbbr 列,那么將看到月份(month)出現在軸標簽里面或者按字母排序的列里面。
為了避免最后再去調整日期表,可以通過應用特定的日期元素來排列其他列,如下:
1 - 點擊打算使用其他的列來排序的列(比如Monthfull) ;
2 - 點擊Modeling下方的排序按鈕,其他列的名稱將會出現,如下圖所示:
3 - 選擇打算按照排序的列(MonthNumber);
這里並不能立即顯示出任何不同,但是當在儀表盤中使用任何你已經調整過的日期列時,它們將會根據排序列進行數據排序。
下表提供給你需要的信息來擴展你創建的數據表以便於所有的日期元素都能被正確排序。
Column | Sort By Column |
MonthAbbr |
MonthNumber |
DayOfWeekFull |
DayOfWeek |
DayOfWeekAbbr | DayOfWeek |
Quarter And Year | QuarterAndYearNumber |
FullDate | DateKey |
MonthAndYearAbbr | YearAndMonthNumber |
MonthAndYear | YearAndMonthNumber |
日期表技巧
當引入時間智能后,一定要遵守兩個基礎原則。
- 日期范圍必須是連續的。
- 在數據模型中數據范圍一定是包含所有使用的其他表中的日期。
一旦你知道你數據中的最大值和最小值日期就可以使用CALENDAR來生成日期,即使兩個值在不同的表里面如下:
DateDimension = CALENDAR(MIN(‘Stock‘[PurchaseDate]), MAX(‘Invoices‘[InvoiceDate]))
或者,你可能更喜歡日期維度通過全年的數據,在這種情況下,公式可以這樣創建表:
DateDimension = CALENDAR(STARTOFYEAR(MIN(‘Stock‘[PurchaseDate])), ENDOFYEAR(MAX(‘Invoices‘[InvoiceDate])))
這個公式擴展了DAX的計算,兩個計算年的公式也是極其有幫助的:
- StartOfYear() - 這個公式得出最小的年份。
- EndOfYear() - 這個公式得出最大的年份
注意
這種日期范圍的主要優點在於隨着數據源的變化自動更新。因此如果Stock 或 Invoices表數據源擴展了新的數據並且在原有日期外的,那么這個時間維度表也會自動變化來包含這部分新增數據的部分。
這里的可以給大家一個小技巧,不需要每次都去創建這個日期表,可先創建一個空的模型,里面只有日期表,結束和開始日期是手填寫的,然后加入所有其他列,接下來復制這個模板文件,以后每次使用都以這個模板文件為基礎創建。只需要替換手動填寫的日期即可。
向數據模型中加入日期表
現在你有了一個日期表,可以與你的數據模型進行整合以便於開始應用這些智能時間。
1 - 點擊關系視圖的圖表來展示數據模型中的表
2 - 點擊管理關系按鈕,對話框會出現。
3 - 點擊新建按鈕,創建關系。
4 - 在對話框頂部選擇時間維度表。
5 - 點擊DateKey列選擇。
6 - 在時間維度表下面的下拉框中選擇Invoice表。
7 - 再點擊InvoiceDate列選擇,對話庫如下:
8 - 點擊Ok,新的表關系就建立了
9 - 點擊關閉,時間維度表就與Invoice表建立了關系。
注意 為了時間智能在PowerBI中能夠正確使用一定要保證日期表和數據表中的數據類型是date或者datetime。
應用時間智能
所有的准備工作都已經完成了,接下來就看如何使用DAX實現隨着時間變化來計算指標。
YearToDate, QuarterToDate, 和MonthToDate 運算
首先,讓我們解決一個簡單但是頻繁的需求:計算月累計、季度累計、和年累計的銷售數字。
這個例子中三個函數是很相似的。因此我只解釋第一個月累計,然后創建下面兩個用復制黏貼的方式。
1 - 在數據視圖中選擇Invoices表,然后點擊新建測量;
2 - 在公式欄用MonthSales替換Measure ;
3 - 輸入這個公式MonthSales = TOTALMTD(SUM(InvoiceLines[SalePrice]),DateDimension[DateKey])。
MonthSales = TOTALMTD(SUM(InvoiceLines[SalePrice]),DateDimension[DateKey])
4 - 回車或者點擊對勾完成公式
現在可以復制這個公式,生成兩個新的公式用來表示季度銷售和年度銷售日期公式如下:
QuarterSales = TOTALQTD(SUM(InvoiceLines[SalePrice]),DateDimension[DateKey]) YearSales = TOTALYTD(SUM(InvoiceLines[SalePrice]),DateDimension[DateKey])
三個公式分別使用了Totalmtd()、Totalqtd和Totalytd來聚合時間其他參數是一樣的。
結果如下:
正縮減,每個月的銷售數字隨着累加到季度銷售數字中,最后還要加到年度銷售數字中。還要注意整個排序是按照monthfull來排序的,其實是按照MonthNumber 進行排序。
總結
在這個例子中,我使用了Invoices表來測試僅僅因為這里存儲了很多指標數據,當然你也可以選擇其他表來嘗試這個智能時間的應用。它不僅方便了對於數據的分類和比較,更提供了一種潛在的排序和聚合。
補充:
還可以在數據庫中建立物理維度表。
創建日期維度表:
CREATE TABLE [dbo].[DimDate]( [datekey] [int] NOT NULL, [date_name] [date] NOT NULL, [the_Year] [int] NULL, [year_name] [nvarchar](10) NULL, [the_quarter] [int] NULL, [quarter_name] [nvarchar](10) NULL, [the_month] [int] NULL, [month_name] [nvarchar](10) NULL, [the_week] [int] NULL, [week_name] [nvarchar](10) NULL, [the_year_quarter] [int] NULL, [year_quarter_name] [nvarchar](10) NULL, [the_year_month] [int] NULL, [year_month_name] [nvarchar](10) NULL, [the_year_week] [int] NULL, [year_week_name] [nvarchar](10) NULL, [the_week_day] [int] NULL, [week_day_name] [nvarchar](10) NULL, [week_day_type] [nvarchar](10) NULL, CONSTRAINT [PK_DimDate] PRIMARY KEY CLUSTERED ( [datekey] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY]
也可以使用存儲過程在物理表中生成時間維度表:
USE [DW] GO /****** Object: StoredProcedure [dbo].[SP_CREATE_TIME_DIMENSION] Script Date: 2017/12/8 18:34:39 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO ALTER PROCEDURE [dbo].[SP_CREATE_TIME_DIMENSION] @begin_date nvarchar(50)='2016-01-01' , @end_date nvarchar(50)='2017-12-31' as /* SP_CREATE_TIME_DIMENSION: 生成時間維數據 begin_date: 起始時間 end_date:結束時間 */ declare @dDate date=convert(date,@begin_date), @v_the_date varchar(10), @v_the_year varchar(4), @v_the_quarter varchar(2), @v_the_month varchar(10), @v_the_month2 varchar(2), @v_the_week varchar(2), @v_the_day varchar(10), @v_the_day2 varchar(2), @v_week_day nvarchar(10), @adddays int=1; WHILE (@dDate<=convert(date,@end_date)) begin set @v_the_date=convert(char(10),@dDate,112);--key值 set @v_the_year=DATEPART("YYYY",@dDate);--年 set @v_the_quarter=DATEPART("QQ",@dDate);--季度 set @v_the_month=DATEPART("MM",@dDate);--月份(字符型) --set @v_the_month2=to_number(to_char(dDate, 'mm'));--月份(數字型) set @v_the_day=DATEPART("dd",@dDate);--日(字符型) --set @v_the_day2=to_char(dDate, 'dd'); set @v_the_week=DATEPART("WW",@dDate);--年的第幾周 set @v_week_day=DATEPART("DW",@dDate); --星期幾 INSERT INTO [dbo].[DimDate] ([datekey] ,[date_name] ,[FiscalQuarter] ,[FiscalYear] ,[FiscalSemester] ,[FiscalWeek] ,[the_Year] ,[year_name] ,[the_quarter] ,[quarter_name] ,[the_month] ,[month_name] ,[the_week] ,[week_name] ,[the_year_quarter] ,[year_quarter_name] ,[the_year_month] ,[year_month_name] ,[the_year_week] ,[year_week_name] ,[the_week_day] ,[week_day_name] ,[week_day_type]) VALUES (@v_the_date ,@dDate ,@v_the_year ,'Y'+convert(nvarchar(10),@v_the_year) ,@v_the_quarter ,'Q'+convert(nvarchar(10),@v_the_quarter) ,@v_the_month ,'M'+convert(nvarchar(10),@v_the_month) ,@v_the_week ,'WK'+convert(nvarchar(10),@v_the_week) ,@v_the_year*100+@v_the_quarter ,'YQ'+convert(nvarchar(10),(@v_the_year*100+@v_the_quarter)) ,@v_the_year*100+@v_the_month ,'YQ'+convert(nvarchar(10),(@v_the_year*100+@v_the_month)) ,@v_the_year*100+@v_the_week ,'YQ'+convert(nvarchar(10),(@v_the_year*100+@v_the_week)) ,@v_week_day ,'WD'+@v_week_day ,case @v_week_day-1 when 6 then '休息日' when 0 then '休息日' else '工作日' end); set @dDate=dateadd(day,@adddays,@dDate); continue if @dDate=dateadd(day,-1,convert(date,@end_date)) break end