mondrian-olap 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +2 -0
- data/Gemfile +15 -0
- data/LICENSE-Mondrian.html +259 -0
- data/LICENSE.txt +22 -0
- data/README.rdoc +219 -0
- data/RUNNING_TESTS.rdoc +41 -0
- data/Rakefile +46 -0
- data/VERSION +1 -0
- data/lib/mondrian-olap.rb +1 -0
- data/lib/mondrian/jars/commons-collections-3.1.jar +0 -0
- data/lib/mondrian/jars/commons-dbcp-1.2.1.jar +0 -0
- data/lib/mondrian/jars/commons-logging-1.0.4.jar +0 -0
- data/lib/mondrian/jars/commons-math-1.0.jar +0 -0
- data/lib/mondrian/jars/commons-pool-1.2.jar +0 -0
- data/lib/mondrian/jars/commons-vfs-1.0.jar +0 -0
- data/lib/mondrian/jars/eigenbase-properties.jar +0 -0
- data/lib/mondrian/jars/eigenbase-resgen.jar +0 -0
- data/lib/mondrian/jars/eigenbase-xom.jar +0 -0
- data/lib/mondrian/jars/javacup.jar +0 -0
- data/lib/mondrian/jars/log4j-1.2.8.jar +0 -0
- data/lib/mondrian/jars/log4j.properties +18 -0
- data/lib/mondrian/jars/mondrian.jar +0 -0
- data/lib/mondrian/jars/olap4j.jar +0 -0
- data/lib/mondrian/olap.rb +14 -0
- data/lib/mondrian/olap/connection.rb +122 -0
- data/lib/mondrian/olap/cube.rb +236 -0
- data/lib/mondrian/olap/query.rb +313 -0
- data/lib/mondrian/olap/result.rb +155 -0
- data/lib/mondrian/olap/schema.rb +158 -0
- data/lib/mondrian/olap/schema_element.rb +123 -0
- data/mondrian-olap.gemspec +116 -0
- data/spec/connection_spec.rb +56 -0
- data/spec/cube_spec.rb +259 -0
- data/spec/fixtures/MondrianTest.xml +128 -0
- data/spec/fixtures/MondrianTestOracle.xml +128 -0
- data/spec/query_spec.rb +582 -0
- data/spec/rake_tasks.rb +185 -0
- data/spec/schema_definition_spec.rb +345 -0
- data/spec/spec_helper.rb +67 -0
- data/spec/support/matchers/be_like.rb +24 -0
- metadata +217 -0
data/spec/cube_spec.rb
ADDED
@@ -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>
|