mondrian-olap 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/.rspec +2 -0
  2. data/Gemfile +15 -0
  3. data/LICENSE-Mondrian.html +259 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.rdoc +219 -0
  6. data/RUNNING_TESTS.rdoc +41 -0
  7. data/Rakefile +46 -0
  8. data/VERSION +1 -0
  9. data/lib/mondrian-olap.rb +1 -0
  10. data/lib/mondrian/jars/commons-collections-3.1.jar +0 -0
  11. data/lib/mondrian/jars/commons-dbcp-1.2.1.jar +0 -0
  12. data/lib/mondrian/jars/commons-logging-1.0.4.jar +0 -0
  13. data/lib/mondrian/jars/commons-math-1.0.jar +0 -0
  14. data/lib/mondrian/jars/commons-pool-1.2.jar +0 -0
  15. data/lib/mondrian/jars/commons-vfs-1.0.jar +0 -0
  16. data/lib/mondrian/jars/eigenbase-properties.jar +0 -0
  17. data/lib/mondrian/jars/eigenbase-resgen.jar +0 -0
  18. data/lib/mondrian/jars/eigenbase-xom.jar +0 -0
  19. data/lib/mondrian/jars/javacup.jar +0 -0
  20. data/lib/mondrian/jars/log4j-1.2.8.jar +0 -0
  21. data/lib/mondrian/jars/log4j.properties +18 -0
  22. data/lib/mondrian/jars/mondrian.jar +0 -0
  23. data/lib/mondrian/jars/olap4j.jar +0 -0
  24. data/lib/mondrian/olap.rb +14 -0
  25. data/lib/mondrian/olap/connection.rb +122 -0
  26. data/lib/mondrian/olap/cube.rb +236 -0
  27. data/lib/mondrian/olap/query.rb +313 -0
  28. data/lib/mondrian/olap/result.rb +155 -0
  29. data/lib/mondrian/olap/schema.rb +158 -0
  30. data/lib/mondrian/olap/schema_element.rb +123 -0
  31. data/mondrian-olap.gemspec +116 -0
  32. data/spec/connection_spec.rb +56 -0
  33. data/spec/cube_spec.rb +259 -0
  34. data/spec/fixtures/MondrianTest.xml +128 -0
  35. data/spec/fixtures/MondrianTestOracle.xml +128 -0
  36. data/spec/query_spec.rb +582 -0
  37. data/spec/rake_tasks.rb +185 -0
  38. data/spec/schema_definition_spec.rb +345 -0
  39. data/spec/spec_helper.rb +67 -0
  40. data/spec/support/matchers/be_like.rb +24 -0
  41. metadata +217 -0
