1.1、members和Children的用法。
select [Measures].[Internet Sales Count] on columns,
[客戶].[全名] on rows
from [Adventure Works DW]
默認顯示的是[全部客戶的總銷售量],即只有一個數據(前提是這個度量下有多個值)
如果要顯示所有客戶的銷售量,在要全部顯示具體的那個軸上加上.members:
select [Measures].[Internet Sales Count] on columns,
[客戶].[全名].members on rows
from [Adventure Works DW]
顯示結果包括總的銷售量和每個人的銷售量
若只要具體的銷售量不需要總的銷售量,就用Children
select [Measures].[Internet Sales Count] on columns,
[客戶].[全名].children on rows
from [Adventure Works DW]
若不要那些為NULL的記錄,那么就在該軸的定義前加個 NON EMPTY
select [Measures].[Internet Sales Count] on columns,
NON EMPTY [客戶].[全名].children on rows
from [Adventure Works DW]
1.2、一個軸上顯示該維中多個元組
一軸中可以有多列數據,沒列數據叫一個元組,每個元組用逗號隔開,且最后的結果集用{}合並:{}中必須是同一維的元組
select
{[Measures].[Internet Sales Count],[Measures].[Sales Amount]} on columns,
NON EMPTY [客戶].[全名].children on rows
from [Adventure Works DW]
1.3、添加一個維以不同角度來顯示結果
如何將[Measures].[Internet Sales Count]和[Measures].[Sales Amount]按客戶維的[客戶].[全名]和產品維的[產品].[Model Name]來划分。
意思就是將[客戶].[全名]和[產品].[Model Name]作為橫軸參數,將[Measures].[Internet Sales Count]和[Measures].[Sales Amount]按縱軸根據兩個橫軸參數得到相應的結果,當然兩個橫軸都要為Children
select
{[Measures].[Internet Sales Count],
[Measures].[Sales Amount]} on columns,
NON EMPTY
[客戶].[全名].children* --方法一是根據*來實現
[產品].[Model Name].children on rows
/*
(
[客戶].[全名].children, --方法二是根據()來實現
[產品].[Model Name].children
) on rows
*/
from [Adventure Works DW]
感想:其實軸和OLAP中的維度變量沒有直接的關系,以為一個軸可以填充多個維的元組,如示例三
1.4、Order排序
Order函數的格式:Order(顯示成員名,依據排序的度量,升/降)
select
{
[Measures].[Internet Sales Count],
[Measures].[Sales Amount]
} on columns,
NON EMPTY
order(
[客戶].[全名].children* --方法一是根據*來實現
[產品].[Model Name].children,[Measures].[Sales Amount],DESC)
on rows
from [Adventure Works DW]
上面的MDX語句有點類似於T-SQL的:
Order by [客戶].[全名], [產品].[Model Name] DESC,先是相同的[客戶].[全名]進行排序,然后是當個[客戶].[全名]里相同的[產品].[Model Name]進行排序.
1.5、Rows軸的所有元組作為一列顯示
/*
下面的結果將顯示:
[產品].[Product Model Lines].[Model Name]緊跟着
[產品].[Product Model Lines].[Product Line]的數據后面顯示
整體為一列
注意一點,和並列兩個不同列的情況不同,若有多個元組作為一列,那么Rows軸的所有元組都必須是一個層次下的元組。?????
*/
select
{
[Measures].[Internet Sales Count],
[Measures].[Sales Amount]
}on columns,
non empty{
[產品].[Product Model Lines].[Product Line],
[產品].[Product Model Lines].[Model Name]
}on rows
from [Adventure Works DW]
1.6、使用Filter和Where語句
/*
Filter和Where的區別:
Filter是針對度量(或元組,貌似元組的結果也是一個度量)篩選結果,只有一種情況Filter會使用維度,如實例八所示。
Where是針對維度篩選結構,比如某個維度需要滿足什么條件。
實例:
1、選擇網絡銷售額和總銷售額。
2、條件是根據總銷售額>1000,網絡銷售額>1500,產品系列為M到S(即M,R,S)中的S。
3、最后對結果進行對網絡銷售額進行降序
*/
select
{
[Measures].[Internet Sales Count],
[Measures].[Sales Amount]
}on columns,
non empty
order(
filter
(
[產品].[Product Model Lines].[Product Line].&[M]:[產品].[Product Model Lines].[Product Line].&[S]*
[產品].[Model Name].children,
[Measures].[Sales Amount]>10000 and
[Measures].[Internet Sales Count]>1500
),[Measures].[Internet Sales Count],DESC)on rows
from [Adventure Works DW]
where ([產品].[Product Line].&[S])
1.7、連續選擇某個區間的維度值(注意是‘值’)時,可以使用符號’:’
如上面的例子,’:’也可以用於時間值的范圍。對於時間值的范圍,它都是計算兩個時間的中間值,所有無所謂先后順序問題。
1.8、查看某維度的相關信息,維度Name.CurrentMember.Name/Value等
/*
只有一種情況Filter會使用維度。
給Filter語句中添加一個選擇條件:用InStr函數來篩選指定維度的Name要包含字符'S'
*/
select
{
[Measures].[Internet Sales Count],
[Measures].[Sales Amount]
}on columns,
non empty
order(
filter
(
[產品].[Product Model Lines].[Product Line].&[M]:[產品].[Product Model Lines].[Product Line].&[S]*
[產品].[Model Name].children,
[Measures].[Sales Amount]>10000 and
[Measures].[Internet Sales Count]>1500
and InStr([產品].[Model Name].CurrentMember.Name,'S')>0-CurrentMember.Name
),[Measures].[Internet Sales Count],DESC)on rows
from [Adventure Works DW]
where ([產品].[Product Line].&[S])
1.9、創建臨時計算成員(它是一個度量,而命名集合是一個維度成員組),以作為查詢和排序之用
/*
創建臨時的兩個度量:[Measures].[My BiLi]和[Measures].[My Beishu]
在一個With語句下,如要定義多個計算成員或者命名查詢,那么只要一個With關鍵字即可。
*/
with member [Measures].[My BiLi] as
[Measures].[Internet Sales Count]/[Measures].[Sales Amount]
--,FORMAT_STRING=‘Currency’
member [Measures].[My Beishu] as
[Measures].[Sales Amount]+[Measures].[Internet Sales Count]
--format_string =“Percent‘
select
{
[Measures].[Internet Sales Count],
[Measures].[Sales Amount],
[Measures].[My BiLi],
[Measures].[My Beishu]
}on columns,
non empty order(
[產品].[Product Model Lines].[Model Name]
,[Measures].[My Beishu],DESC)
on rows
from [Adventure Works DW]
where ([產品].[Product Line].&[S])
1.10、創建臨時命名集合
創建命名查詢(返回的結果就是命名集合)方法有:
With Member as ….和Create Member as…
With Set … As和Create Set…. As。
前者With是創建一個臨時的計算成員或者命名集合,后者Create是創建持久的計算成員或命名集合。
Set和Member的區別是:
Member只能操作一個維度並返回,而Set可以操作多個維度並返回。
/*
set 操作的對象是維度,固所查詢的命名集合是一個維度組,該維度組可以構成rows軸。
filter(維度組,度量組條件/一些特殊的維度組條件,比如InStr函數)
*/
with member [Measures].[My BiLi] as
[Measures].[Internet Sales Count]/[Measures].[Sales Amount],
format_string='Percent'--注意這里是字母格式下的單引號
member [Measures].[My Beishu] as
[Measures].[Sales Amount]+[Measures].[Internet Sales Count]
--,FORMAT_STRING ='Currency'
--定義一個維度組,該維度[產品].[Product Model Lines].[Model Name],
--自定義計算成員(度量)[Measures].[My Beishu]>222000且[產品].[Model Name]名稱包含'RO'
set [heihei] as
filter(order(
[產品].[Product Model Lines].[Model Name]
,[Measures].[My Beishu],DESC)
,[Measures].[My Beishu]>222000
and InStr([產品].[Model Name].CurrentMember.Name,'Ro')>0
)
select
{
[Measures].[Internet Sales Count]
,[Measures].[Sales Amount]
,[Measures].[My BiLi]
,[Measures].[My Beishu]
}on columns,
non empty [heihei] on rows
from [Adventure Works DW]
//where ([產品].[Product Line].&[S])
1.11、TopCount函數
操作的對象也是維度,固返回的對象也是維度。固其所定義的對象可以直接作為rows軸使用。
/*
topcount(維度,前N項,依據的度量),如
topcount([產品].[Model Name].children,10,[Measures].[Sales Amount])
*/
with
member [allsalses] as
[Measures].[Sales Amount],format_string='Currency'
set [MyTopCount] as
topcount
(
[產品].[Model Name].children*[客戶].[客戶所在地域].[地區區域_市],
10,
[Measures].[Sales Amount]
)
select
{
[Measures].[Internet Sales Count],
[allsalses]
} on columns,
non empty [MyTopCount]
--non empty order([產品].[Model Name].children,[Measures].[Sales Amount],DESC)
on rows
from
[Adventure Works DW]
1.12、Generate函數,將第二個表達式的結果帶入第一個表達式進行處理(前提是:在第二個表達式中要有第一個表達式的引用)
/*
實例實現要求:想得到銷售額靠前的5個州,且輸出各個州各自最熱賣的5中產品
generate
(
Set_Expression1 第一個表達式
Set_Expression1 第二個表達式
[all] 若不設置該項,則刪除重復的,若為all,則顯示所有,包括重復的。
)
1、將第二個表達式的結果作為引用帶入第一個表達式中計算,最后得到並集(前提是第二個表達式中有第一個表達式的元組的引用),如第二中存在第一元組.CurrentMember
2、返回的最后結果為第二個表達式中的元組,如果第二個表達式中指定了第一個表達式的引用,即【第一個表達式元組.CurrentMember,其他元組】,則結果為第一和第二的並集,總之為第二個表達式的元組
3、有點類似於T-SQL中的outer Apply
*/
with member [mysale]
as
[Measures].[Sales Amount],format_string='Currency'
select [mysale] on columns,
generate
(
topcount([客戶].[國家_地區區域].children,3,[Measures].[Sales Amount])
,(
[客戶].[國家_地區區域].Currentmember,--這是引用,所有結果中也有這個列
topcount
(
[產品].[Product Model Lines].[Model Name],3,[Measures].[Sales Amount]
)
)
,all
) on rows
from [Adventure Works DW]
1.13、Rank指定元組在集合中的位置函數
/*
Rank:返回指定元組在指定集中的排名(排名從1 開始)。
Rank(Tuple_Expression, Set_Expression [ ,Numeric Expression ] )
Tuple_Expression:指定的元組
Set_Expression :指定集
Return Value:是一個度量,指定元組在指定集中的當前位置
*/
with
set [SaleRankSet] as
filter(
order
(
([客戶].[國家_地區區域].children,[產品].[Model Name].children)------------這個排序的元組列集合要一樣
,[Measures].[Sales Amount],DESC)
,[Measures].[Sales Amount]<>0)
member [SaleRank] as
rank(
([客戶].[國家_地區區域].currentmember,[產品].[Model Name].currentmember)--這個排序的元組列集合要一樣
,[SaleRankSet])
--計算成員只是得到該元組在指定集合中的位置,Rank本身沒有排序功能,隱藏的部分排序邏輯在命名集合中已經做好了
--由於有了第一個命名集合在該計算成員中的應用才真正得到了具體元組在集合中的正確排序序號。
select
{
[SaleRank],[Measures].[Sales Amount]
} on columns,
[SaleRankSet]
on rows
from [Adventure Works DW]
注:為了便於理解,我們有必要提一下mdx語句在解析執行過程中的順序:from->where->with->select。
1.14、一些函數的介紹
1、成員函數
1、 Ancestor(Member_Expression, Level_Expression) 此函數返回指定成員在指定級別或距離處的祖先。
Ascendants返回成員祖先的集合,包括成員本身
如
select [Measures].[Internet Sales Count] on columns,
Ancestors
(
[客戶].[客戶所在地域].[全名].&[15019],
[客戶].[客戶所在地域].[國家]
)on rows
from [Adventure Works DW]
將返回15019的國家:澳大利亞
2、ClosingPeriod(1,2)
返回指定成員在指定級別處的后代中的最后一個同級成員。即2下面的所有子節點中和1是同一個級別的最后的一個節點。
如:
SELECT ClosingPeriod ([Date].[Calendar].[Month],[Date].[Calendar].[Calendar Year].&[2003]) ON 0
FROM [Adventure Works]
December, 2003和Tail(Descendants(2,1), 1).是等效的
3、Cousin(1,2 )表示1這個結構層次位置在2中都有哪些,即計算1這個人在2這個家庭中的堂兄妹,表兄妹等。
4、LastPeriods(Index, Member_Expression)
表示該層中指定成員和該成員之前的Index-1個成員,這些成員都屬於同一級。
CurrentMember:返回遍歷過程中指定層次結構的當前成員,有點類似於each(function(i){})中的i,一般情況下應用於引用處理。
5、Descendants
/*
descendants(成員名,級別名,標記)
對某個成員名其下的所有子級別的數據,這個子級別是一直到級別名為止。
最后的數據都是成員名下面的數據這點很重要。
SELF_AND_BEFORE:
最后的數據包括成員自己,然后該成員對於目標級別這個中間級別的各項數據,然后知道目標級別的數據
即由很多級別所對應的數據構成
*/
select [Measures].[Internet Sales Count] on columns,
descendants(
[產品].[Product Model Lines].[Model Name].&[HL Mountain Frame]
,[產品].[Product Model Lines].[English Product Name]
,SElf_and_before
)
on rows
from [Adventure Works DW]
(
Member_Expression , 成員
Level_Expression, 級別
Tag 標記
)
1.15、LastPeriods 和 元組.LastChild
/*
最后四種型號的產品在最后個客戶中的銷售量和排名
自己寫的,也不知道對不對?
*/
with
set [Last4Names] as
LastPeriods(4,[產品].[Model Name].lastChild)
set [OrdersNames] as
order([Last4Names],[Measures].[Sales Amount],DESC)
member [RanlNames] as--Model Name的排名表
rank([產品].[Model Name],[OrdersNames])
set [Last4Customer] as--最后的四個客戶名稱
LastPeriods(4,[客戶].[全名].LastChild)
select {[RanlNames],[Measures].[Sales Amount]} on columns,
order(generate
(
[Last4Customer],
(
[客戶].[全名]*[Last4Names]
),
all
)
,[RanlNames],ASC)on rows
from [Adventure Works DW]
1.16、Children和Members的區別
/*
members: 維度/級別
children:維度/成員(成員是只有具體值,下面可以有子節點)
注意點:
1、只有在維度上時,members有統計功能,而children沒有統計功能
2、層次結構根部作為特殊的維度。
說明:
1、層次結構:即維度層次結構,如時間維度的層次結構:年-月-日
2、級別:層次結構中的某一層,如上面的層次結構中,年、月、日就是級別
3、成員:某一級別中的具體值,如上面的月級別中的2月、3月。或者年級別中的2001年、2002年等。
4、總共有分:維度、層次結構、級別、成員
*/
select [Measures].[Sales Amount] on columns,
non empty
[客戶].[客戶所在地域].[國家].&[Australia].children
//[客戶].[客戶所在地域].[國家].&[Australia].members--這時候會報錯
on rows
from [Adventure Works DW]
1、members不會包含計算成員,如果要顯示計算成員可以用 .AllMembers
1.17、幾個重要的概念
1、 數據和元數據
事實數據表中的數據或行都是數據,而其他地方(在OLAP中定義的聚合,有點像計算列,是存儲在磁盤上的,不要每次加載的時候都計算)的數據都是元數據。
2、因為事實表的大小通常很大,所有要設置分區來在不同磁盤上存儲事實數據。
1.18、PeriodsToDate(Level_Expression,Member_Expression)的用法
1、有點類似於Cousin,先回顧下Cousin
Cousin(1,2 )表示1這個結構層次位置在2中都有哪些,即計算1這個人在2這個家庭中的堂兄妹,表兄妹等。它是全橫和全縱關系,而PeriodsToDate是上縱關系
_|_
|
全縱是指【親兄、親弟】,橫向是指【堂表兄、堂表弟】Cousin
|
上縱是指【親兄】(包括自己)PeriodsToDate
2、那么PeriodsToDate(級別,成員)表示:
[1]、先獲取該級別下的與該成員是同一級別的所有成員。
[2]、然后從第一個成員開始,到上面的指定成員結束
[3]、簡單點就是計算指定成員在該成員所屬的指定級別下的哥哥和自己的集合
如:
PeriodsToDate
(
[Due Date].[Calendar Date].[Calendar Semester],--級別是半年
[Due Date].[Calendar Date].[Calendar Month].&[August]&[2001]--成員是2001年的八月
)
1、計算成員所的在級別成員:計算屬於2001.8成員的半年級別成員是2001下半年這個成員([Due Date].[Calendar Date].[Calendar Semester].&[2]&[2001]),
2、計算該級別成員下同指定成員是同一級別的成員(哥哥和自己)集合:於2001.8是同一級別的下半年兄長成員和本身成員為:2001.7,2001.8這兩個成員。
所以PeriodsToDate這個函數可以用於累計計算,如十九實例所示
在 MDX 中計算累積值 (Accumulating) 尤其是按時間的累積是一個非常常見的需求
1.19、SUM
Sum(Set_Expression, Numeric_Expression)
計算Set_Expression集合中每個元素對Numeric_Expression度量的和的總計,如:
下例將返回截至 【2002 年 7 月 20 日】【 7 月份】的 Internet 銷售運費之和。
WITH
MEMBER Measures.x AS SUM
(
--返回截至 【2002 年 7 月 20 日】【當前星期】的 Internet 銷售運費之和
--WTD([Date].[Calendar].[Date].[July 20, 2002])
--返回截至 【2002 年 7 月 20 日】【 7月份】的 Internet 銷售運費之和
MTD([Date].[Calendar].[Date].[July 20, 2002])
--返回截至 【2002 年 7 月 20 日】【第三季度】的 Internet 銷售運費之和
--QTD([Date].[Calendar].[Date].[July 20, 2002])
--返回截至 【2002 年 7 月 20 日】【2002年】的 Internet 銷售運費之和
--YTD([Date].[Calendar].[Date].[July 20, 2002])
, [Measures].[Internet Freight Cost]
)
SELECT Measures.x ON 0
FROM [Adventure Works]
通常,SUM 函數與 CURRENTMEMBER 函數或 YTD 之類的函數(返回根據層次結構的當前成員而變化的集合)一起使用。比如:
1.20、IIf(Logical_Expression, Expression1, Expression2)
如果邏輯表達式為True就執行第一個表達式,否則執行第二個。
如果邏輯表達式為零,那么就其返回False。
如:
IIF([Measures].[Internet Sales Amount]>10000
, "Sales Are High", "Sales Are Low")
1.21、ParallelPeriod( Level_Expression ,Index , Member_Expression )
表示Member_Expression向前回滾Index * Level_Expression的時間
SELECT ParallelPeriod ([Date].[Calendar].[Calendar Quarter]
, 3
, [Date].[Calendar].[Month].[October 2003])
ON 0
FROM [Adventure Works]
表示2003年10月向前回滾3*季度(3*3=9),即回滾9個月,結果為2003年1月
要知道這個函數可以嵌套,假設當前同是計算某個值時,那么要求去年同期和上個月同期等,可以再次利用當前這個新定義的度量
1.22、With Member
1、 當為一個參數時,就直接返回結果
2、 當為兩個參數時,第一個為條件,第二個為目標值,如
MEMBER [Measures].[當月計划延保台次] AS
([目標類型].[目標類型名稱].&[延保台次],[Measures].[門店月目標值])
表示:求延保台次的門店月目標值,而不是其他的門店目標值
注意:若存在兩個參數,那么第一個參數必須為單一值,如果是集合,那么要用到聚合函數,比如:
member [Measures].[月達成率_整車銷售] as
sum(mtd([日期].[年-月-日]),iif([Measures].[銷售量]=null,0,[Measures].[銷售量]))
(mtd([日期].[年-月-日]),[Measures].[銷售量])--這個是錯誤的,因為第一個參數是一個集合
3、 參數的順序沒關系。
1.23、元組和集的概念
元組:
1、 用()表示,一個維度默認就是一個元組,只是這個元組沒有’()’符號。
2、 元組中的成員必須來自不同的維度。因為如果是相同維度下的成員,如果這兩個成員的值不同,那么整個元組的切片結果肯定不同,即沒意義。
3、 一個多維數據集被一個元組中的所有成員進行分割,且結果唯一。假設是作用在Columns軸中,那么對於Rows中的每一行維度都唯一確定一個結果。
集:是元組的容器
1、 用{}表示,默認一個元組就是一個集,只是這個集沒有{}標識。
2、 集中的每個元組必須來自相同的維度。這個相同的維度是指每個元組中的第N個成員的維度是一樣的,且每個成員的順序相對於維度相同性來說都是一一對應的,
3、 一個多維數據集被一個集中的不同元組分別進行切割,且結果個數為元組個數N。假設是作用在Columns軸中,那么對於Rows中的每一行都有N個橫向的列,每一列對應一個元組與該行維度切片后的唯一結果。
舉例說明:
1、([產品].[Model Name],[客戶].[教育])
表示一個元組,且有兩個維度成員。正確
顯示:如果作用列軸,那么對於每一行都只有一個單元格的結果。
如果作用在行軸,那么對於每一列有且只有一個單元格的結果
2、{([產品].[Model Name],[客戶].[教育])}
表示一個集,且該集中有一個元組,且該元組中有兩個維度成員。該語句也正確
顯示:同上
3、{[產品].[Model Name],[客戶].[教育]}
表示一個集,且集中有兩個元組,該語句是不正確的,因為兩個元組具有不相同的維度。
假設該語句中具有兩個相同維度的元組,那么該語句正確,且
顯示: 如果作用列軸,那么對於每一行都有兩個(因為有兩個元組)單元格的結果。
如果作用在行軸,那么對於每一列都有兩個個單元格的結果
一個元組中的多個維度成員共同進行切片,結果只有一個。而集中的多個元組分別進行切片,且分別顯示結果。
1.24、CrossJoin(set,set):用於構造集
使用場合:在用到三維或以上的時候就可以用這個函數來構造新的多維數據集。
原 理:對於第一個集中的每個結果都於第二個集中的每一個結果進行組合,得到最后的結果。有點類似於笛卡爾積,但是又不全是笛卡爾積。