惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
U
Unit 42
GbyAI
GbyAI
M
MIT News - Artificial intelligence
美团技术团队
罗磊的独立博客
雷峰网
雷峰网
量子位
博客园 - 【当耐特】
Last Week in AI
Last Week in AI
D
Docker
小众软件
小众软件
S
SegmentFault 最新的问题
Blog — PlanetScale
Blog — PlanetScale
阮一峰的网络日志
阮一峰的网络日志
宝玉的分享
宝玉的分享
T
Tailwind CSS Blog
WordPress大学
WordPress大学
V
V2EX
博客园_首页
腾讯CDC
The Cloudflare Blog
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

博客园 - anchky

招聘.Net或者Php工程师(可兼职) AMO添加维度属性、层次结构 求Tech·Ed 2007微软技术大会,上海站的票一张 在杭州的日子,每天数据挖掘 - anchky - 博客园 推荐Minesage的BI原创资源 OLAP项目的一般过程 Code For MiningStructure DataMining Digest 分解分析树,KPIs 用OWC展示多维数据集 MDX函数使用介绍(四):字符串函数&元组函数 在2005中使用DrillThrough函数 MDX函数使用介绍(三):聚合函数 在AS2005的From子句中使用Select从句 MDX 函数的使用介绍(二):数值函数 通过http访问AS的server端配置(AS2000) MDX 函数的使用介绍(一) Some Digest From MDX Solution 推荐一个Blog“Microsoft SQL Server Development Customer Advisory Team”
文摘 MDX Solutions
anchky · 2006-11-24 · via 博客园 - anchky
 

 

1.     

[Measures].[Sales Sum] / [Measures].[Item Count]

If you need to take a simple average of values associated with a set of cells,

you can use the MDX Avg() function, as in the following example:

WITH

SET [My States] AS

{ [Customer].[MA], [Customer].[ME], [Customer].[MI], [Customer].[MO] }

MEMBER [Customer].[Avg Over States] AS Avg ([My States])

SELECT

{ [Measures].[Dollar Sales], [Measures].[Unit Sales] } on columns,

{ [Products].[Family].Members } on rows

FROM Sales

WHERE ([Customer].[Avg Over States])

This query returns a grid of three measures by N product families. The sales, units, and profit measures are each averaged over the five best customers in terms of total profit. Notice that the expression to be averaged by the Avg() function has been left unspecified in the [Avg Over States] calculation. Leaving it unspecified is the equivalent of saying:

([Measures].CurrentMember, [Products].CurrentMember , . . . )

 

2.     

Sum (

CrossJoin(

Descendants ([Industry].CurrentMember, [Industry].[Company],

SELF),

Descendants ([Time].CurrentMember, [Time].[Day], SELF)

)

,([Measures].[Share Price] * [Measures].[Units Sold])

) / [Measures].[Units Sold]

will calculate this weighted average.

A difficulty lurks in formulating the query this way, however. The greater the number of dimensions you are including in the average, the larger the size of the cross-joined set. You can run into performance problems (as well as intelligibility problems) if the number of dimensions being combined is large and the server actually builds the cross-joined set in memory while executing this. Moreover, you should account for all dimensions in the cube or you may accidentally involve aggregate [Share Price] values in a multiplication, which will probably be an error. In Analysis Services 2005, you can improve this by using NonEmpty() around a cross-join, as follows:

NonEmpty (

{ [Measures].[Share Price], [Measures].[Units Sold])}

* Descendants ([Industry].CurrentMember,

[Industry].[Company], SELF)

* Descendants ([Time].CurrentMember, [Time].[Day], SELF)

* Descendants ([Customer].CurrentMember, [Time].[Day], SELF))

)

3.    同比(时间)

The following is equally valid, and its results are shown in Figure 3-4. Note that the Q4 difference is based on Q3 and Q4 expenses, whereas each month’s difference is based on its expenses and the prior month’s expenses.

WITH MEMBER [Measures].[Unit Sales Increase] AS

[Measures].[Unit Sales]

- ([Measures].[Unit Sales], [Time].CurrentMember.PrevMember)

SELECT

{ [Time].[Q4, 2005], [Time].[Q4, 2005].Children } on columns,

{ [Measures].[Unit Sales], [Measures].[Unit Sales Increase] }

on rows