@@ -0,0 +1,259 @@
1
+ require "spec_helper"
2
+
3
+ describe "Cube" do
4
+ before(:all) do
5
+ @schema = Mondrian::OLAP::Schema.define do
6
+ cube 'Sales' do
7
+ table 'sales'
8
+ dimension 'Gender', :foreign_key => 'customer_id' do
9
+ hierarchy :has_all => true, :primary_key => 'id' do
10
+ table 'customers'
11
+ level 'Gender', :column => 'gender', :unique_members => true
12
+ end
13
+ end
14
+ dimension 'Customers', :foreign_key => 'customer_id' do
15
+ hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
16
+ table 'customers'
17
+ level 'Country', :column => 'country', :unique_members => true
18
+ level 'State Province', :column => 'state_province', :unique_members => true
19
+ level 'City', :column => 'city', :unique_members => false
20
+ level 'Name', :column => 'fullname', :unique_members => true
21
+ end
22
+ end
23
+ calculated_member 'Non-USA' do
24
+ dimension 'Customers'
25
+ formula '[Customers].[All Customers] - [Customers].[USA]'
26
+ end
27
+ dimension 'Time', :foreign_key => 'time_id', :type => 'TimeDimension' do
28
+ hierarchy :has_all => false, :primary_key => 'id' do
29
+ table 'time'
30
+ level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
31
+ level 'Quarter', :column => 'quarter', :unique_members => false, :level_type => 'TimeQuarters'
32
+ level 'Month', :column => 'month_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeMonths'
33
+ end
34
+ hierarchy 'Weekly', :has_all => false, :primary_key => 'id' do
35
+ table 'time'
36
+ level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
37
+ level 'Week', :column => 'weak_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeWeeks'
38
+ end
39
+ end
40
+ measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum'
41
+ measure 'Store Sales', :column => 'store_sales', :aggregator => 'sum'
42
+ end
43
+ end
44
+ @olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
45
+ end
46
+
47
+ it "should get all cube names" do
48
+ @olap.cube_names.should == ['Sales']
49
+ end
50
+
51
+ it "should get cube by name" do
52
+ @olap.cube('Sales').should be_a(Mondrian::OLAP::Cube)
53
+ end
54
+
55
+ it "should return nil when getting cube with invalid name" do
56
+ @olap.cube('invalid').should be_nil
57
+ end
58
+
59
+ it "should get cube name" do
60
+ @olap.cube('Sales').name.should == 'Sales'
61
+ end
62
+
63
+ describe "dimensions" do
64
+ before(:all) do
65
+ @cube = @olap.cube('Sales')
66
+ @dimension_names = ['Measures', 'Gender', 'Customers', 'Time']
67
+ end
68
+
69
+ it "should get dimension names" do
70
+ @cube.dimension_names.should == @dimension_names
71
+ end
72
+
73
+ it "should get dimensions" do
74
+ @cube.dimensions.map{|d| d.name}.should == @dimension_names
75
+ end
76
+
77
+ it "should get dimension by name" do
78
+ @cube.dimension('Gender').name.should == 'Gender'
79
+ end
80
+
81
+ it "should get dimension full name" do
82
+ @cube.dimension('Gender').full_name.should == '[Gender]'
83
+ end
84
+
85
+ it "should get measures dimension" do
86
+ @cube.dimension('Measures').should be_measures
87
+ end
88
+
89
+ it "should get dimension type" do
90
+ @cube.dimension('Gender').dimension_type.should == :standard
91
+ @cube.dimension('Time').dimension_type.should == :time
92
+ @cube.dimension('Measures').dimension_type.should == :measures
93
+ end
94
+ end
95
+
96
+ describe "dimension hierarchies" do
97
+ before(:all) do
98
+ @cube = @olap.cube('Sales')
99
+ end
100
+
101
+ it "should get hierarchies" do
102
+ hierarchies = @cube.dimension('Gender').hierarchies
103
+ hierarchies.size.should == 1
104
+ hierarchies[0].name.should == 'Gender'
105
+ end
106
+
107
+ it "should get hierarchy names" do
108
+ @cube.dimension('Time').hierarchy_names.should == ['Time', 'Time.Weekly']
109
+ end
110
+
111
+ it "should get hierarchy by name" do
112
+ @cube.dimension('Time').hierarchy('Time.Weekly').name.should == 'Time.Weekly'
113
+ end
114
+
115
+ it "should get default hierarchy" do
116
+ @cube.dimension('Time').hierarchy.name.should == 'Time'
117
+ end
118
+
119
+ it "should get hierarchy levels" do
120
+ @cube.dimension('Customers').hierarchy.levels.map(&:name).should == ['(All)', 'Country', 'State Province', 'City', 'Name']
121
+ end
122
+
123
+ it "should get hierarchy level names" do
124
+ @cube.dimension('Time').hierarchy.level_names.should == ['Year', 'Quarter', 'Month']
125
+ @cube.dimension('Customers').hierarchy.level_names.should == ['(All)', 'Country', 'State Province', 'City', 'Name']
126
+ end
127
+
128
+ it "should get hierarchy level depths" do
129
+ @cube.dimension('Customers').hierarchy.levels.map(&:depth).should == [0, 1, 2, 3, 4]
130
+ end
131
+
132
+ it "should get hierarchy level members count" do
133
+ @cube.dimension('Gender').hierarchy.levels.map(&:members_count).should == [1, 2]
134
+ end
135
+ end
136
+
137
+ describe "hierarchy values" do
138
+ before(:all) do
139
+ @cube = @olap.cube('Sales')
140
+ end
141
+
142
+ it "should get hierarchy all member" do
143
+ @cube.dimension('Gender').hierarchy.has_all?.should be_true
144
+ @cube.dimension('Gender').hierarchy.all_member_name.should == 'All Genders'
145
+ end
146
+
147
+ it "should not get all member for hierarchy without all member" do
148
+ @cube.dimension('Time').hierarchy.has_all?.should be_false
149
+ @cube.dimension('Time').hierarchy.all_member_name.should be_nil
150
+ end
151
+
152
+ it "should get hierarchy root members" do
153
+ @cube.dimension('Gender').hierarchy.root_members.map(&:name).should == ['All Genders']
154
+ @cube.dimension('Gender').hierarchy.root_member_names.should == ['All Genders']
155
+ @cube.dimension('Time').hierarchy.root_members.map(&:name).should == ['2010', '2011']
156
+ @cube.dimension('Time').hierarchy.root_member_names.should == ['2010', '2011']
157
+ end
158
+
159
+ it "should return child members for specified member" do
160
+ @cube.dimension('Gender').hierarchy.child_names('All Genders').should == ['F', 'M']
161
+ @cube.dimension('Customers').hierarchy.child_names('USA', 'OR').should ==
162
+ ["Albany", "Beaverton", "Corvallis", "Lake Oswego", "Lebanon", "Milwaukie",
163
+ "Oregon City", "Portland", "Salem", "W. Linn", "Woodburn"]
164
+ end
165
+
166
+ it "should return child members for hierarchy" do
167
+ @cube.dimension('Gender').hierarchy.child_names.should == ['F', 'M']
168
+ end
169
+
170
+ it "should not return child members for leaf member" do
171
+ @cube.dimension('Gender').hierarchy.child_names('All Genders', 'F').should == []
172
+ end
173
+
174
+ it "should return nil as child members if parent member not found" do
175
+ @cube.dimension('Gender').hierarchy.child_names('N').should be_nil
176
+ end
177
+
178
+ end
179
+
180
+ describe "level members" do
181
+ before(:all) do
182
+ @cube = @olap.cube('Sales')
183
+ end
184
+
185
+ it "should get primary hierarchy level members" do
186
+ @cube.dimension('Customers').hierarchy.level('Country').members.
187
+ map(&:name).should == ['Canada', 'Mexico', 'USA']
188
+ end
189
+
190
+ it "should get secondary hierarchy level members" do
191
+ @cube.dimension('Time').hierarchy('Time.Weekly').level('Year').members.
192
+ map(&:name).should == ['2010', '2011']
193
+ end
194
+ end
195
+
196
+ describe "members" do
197
+ before(:all) do
198
+ @cube = @olap.cube('Sales')
199
+ end
200
+
201
+ it "should return member for specified full name" do
202
+ @cube.member('[Gender].[All Genders]').name.should == 'All Genders'
203
+ @cube.member('[Customers].[USA].[OR]').name.should == 'OR'
204
+ end
205
+
206
+ it "should not return member for invalid full name" do
207
+ @cube.member('[Gender].[invalid]').should be_nil
208
+ end
209
+
210
+ it "should return child members for member" do
211
+ @cube.member('[Gender].[All Genders]').children.map(&:name).should == ['F', 'M']
212
+ @cube.member('[Customers].[USA].[OR]').children.map(&:name).should ==
213
+ ["Albany", "Beaverton", "Corvallis", "Lake Oswego", "Lebanon", "Milwaukie",
214
+ "Oregon City", "Portland", "Salem", "W. Linn", "Woodburn"]
215
+ end
216
+
217
+ it "should return empty children array if member does not have children" do
218
+ @cube.member('[Gender].[All Genders].[F]').children.should be_empty
219
+ end
220
+
221
+ it "should return member depth" do
222
+ @cube.member('[Customers].[All Customers]').depth.should == 0
223
+ @cube.member('[Customers].[USA]').depth.should == 1
224
+ @cube.member('[Customers].[USA].[CA]').depth.should == 2
225
+ end
226
+
227
+ it "should return descendants for member at specified level" do
228
+ @cube.member('[Customers].[Mexico]').descendants_at_level('City').map(&:name).should ==
229
+ ["San Andres", "Santa Anita", "Santa Fe", "Tixapan", "Acapulco", "Guadalajara",
230
+ "Mexico City", "Tlaxiaco", "La Cruz", "Orizaba", "Merida", "Camacho", "Hidalgo"]
231
+ end
232
+
233
+ it "should not return descendants for member when upper level specified" do
234
+ @cube.member('[Customers].[Mexico].[DF]').descendants_at_level('Country').should be_nil
235
+ end
236
+
237
+ it "should be drillable when member has descendants" do
238
+ @cube.member('[Customers].[USA]').should be_drillable
239
+ end
240
+
241
+ it "should not be drillable when member has no descendants" do
242
+ @cube.member('[Gender].[F]').should_not be_drillable
243
+ end
244
+
245
+ it "should not be drillable when member is calculated" do
246
+ @cube.member('[Customers].[Non-USA]').should_not be_drillable
247
+ end
248
+
249
+ it "should be calculated when member is calculated" do
250
+ @cube.member('[Customers].[Non-USA]').should be_calculated
251
+ end
252
+
253
+ it "should not be calculated when normal member" do
254
+ @cube.member('[Customers].[USA]').should_not be_calculated
255
+ end
256
+
257
+ end
258
+
259
+ end
@@ -0,0 +1,128 @@
1
+ <?xml version="1.0"?>
2
+ <Schema name="MondrianTest">
3
+ <Dimension name="Time" type="TimeDimension">
4
+ <Hierarchy hasAll="false" primaryKey="id">
5
+ <Table name="time"/>
6
+ <Level name="Year" column="the_year" type="Numeric" uniqueMembers="true"
7
+ levelType="TimeYears"/>
8
+ <Level name="Quarter" column="quarter" uniqueMembers="false"
9
+ levelType="TimeQuarters"/>
10
+ <Level name="Month" column="month_of_year" uniqueMembers="false" type="Numeric"
11
+ levelType="TimeMonths"/>
12
+ </Hierarchy>
13
+ <Hierarchy hasAll="true" name="Weekly" primaryKey="id">
14
+ <Table name="time"/>
15
+ <Level name="Year" column="the_year" type="Numeric" uniqueMembers="true"
16
+ levelType="TimeYears"/>
17
+ <Level name="Week" column="week_of_year" type="Numeric" uniqueMembers="false"
18
+ levelType="TimeWeeks"/>
19
+ <Level name="Day" column="day_of_month" uniqueMembers="false" type="Numeric"
20
+ levelType="TimeDays"/>
21
+ </Hierarchy>
22
+ </Dimension>
23
+
24
+ <Dimension name="Product">
25
+ <Hierarchy hasAll="true" primaryKey="id" primaryKeyTable="products">
26
+ <Join leftKey="product_class_id" rightKey="id">
27
+ <Table name="products"/>
28
+ <Table name="product_classes"/>
29
+ </Join>
30
+ <Level name="Product Family" table="product_classes" column="product_family"
31
+ uniqueMembers="true"/>
32
+ <Level name="Product Department" table="product_classes" column="product_department"
33
+ uniqueMembers="false"/>
34
+ <Level name="Product Category" table="product_classes" column="product_category"
35
+ uniqueMembers="false"/>
36
+ <Level name="Product Subcategory" table="product_classes" column="product_subcategory"
37
+ uniqueMembers="false"/>
38
+ <Level name="Brand Name" table="products" column="brand_name" uniqueMembers="false"/>
39
+ <Level name="Product Name" table="products" column="product_name"
40
+ uniqueMembers="true"/>
41
+ </Hierarchy>
42
+ </Dimension>
43
+
44
+ <Cube name="Sales" defaultMeasure="Unit Sales">
45
+ <Table name="sales"/>
46
+ <DimensionUsage name="Time" source="Time" foreignKey="time_id"/>
47
+ <DimensionUsage name="Product" source="Product" foreignKey="product_id"/>
48
+ <Dimension name="Customers" foreignKey="customer_id">
49
+ <Hierarchy hasAll="true" allMemberName="All Customers" primaryKey="id">
50
+ <Table name="customers"/>
51
+ <Level name="Country" column="country" uniqueMembers="true"/>
52
+ <Level name="State Province" column="state_province" uniqueMembers="true"/>
53
+ <Level name="City" column="city" uniqueMembers="false"/>
54
+ <Level name="Name" column="id" type="Numeric" uniqueMembers="true">
55
+ <NameExpression>
56
+ <SQL dialect="oracle">
57
+ fname || ' ' || lname
58
+ </SQL>
59
+ <SQL dialect="postgres">
60
+ "fname" || ' ' || "lname"
61
+ </SQL>
62
+ <SQL dialect="mysql">
63
+ CONCAT(`customer`.`fname`, ' ', `customer`.`lname`)
64
+ </SQL>
65
+ <SQL dialect="generic">
66
+ fullname
67
+ </SQL>
68
+ </NameExpression>
69
+ <OrdinalExpression>
70
+ <SQL dialect="oracle">
71
+ fname || ' ' || lname
72
+ </SQL>
73
+ <SQL dialect="postgres">
74
+ "fname" || ' ' || "lname"
75
+ </SQL>
76
+ <SQL dialect="mysql">
77
+ CONCAT(`customer`.`fname`, ' ', `customer`.`lname`)
78
+ </SQL>
79
+ <SQL dialect="generic">
80
+ fullname
81
+ </SQL>
82
+ </OrdinalExpression>
83
+ <Property name="Gender" column="gender"/>
84
+ </Level>
85
+ </Hierarchy>
86
+ </Dimension>
87
+ <Dimension name="Gender" foreignKey="customer_id">
88
+ <Hierarchy hasAll="true" allMemberName="All Gender" primaryKey="id">
89
+ <Table name="customers"/>
90
+ <Level name="Gender" column="gender" uniqueMembers="true"/>
91
+ </Hierarchy>
92
+ </Dimension>
93
+
94
+ <Measure name="Unit Sales" column="unit_sales" aggregator="sum"
95
+ formatString="Standard"/>
96
+ <Measure name="Store Cost" column="store_cost" aggregator="sum"
97
+ formatString="#,###.00"/>
98
+ <Measure name="Store Sales" column="store_sales" aggregator="sum"
99
+ formatString="#,###.00"/>
100
+ <Measure name="Sales Count" column="product_id" aggregator="count"
101
+ formatString="#,###"/>
102
+ <Measure name="Customer Count" column="customer_id"
103
+ aggregator="distinct-count" formatString="#,###"/>
104
+ <CalculatedMember
105
+ name="Profit"
106
+ dimension="Measures">
107
+ <Formula>[Measures].[Store Sales] - [Measures].[Store Cost]</Formula>
108
+ <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
109
+ </CalculatedMember>
110
+ <CalculatedMember
111
+ name="Profit last Period"
112
+ dimension="Measures"
113
+ formula="COALESCEEMPTY((Measures.[Profit], [Time].[Time].PREVMEMBER), Measures.[Profit])"
114
+ visible="false">
115
+ <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
116
+ <CalculatedMemberProperty name="MEMBER_ORDINAL" value="18"/>
117
+ </CalculatedMember>
118
+ <CalculatedMember
119
+ name="Profit Growth"
120
+ dimension="Measures"
121
+ formula="([Measures].[Profit] - [Measures].[Profit last Period]) / [Measures].[Profit last Period]"
122
+ visible="true"
123
+ caption="Gewinn-Wachstum">
124
+ <CalculatedMemberProperty name="FORMAT_STRING" value="0.0%"/>
125
+ </CalculatedMember>
126
+ </Cube>
127
+
128
+ </Schema>
@@ -0,0 +1,128 @@
1
+ <?xml version="1.0"?>
2
+ <Schema name="MondrianTest">
3
+ <Dimension name="Time" type="TimeDimension">
4
+ <Hierarchy hasAll="false" primaryKey="ID">
5
+ <Table name="TIME"/>
6
+ <Level name="Year" column="THE_YEAR" type="Numeric" uniqueMembers="true"
7
+ levelType="TimeYears"/>
8
+ <Level name="Quarter" column="QUARTER" uniqueMembers="false"
9
+ levelType="TimeQuarters"/>
10
+ <Level name="Month" column="MONTH_OF_YEAR" uniqueMembers="false" type="Numeric"
11
+ levelType="TimeMonths"/>
12
+ </Hierarchy>
13
+ <Hierarchy hasAll="true" name="Weekly" primaryKey="ID">
14
+ <Table name="TIME"/>
15
+ <Level name="Year" column="THE_YEAR" type="Numeric" uniqueMembers="true"
16
+ levelType="TimeYears"/>
17
+ <Level name="Week" column="WEEK_OF_YEAR" type="Numeric" uniqueMembers="false"
18
+ levelType="TimeWeeks"/>
19
+ <Level name="Day" column="DAY_OF_MONTH" uniqueMembers="false" type="Numeric"
20
+ levelType="TimeDays"/>
21
+ </Hierarchy>
22
+ </Dimension>
23
+
24
+ <Dimension name="Product">
25
+ <Hierarchy hasAll="true" primaryKey="ID" primaryKeyTable="PRODUCTS">
26
+ <Join leftKey="PRODUCT_CLASS_ID" rightKey="ID">
27
+ <Table name="PRODUCTS"/>
28
+ <Table name="PRODUCT_CLASSES"/>
29
+ </Join>
30
+ <Level name="Product Family" table="PRODUCT_CLASSES" column="PRODUCT_FAMILY"
31
+ uniqueMembers="true"/>
32
+ <Level name="Product Department" table="PRODUCT_CLASSES" column="PRODUCT_DEPARTMENT"
33
+ uniqueMembers="false"/>
34
+ <Level name="Product Category" table="PRODUCT_CLASSES" column="PRODUCT_CATEGORY"
35
+ uniqueMembers="false"/>
36
+ <Level name="Product Subcategory" table="PRODUCT_CLASSES" column="PRODUCT_SUBCATEGORY"
37
+ uniqueMembers="false"/>
38
+ <Level name="Brand Name" table="PRODUCTS" column="BRAND_NAME" uniqueMembers="false"/>
39
+ <Level name="Product Name" table="PRODUCTS" column="PRODUCT_NAME"
40
+ uniqueMembers="true"/>
41
+ </Hierarchy>
42
+ </Dimension>
43
+
44
+ <Cube name="Sales" defaultMeasure="Unit Sales">
45
+ <Table name="SALES"/>
46
+ <DimensionUsage name="Time" source="Time" foreignKey="TIME_ID"/>
47
+ <DimensionUsage name="Product" source="Product" foreignKey="PRODUCT_ID"/>
48
+ <Dimension name="Customers" foreignKey="CUSTOMER_ID">
49
+ <Hierarchy hasAll="true" allMemberName="All Customers" primaryKey="ID">
50
+ <Table name="CUSTOMERS"/>
51
+ <Level name="Country" column="COUNTRY" uniqueMembers="true"/>
52
+ <Level name="State Province" column="STATE_PROVINCE" uniqueMembers="true"/>
53
+ <Level name="City" column="CITY" uniqueMembers="false"/>
54
+ <Level name="Name" column="ID" type="Numeric" uniqueMembers="true">
55
+ <NameExpression>
56
+ <SQL dialect="oracle">
57
+ fname || ' ' || lname
58
+ </SQL>
59
+ <SQL dialect="postgres">
60
+ "fname" || ' ' || "lname"
61
+ </SQL>
62
+ <SQL dialect="mysql">
63
+ CONCAT(`customer`.`fname`, ' ', `customer`.`lname`)
64
+ </SQL>
65
+ <SQL dialect="generic">
66
+ FULLNAME
67
+ </SQL>
68
+ </NameExpression>
69
+ <OrdinalExpression>
70
+ <SQL dialect="oracle">
71
+ fname || ' ' || lname
72
+ </SQL>
73
+ <SQL dialect="postgres">
74
+ "fname" || ' ' || "lname"
75
+ </SQL>
76
+ <SQL dialect="mysql">
77
+ CONCAT(`customer`.`fname`, ' ', `customer`.`lname`)
78
+ </SQL>
79
+ <SQL dialect="generic">
80
+ FULLNAME
81
+ </SQL>
82
+ </OrdinalExpression>
83
+ <Property name="Gender" column="GENDER"/>
84
+ </Level>
85
+ </Hierarchy>
86
+ </Dimension>
87
+ <Dimension name="Gender" foreignKey="CUSTOMER_ID">
88
+ <Hierarchy hasAll="true" allMemberName="All Gender" primaryKey="ID">
89
+ <Table name="CUSTOMERS"/>
90
+ <Level name="Gender" column="GENDER" uniqueMembers="true"/>
91
+ </Hierarchy>
92
+ </Dimension>
93
+
94
+ <Measure name="Unit Sales" column="UNIT_SALES" aggregator="sum"
95
+ formatString="Standard"/>
96
+ <Measure name="Store Cost" column="STORE_COST" aggregator="sum"
97
+ formatString="#,###.00"/>
98
+ <Measure name="Store Sales" column="STORE_SALES" aggregator="sum"
99
+ formatString="#,###.00"/>
100
+ <Measure name="Sales Count" column="PRODUCT_ID" aggregator="count"
101
+ formatString="#,###"/>
102
+ <Measure name="Customer Count" column="CUSTOMER_ID"
103
+ aggregator="distinct-count" formatString="#,###"/>
104
+ <CalculatedMember
105
+ name="Profit"
106
+ dimension="Measures">
107
+ <Formula>[Measures].[Store Sales] - [Measures].[Store Cost]</Formula>
108
+ <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
109
+ </CalculatedMember>
110
+ <CalculatedMember
111
+ name="Profit last Period"
112
+ dimension="Measures"
113
+ formula="COALESCEEMPTY((Measures.[Profit], [Time].[Time].PREVMEMBER), Measures.[Profit])"
114
+ visible="false">
115
+ <CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
116
+ <CalculatedMemberProperty name="MEMBER_ORDINAL" value="18"/>
117
+ </CalculatedMember>
118
+ <CalculatedMember
119
+ name="Profit Growth"
120
+ dimension="Measures"
121
+ formula="([Measures].[Profit] - [Measures].[Profit last Period]) / [Measures].[Profit last Period]"
122
+ visible="true"
123
+ caption="Gewinn-Wachstum">
124
+ <CalculatedMemberProperty name="FORMAT_STRING" value="0.0%"/>
125
+ </CalculatedMember>
126
+ </Cube>
127
+
128
+ </Schema>