Performing Advanced Set Construction
Assembling Sets with the Generate Function
如果你對C#或者VB 等其它變成語言熟悉的話,應該對循環比較熟悉。在循環中,可以遍歷集合里的每一個對象,在遍歷的時候,對對象會執行一些操作。換一種方式來看MDX SET中的元組就如同看集合中的對象,使用 SET集合的一些表達式來執行一些操作,對 Generate 函數來說這個可能就是對它的一個初步概念和認識。
Generate ({Set}, {Set Expression} [, ALL])
在Generate 函數中迭代的 SET 集合中的每一個元組,都會參與到一個基於 SET 集合的表達式中計算。每一次迭代返回的一個集合都會和其它迭代后產生的集合連接起來重新組成一個新的集合並返回,ALL 關鍵字的作用就是定義是否需要保留重復的元組。
使用Generate 函數的機會不是非常的多,但是如果碰到需要循環迭代的邏輯,這時就需要考慮是否需要使用Generate 來解決一些問題。
示例一 - 先看一個簡單的查詢 Reseller Sales 銷售前5的產品
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, TopCount( {[Product].[Product].[Product].Members}, 5, ([Measures].[Reseller Sales Amount]) ) ON ROWS FROM [Step-by-Step];
這個示例在之前的章節中一直在使用,觀察一下這個查詢返回的都是自行車,當然事先並不知道返回的一定就是自行車。如果我們想查詢每個產品分類下前5名銷售的產品,可以使用 Generate 函數。
示例二
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, Generate( {[Product].[Category].[Category].Members}, TopCount( {[Product].[Product].[Product].Members}, 5, ([Measures].[Reseller Sales Amount]) ) ) ON ROWS FROM [Step-by-Step]
這次查詢的結果如上圖所示和之前查詢的結果完全一樣,如何解釋這個問題? 我們加上 ALL 關鍵字。
示例三 – 帶 ALL 的 Generate 函數
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, Generate( {[Product].[Category].[Category].Members}, TopCount( {[Product].[Product].[Product].Members}, 5, ([Measures].[Reseller Sales Amount]) ), ALL ) ON ROWS FROM [Step-by-Step]
這個查詢結果應該是一個包含有20個產品的集合,因為首先我們的產品分類有四種,我們可以看到Generate 函數的第一個參數是一個集合{[Product].[Category].[Category].Members} 有四個成員。
四個成員就意味着有四輪循環,每一輪循環中經過 TopCount 函數會返回5個產品信息,那么總共有20個成員的集合返回。由於在 TopCount 函數中取銷售最多的前5名產品的過程中,沒有使用到 Category 這個上下文環境,那么這樣就造成了每個迭代過程中取銷售前5名的范圍都是在所有產品中取。這樣循環4次每次取到的結果都是一樣,我們使用 ALL 關鍵字就看得出來這幾次循環取的產品是一樣的。因為在上一個示例中,在 Generate 函數中並沒有使用 All 函數,因此重復的元組被自動的剔出掉, 所以最終的結果是只返回了5個產品。
為了解決這個問題,我們應該記得在 MDX Step by Step 讀書筆記(五) - Working with Expressions (MDX 表達式) - CurrentMember - Properties - Existing 的使用 中講解了 Existing 關鍵字的作用,它可以強制當前集合關聯到上下文環境。在這個例子中,什么是上下文環境?Category 就是上下文環境,要求在每個Category的上下文環境(可以理解為查詢范圍)中來查詢前5的產品。
示例四 – 在 Generate 函數中使用 Existing 上下文環境的應用
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, Generate( {[Product].[Category].[Category].Members}, TopCount( EXISTING {[Product].[Product].[Product].Members}, 5, ([Measures].[Reseller Sales Amount]) ), ALL ) ON ROWS FROM [Step-by-Step]
這樣就查詢出來了,但是查詢結果看得有點費勁,因此再改一改。
示例五 – 使用 Existing 的 Generate 函數
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, Generate( {[Product].[Category].[Category].Members}, {[Product].[Category].CurrentMember}* TopCount( EXISTING {[Product].[Product].[Product].Members}, 5, ([Measures].[Reseller Sales Amount]) ), ALL ) ON ROWS FROM [Step-by-Step];
這樣就可以看到它們各自的分類以及分類下前5的產品。
Assembling Sets with the Extract Function
Extract 函數的主要作用就是從一個集合中根據其它的層次結構來抽取元組並形成一個新的集合。
Extract ({Set}, Hierarchy1 [, Hierarchy2, .. HierarchyN])
第一個參數是一個集合,第二個參數以后都是屬性層次結構。相當於比如集合中的元組由 Product 和 Calendar 這兩個成員組成,假設第二個參數是 Product 層次結構,那么最后的結構就是將集合中與 Product 層次結構關聯的那部分元組(即Product成員)取出,而 Calendar 成員將被排除在返回的集合中。這個操作與 CrossJoin 的操作正好相反,CrossJoin 是兩組集合相結合,而 Extract是按照提供的層次結構對集合進行分解。
示例一 – 先看使用 * 或者 CrossJoin 的示例
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, {[Product].[Product].[Product].Members} * {[Date].[Calendar].[Month].Members} ON ROWS FROM [Step-by-Step]
在這個查詢中,可以看到月份和產品結合后 Reseller Sales 的情況。這個查詢的數據量可能有點多,那么我們可能更希望關注那些賣的比較不錯的產品,比如查詢那些大於 16000 的產品。
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, Filter( {[Product].[Product].[Product].Members} * {[Date].[Calendar].[Month].Members}, ([Measures].[Reseller Sales Amount])>160000 ) ON ROWS FROM [Step-by-Step]
這下可以看清楚一些,行中有兩列組成,一列是來源於{[Product].[Product].[Product].Members} 一列來源於{[Date].[Calendar].[Month].Members} 它們通過 CrossJoin 關聯起來。那么如果我們在這里只想看到 Product 或者 Date 方面的內容,那么就需要對這個查詢結果進行拆分。
示例二 – 使用 Extract 根據層次結構分拆集合
SELECT {([Measures].[Reseller Sales Amount])} ON COLUMNS, Extract( Filter( {[Product].[Product].[Product].Members} * {[Date].[Calendar].[Month].Members}, ([Measures].[Reseller Sales Amount])>160000 ), [Product].[Product] ) ON ROWS FROM [Step-by-Step]
對比上一個例子,抽取出來的部分只有產品部分內容,並且它們是唯一的。因為對比上一個示例,一個產品在多個月份都有數據,現在只提取產品部分,那么它們的數據將自動合並累加到一個唯一的產品了。
更多 BI 文章請參看 BI 系列隨筆列表 (SSIS, SSRS, SSAS, MDX, SQL Server) 如果覺得這篇文章看了對您有幫助,請幫助推薦,以方便他人在 BIWORK 博客推薦欄中快速看到這些文章。