FROM Sales

 

4.    环比

PeriodsToDate ( [Time].[Year], [Time].CurrentMember ),

[Measures].[Dollar Sales]

)

SELECT

{ [Time].[Quarter].[Q3, 2000], [Time].[Quarter].[Q4, 2000],

[Time].[Quarter].[Q1, 2001]

} on columns,

{ [Measures].[Expenses], [Measures].[YTD Expenses] } on rows

FROM Costing

Note that the [Unit Sales YAgo Increase] for Q1, 2005 is the difference

in first-quarter sales, whereas the [Unit Sales YAgo Increase] for Jan,

2005 is the difference in January sales.

5.    Year-to-Date (Period-to-Date) Aggregations

WITH MEMBER [Measures].[YTD Dollar Sales] AS

Sum (

PeriodsToDate ( [Time].[Year], [Time].CurrentMember ),

[Measures].[Dollar Sales]

)

SELECT

{ [Time].[Quarter].[Q3, 2000], [Time].[Quarter].[Q4, 2000],

[Time].[Quarter].[Q1, 2001]

} on columns,

{ [Measures].[Expenses], [Measures].[YTD Expenses] } on rows

FROM Costing

If the time dimension is tagged as being of Time type and the year level within it is tagged as being of type Year, then you could also use the shorthand:

Sum (

YTD ([Time].CurrentMember),

[Measures].[Expenses]

)

or even:

Sum (

YTD (),

[Measures].[Expenses]

)

6.     

For example, the following returns

all months from the first month in the time dimension to July, 2005:

{ NULL : [Time].[Jul, 2005] }

In a more standard way, you can reference the first member at the current level of the time dimension with one of the following expressions:

[Time].CurrentMember.Level.Members.Item(0)

OpeningPeriod ([Time].[All Time], [Time].CurrentMember.Level)

OpeningPeriod ([Time], [Time].CurrentMember.Level) The first way takes the level of the current time member, gets its members, and selects the first member in it, whereas the second one simply asks for the opening period at the current member’s level across all times.

The second way also requires an All level in the time dimension, which may or may not be defined. Using the second approach, you could specify:

WITH MEMBER [Measures].[All Accumulated Unit Sales] AS

Sum (

{ OpeningPeriod ([Time].CurrentMember.Level, [Time].[All Time])

: [Time].CurrentMember },

[Measures].[Expenses]

)

SELECT

{ [Time].[Quarter].[Q3, 2005], [Time].[Quarter].[Q4, 2005]

} on columns,

{ [Measures].[Unit Sales], [Measures].[All Accumulated Unit Sales] } on

rows

FROM Sales

The most direct way, if the time dimension has an All level, is simply to use

PeriodsToDate() with the [Time].[(All)] level:

WITH MEMBER [Measures].[All Accumulated Expenses] AS

Sum (

PeriodsToDate ( [Time].[(All)], [Time].CurrentMember ),

[Measures].[Expenses]

)

SELECT

...

7.     

in Analysis Services 2005, attribute members are tightly linked to base dimension members, so that the current member of the base dimension influences the current member of the attribute member. So we could filter product SKUs by their ship weight with the following as well:

Filter (

[Product].[ByCategory].[SKU].Members,

[Product].[ShipWeight].CurrentMember.MemberValue

>= 1

AND

[Product].[ShipWeight].CurrentMember.MemberValue

<= 5

)

Remember that member properties are defined for a particular level, but when you reference them through the .Properties() function, only the name is of interest, not the unique name. This means that if the same property name is in two or more levels, all of them will return a result when referenced through the .Properties() function. In the case of parent-child dimensions, a member property is defined for every apparent level (except perhaps the All level, depending on the dimension definition), because internally, all parent-child members are stored in one database level. Every query passes through five main execution stages after the query is successfully parsed. The stages, in order, are

1. Resolving the FROM clause (if any—it is optional in Essbase)

2. Resolving the WHERE clause, if any

3. Resolving named sets in the WITH clause

4. Resolving the tuples on each axis

5. Calculating the cells brought back in the axis intersections

a. Resolving NON EMPTY intersections

b. (AS2005) Resolving the HAVING clause on each axis

Physically, there is no requirement that this is the required order, but logically

this is the sequence. Figure 4-1 provides a conceptual flowchart of the

process.

Along the way, there is always a default cell context and a default iteration context. This starts from outside the query and is always carried from one stage to the next. Each stage can modify this context before passing on to the next stage.

8.     

SELECT

{[Product].[Health], [Product].[Shaving]}

on axis(0)

FROM [Sales]

WHERE ([Time].[2005], [Measures].[Dollar Sales])

After the slicer is evaluated, the cell context used in evaluating the product

members is still:

( Time.[2005],

Product.DefaultMember,

Customer.DefaultMember,

Promotion.DefaultMember,

Measures.[Dollar Sales]

)

Because the axis is defined by enumerating member names, it doesn’t matter what the cell context is. Once the axis is resolved, the cell data can be pulled back. The two tuples effectively pulled back are shown in Figure 4-4.

 

9.     

SELECT

Filter (

[Product].[Category].Members,

[Measures].[Dollars Sold] > 900000

)

on axis(0)

FROM Sales

WHERE ([Time].[2005], [Measures].[Dollars Sold])

The cell context after the WHERE clause is resolved as before. This means that when the Filter() is executing, the values associated with the members are as follows.

The data values that are compared to 900,000 are from the tuples shown in Figure 4-5. Note that the cell context set up by the slicer is passed along during the evaluation of the axis. Once the filter has returned a set of members, the axis is resolved and you will see the results, as shown in Figure 4-6.

Within the Filter(), you can take this context tuple and modify it. Consider the following query, which filters the product categories where Dollar Sales increased more than 40 percent from the previous year:

SELECT

Filter (

[Product].[Category].Members,

[Measures].[Dollar Sales] >

1.4 *

( [Measures].[Dollar Sales],

[Time].CurrentMember.PrevMember )

)

on axis(0)

FROM Sales

WHERE ([Time].[2005], [Measures].[Dollar Sales])

The slicer sets up ([Time].[2005], [Measures].[Dollar Sales])

again. Within the filter, the Dollar Sales are compared to the Dollar Sales from

the previous time member. As the time component of the context is [2005],the previous time member will be 2004. Inside this filter, the comparisons made are shown in Figure 4-7.

Because the context carries one member from each dimension in it, you can rely even more on it in your expressions. Aquery that performs the same work as the previous query, but phrased in a different way, is as follows:

SELECT

Filter (

[Product].[Category].Members,

[Time].CurrentMember >

1.4 * [Time].CurrentMember.PrevMember

)

on axis(0)

FROM Sales

WHERE ([Time].[2005], [Measures].[Dollar Sales])

The Filter()’s comparison expression doesn’t refer to any fixed points at all. Because the context of the Filter() includes [Measures].[Dollar

Sales], that is what is used. You would choose to build a query this way if you only wanted to specify the measure in one place. Looking at this as an example of a Filter() expression more than as a complete query, you also might use it against multiple measures without needing to edit it.

10.             

Just because the slicer provides context doesn’t mean you need to use it. Consider the following query with important portions underlined, and whose results are in Figure 4-8:

SELECT

{ Filter (

[Product].[Category].Members,

([Measures].[Unit Sales], [Time].[Q4, 2005])

> 1.4 * ([Measures].[Unit Sales],

[Time].[Q4, 2004] )

) }

on axis(0)

FROM Sales

WHERE ([Time].[2005], [Measures].[Dollar Sales])



The slicer sets up ([Time].[2005] and [Measures].[Dollar Sales]),

but the Filter() expression compares [Measures].[Unit Sales] at

[Time].[Q4, 2005] and [Time].[Q4, 2004]. The expressions used in the

Filter(), or in any other part of deciding an axis, can selectively rely on or override any portion of the cell context. So the results are Dollar Sales in 2005, but the filter condition was entirely on Unit Sales from other time periods. Although we have been highlighting the columns axis, the following is true for all axes:

■■ Evaluation of each axis takes a cell context from the WHERE clause.

■■ Each axis evaluates independently from the others (except in Analysis

Services when influenced by the Axis() function).

Resolving each axis can involve the computation of an arbitrary number of cells, depending on the expressions involved. Once the axes are resolved, each cell that is retrieved is identified by the tuple formed by combining each axis’ tuple for that cell with the slicer. Any

dimension not explicitly mapped to a tuple has its default member in the slicer.