mondrian-olap 0.4.0-java
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.rspec +2 -0
- data/Changelog.md +60 -0
- data/Gemfile +21 -0
- data/LICENSE-Mondrian.html +259 -0
- data/LICENSE.txt +22 -0
- data/README.md +302 -0
- data/RUNNING_TESTS.rdoc +66 -0
- data/Rakefile +48 -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 +5 -0
- data/lib/mondrian/jars/mondrian.jar +0 -0
- data/lib/mondrian/jars/olap4j.jar +0 -0
- data/lib/mondrian/olap.rb +17 -0
- data/lib/mondrian/olap/connection.rb +201 -0
- data/lib/mondrian/olap/cube.rb +297 -0
- data/lib/mondrian/olap/error.rb +57 -0
- data/lib/mondrian/olap/query.rb +342 -0
- data/lib/mondrian/olap/result.rb +264 -0
- data/lib/mondrian/olap/schema.rb +378 -0
- data/lib/mondrian/olap/schema_element.rb +153 -0
- data/lib/mondrian/olap/schema_udf.rb +282 -0
- data/mondrian-olap.gemspec +128 -0
- data/spec/connection_role_spec.rb +130 -0
- data/spec/connection_spec.rb +72 -0
- data/spec/cube_spec.rb +318 -0
- data/spec/fixtures/MondrianTest.xml +134 -0
- data/spec/fixtures/MondrianTestOracle.xml +134 -0
- data/spec/mondrian_spec.rb +53 -0
- data/spec/query_spec.rb +807 -0
- data/spec/rake_tasks.rb +260 -0
- data/spec/schema_definition_spec.rb +1249 -0
- data/spec/spec_helper.rb +134 -0
- data/spec/support/matchers/be_like.rb +24 -0
- metadata +278 -0
@@ -0,0 +1,72 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe "Connection" do
|
4
|
+
|
5
|
+
describe "create" do
|
6
|
+
before(:each) do
|
7
|
+
@olap = Mondrian::OLAP::Connection.new(CONNECTION_PARAMS_WITH_CATALOG)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should not be connected before connection" do
|
11
|
+
@olap.should_not be_connected
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should be successful" do
|
15
|
+
@olap.connect.should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "create with catalog content" do
|
21
|
+
before(:all) do
|
22
|
+
@schema_xml = File.read(CATALOG_FILE)
|
23
|
+
end
|
24
|
+
it "should be successful" do
|
25
|
+
@olap = Mondrian::OLAP::Connection.new(CONNECTION_PARAMS.merge(
|
26
|
+
:catalog_content => @schema_xml
|
27
|
+
))
|
28
|
+
@olap.connect.should be_true
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "properties" do
|
34
|
+
before(:all) do
|
35
|
+
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS_WITH_CATALOG)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should be connected" do
|
39
|
+
@olap.should be_connected
|
40
|
+
end
|
41
|
+
|
42
|
+
# to check that correct database dialect is loaded by ServiceDiscovery detected class loader
|
43
|
+
it "should use corresponding Mondrian dialect" do
|
44
|
+
# read private "schema" field
|
45
|
+
schema_field = @olap.raw_schema.getClass.getDeclaredField("schema")
|
46
|
+
schema_field.setAccessible(true)
|
47
|
+
private_schema = schema_field.get(@olap.raw_schema)
|
48
|
+
private_schema.getDialect.java_class.name.should == case MONDRIAN_DRIVER
|
49
|
+
when 'mysql' then 'mondrian.spi.impl.MySqlDialect'
|
50
|
+
when 'postgresql' then 'mondrian.spi.impl.PostgreSqlDialect'
|
51
|
+
when 'oracle' then 'mondrian.spi.impl.OracleDialect'
|
52
|
+
when 'luciddb' then 'mondrian.spi.impl.LucidDbDialect'
|
53
|
+
when 'mssql' then 'mondrian.spi.impl.MicrosoftSqlServerDialect'
|
54
|
+
when 'sqlserver' then 'mondrian.spi.impl.MicrosoftSqlServerDialect'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
describe "close" do
|
61
|
+
before(:all) do
|
62
|
+
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS_WITH_CATALOG)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should not be connected after close" do
|
66
|
+
@olap.close
|
67
|
+
@olap.should_not be_connected
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
data/spec/cube_spec.rb
ADDED
@@ -0,0 +1,318 @@
|
|
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
|
+
description 'Sales description'
|
8
|
+
table 'sales'
|
9
|
+
dimension 'Gender', :foreign_key => 'customer_id' do
|
10
|
+
description 'Gender description'
|
11
|
+
hierarchy :has_all => true, :primary_key => 'id' do
|
12
|
+
description 'Gender hierarchy description'
|
13
|
+
table 'customers'
|
14
|
+
level 'Gender', :column => 'gender', :unique_members => true, :description => 'Gender level description'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
dimension 'Customers', :foreign_key => 'customer_id' do
|
18
|
+
hierarchy :has_all => true, :all_member_name => 'All Customers', :primary_key => 'id' do
|
19
|
+
table 'customers'
|
20
|
+
level 'Country', :column => 'country', :unique_members => true
|
21
|
+
level 'State Province', :column => 'state_province', :unique_members => true
|
22
|
+
level 'City', :column => 'city', :unique_members => false
|
23
|
+
level 'Name', :column => 'fullname', :unique_members => true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
calculated_member 'Non-USA' do
|
27
|
+
dimension 'Customers'
|
28
|
+
formula '[Customers].[All Customers] - [Customers].[USA]'
|
29
|
+
end
|
30
|
+
dimension 'Time', :foreign_key => 'time_id', :type => 'TimeDimension' do
|
31
|
+
hierarchy :has_all => false, :primary_key => 'id' do
|
32
|
+
table 'time'
|
33
|
+
level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
|
34
|
+
level 'Quarter', :column => 'quarter', :unique_members => false, :level_type => 'TimeQuarters'
|
35
|
+
level 'Month', :column => 'month_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeMonths'
|
36
|
+
end
|
37
|
+
hierarchy 'Weekly', :has_all => false, :primary_key => 'id' do
|
38
|
+
table 'time'
|
39
|
+
level 'Year', :column => 'the_year', :type => 'Numeric', :unique_members => true, :level_type => 'TimeYears'
|
40
|
+
level 'Week', :column => 'weak_of_year', :type => 'Numeric', :unique_members => false, :level_type => 'TimeWeeks'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
measure 'Unit Sales', :column => 'unit_sales', :aggregator => 'sum'
|
44
|
+
measure 'Store Sales', :column => 'store_sales', :aggregator => 'sum'
|
45
|
+
measure 'Store Cost', :column => 'store_cost', :aggregator => 'sum', :visible => false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
@olap = Mondrian::OLAP::Connection.create(CONNECTION_PARAMS.merge :schema => @schema)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should get all cube names" do
|
52
|
+
@olap.cube_names.should == ['Sales']
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should get cube by name" do
|
56
|
+
@olap.cube('Sales').should be_a(Mondrian::OLAP::Cube)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should return nil when getting cube with invalid name" do
|
60
|
+
@olap.cube('invalid').should be_nil
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should get cube name" do
|
64
|
+
@olap.cube('Sales').name.should == 'Sales'
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should get cube description" do
|
68
|
+
@olap.cube('Sales').description.should == 'Sales description'
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "dimensions" do
|
72
|
+
before(:all) do
|
73
|
+
@cube = @olap.cube('Sales')
|
74
|
+
@dimension_names = ['Measures', 'Gender', 'Customers', 'Time']
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should get dimension names" do
|
78
|
+
@cube.dimension_names.should == @dimension_names
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should get dimensions" do
|
82
|
+
@cube.dimensions.map{|d| d.name}.should == @dimension_names
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should get dimension by name" do
|
86
|
+
@cube.dimension('Gender').name.should == 'Gender'
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return nil when getting dimension with invalid name" do
|
90
|
+
@cube.dimension('invalid').should be_nil
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should get dimension description" do
|
94
|
+
@cube.dimension('Gender').description.should == 'Gender description'
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should get dimension full name" do
|
98
|
+
@cube.dimension('Gender').full_name.should == '[Gender]'
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should get measures dimension" do
|
102
|
+
@cube.dimension('Measures').should be_measures
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should get dimension type" do
|
106
|
+
@cube.dimension('Gender').dimension_type.should == :standard
|
107
|
+
@cube.dimension('Time').dimension_type.should == :time
|
108
|
+
@cube.dimension('Measures').dimension_type.should == :measures
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "dimension hierarchies" do
|
113
|
+
before(:all) do
|
114
|
+
@cube = @olap.cube('Sales')
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should get hierarchies" do
|
118
|
+
hierarchies = @cube.dimension('Gender').hierarchies
|
119
|
+
hierarchies.size.should == 1
|
120
|
+
hierarchies[0].name.should == 'Gender'
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should get hierarchy description" do
|
124
|
+
hierarchies = @cube.dimension('Gender').hierarchies.first.description.should == 'Gender hierarchy description'
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should get hierarchy names" do
|
128
|
+
@cube.dimension('Time').hierarchy_names.should == ['Time', 'Time.Weekly']
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should get hierarchy by name" do
|
132
|
+
@cube.dimension('Time').hierarchy('Time.Weekly').name.should == 'Time.Weekly'
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should return nil when getting hierarchy with invalid name" do
|
136
|
+
@cube.dimension('Time').hierarchy('invalid').should be_nil
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should get default hierarchy" do
|
140
|
+
@cube.dimension('Time').hierarchy.name.should == 'Time'
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should get hierarchy levels" do
|
144
|
+
@cube.dimension('Customers').hierarchy.levels.map(&:name).should == ['(All)', 'Country', 'State Province', 'City', 'Name']
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should get hierarchy level names" do
|
148
|
+
@cube.dimension('Time').hierarchy.level_names.should == ['Year', 'Quarter', 'Month']
|
149
|
+
@cube.dimension('Customers').hierarchy.level_names.should == ['(All)', 'Country', 'State Province', 'City', 'Name']
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should get hierarchy level depths" do
|
153
|
+
@cube.dimension('Customers').hierarchy.levels.map(&:depth).should == [0, 1, 2, 3, 4]
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should get hierarchy level members count" do
|
157
|
+
@cube.dimension('Gender').hierarchy.levels.map(&:members_count).should == [1, 2]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "hierarchy values" do
|
162
|
+
before(:all) do
|
163
|
+
@cube = @olap.cube('Sales')
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should get hierarchy all member" do
|
167
|
+
@cube.dimension('Gender').hierarchy.has_all?.should be_true
|
168
|
+
@cube.dimension('Gender').hierarchy.all_member_name.should == 'All Genders'
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should not get all member for hierarchy without all member" do
|
172
|
+
@cube.dimension('Time').hierarchy.has_all?.should be_false
|
173
|
+
@cube.dimension('Time').hierarchy.all_member_name.should be_nil
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should get hierarchy root members" do
|
177
|
+
@cube.dimension('Gender').hierarchy.root_members.map(&:name).should == ['All Genders']
|
178
|
+
@cube.dimension('Gender').hierarchy.root_member_names.should == ['All Genders']
|
179
|
+
@cube.dimension('Time').hierarchy.root_members.map(&:name).should == ['2010', '2011']
|
180
|
+
@cube.dimension('Time').hierarchy.root_member_names.should == ['2010', '2011']
|
181
|
+
end
|
182
|
+
|
183
|
+
it "should return child members for specified member" do
|
184
|
+
@cube.dimension('Gender').hierarchy.child_names('All Genders').should == ['F', 'M']
|
185
|
+
@cube.dimension('Customers').hierarchy.child_names('USA', 'OR').should ==
|
186
|
+
["Albany", "Beaverton", "Corvallis", "Lake Oswego", "Lebanon", "Milwaukie",
|
187
|
+
"Oregon City", "Portland", "Salem", "W. Linn", "Woodburn"]
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should return child members for hierarchy" do
|
191
|
+
@cube.dimension('Gender').hierarchy.child_names.should == ['F', 'M']
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should not return child members for leaf member" do
|
195
|
+
@cube.dimension('Gender').hierarchy.child_names('All Genders', 'F').should == []
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should return nil as child members if parent member not found" do
|
199
|
+
@cube.dimension('Gender').hierarchy.child_names('N').should be_nil
|
200
|
+
end
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "level members" do
|
205
|
+
before(:all) do
|
206
|
+
@cube = @olap.cube('Sales')
|
207
|
+
end
|
208
|
+
|
209
|
+
it "should get level description" do
|
210
|
+
@cube.dimension('Gender').hierarchy.level('Gender').description.should == 'Gender level description'
|
211
|
+
end
|
212
|
+
|
213
|
+
it "should return nil when getting level with invalid name" do
|
214
|
+
@cube.dimension('Gender').hierarchy.level('invalid').should be_nil
|
215
|
+
end
|
216
|
+
|
217
|
+
it "should get primary hierarchy level members" do
|
218
|
+
@cube.dimension('Customers').hierarchy.level('Country').members.
|
219
|
+
map(&:name).should == ['Canada', 'Mexico', 'USA']
|
220
|
+
end
|
221
|
+
|
222
|
+
it "should get secondary hierarchy level members" do
|
223
|
+
@cube.dimension('Time').hierarchy('Time.Weekly').level('Year').members.
|
224
|
+
map(&:name).should == ['2010', '2011']
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe "members" do
|
229
|
+
before(:all) do
|
230
|
+
@cube = @olap.cube('Sales')
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should return member for specified full name" do
|
234
|
+
@cube.member('[Gender].[All Genders]').name.should == 'All Genders'
|
235
|
+
@cube.member('[Customers].[USA].[OR]').name.should == 'OR'
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should not return member for invalid full name" do
|
239
|
+
@cube.member('[Gender].[invalid]').should be_nil
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should return child members for member" do
|
243
|
+
@cube.member('[Gender].[All Genders]').children.map(&:name).should == ['F', 'M']
|
244
|
+
@cube.member('[Customers].[USA].[OR]').children.map(&:name).should ==
|
245
|
+
["Albany", "Beaverton", "Corvallis", "Lake Oswego", "Lebanon", "Milwaukie",
|
246
|
+
"Oregon City", "Portland", "Salem", "W. Linn", "Woodburn"]
|
247
|
+
end
|
248
|
+
|
249
|
+
it "should return empty children array if member does not have children" do
|
250
|
+
@cube.member('[Gender].[All Genders].[F]').children.should be_empty
|
251
|
+
end
|
252
|
+
|
253
|
+
it "should return member depth" do
|
254
|
+
@cube.member('[Customers].[All Customers]').depth.should == 0
|
255
|
+
@cube.member('[Customers].[USA]').depth.should == 1
|
256
|
+
@cube.member('[Customers].[USA].[CA]').depth.should == 2
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should return descendants for member at specified level" do
|
260
|
+
@cube.member('[Customers].[Mexico]').descendants_at_level('City').map(&:name).should ==
|
261
|
+
["San Andres", "Santa Anita", "Santa Fe", "Tixapan", "Acapulco", "Guadalajara",
|
262
|
+
"Mexico City", "Tlaxiaco", "La Cruz", "Orizaba", "Merida", "Camacho", "Hidalgo"]
|
263
|
+
end
|
264
|
+
|
265
|
+
it "should not return descendants for member when upper level specified" do
|
266
|
+
@cube.member('[Customers].[Mexico].[DF]').descendants_at_level('Country').should be_nil
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should be drillable when member has descendants" do
|
270
|
+
@cube.member('[Customers].[USA]').should be_drillable
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should not be drillable when member has no descendants" do
|
274
|
+
@cube.member('[Gender].[F]').should_not be_drillable
|
275
|
+
end
|
276
|
+
|
277
|
+
it "should not be drillable when member is calculated" do
|
278
|
+
@cube.member('[Customers].[Non-USA]').should_not be_drillable
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should be calculated when member is calculated" do
|
282
|
+
@cube.member('[Customers].[Non-USA]').should be_calculated
|
283
|
+
end
|
284
|
+
|
285
|
+
it "should not be calculated when normal member" do
|
286
|
+
@cube.member('[Customers].[USA]').should_not be_calculated
|
287
|
+
end
|
288
|
+
|
289
|
+
it "should be all member when member is all member" do
|
290
|
+
@cube.member('[Customers].[All Customers]').should be_all_member
|
291
|
+
end
|
292
|
+
|
293
|
+
it "should not be all member when member is not all member" do
|
294
|
+
@cube.member('[Customers].[USA]').should_not be_all_member
|
295
|
+
end
|
296
|
+
|
297
|
+
it "should get dimension type of standard dimension member" do
|
298
|
+
@cube.member('[Customers].[USA]').dimension_type.should == :standard
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should get dimension type of measure" do
|
302
|
+
@cube.member('[Measures].[Unit Sales]').dimension_type.should == :measures
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should get dimension type of time dimension member" do
|
306
|
+
@cube.member('[Time].[2011]').dimension_type.should == :time
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should be visble when member is visible" do
|
310
|
+
@cube.member('[Measures].[Store Sales]').should be_visible
|
311
|
+
end
|
312
|
+
|
313
|
+
it "should not be visble when member is not visible" do
|
314
|
+
@cube.member('[Measures].[Store Cost]').should_not be_visible
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
@@ -0,0 +1,134 @@
|
|
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="postgresql">
|
60
|
+
"fname" || ' ' || "lname"
|
61
|
+
</SQL>
|
62
|
+
<SQL dialect="mysql">
|
63
|
+
CONCAT(`customers`.`fname`, ' ', `customers`.`lname`)
|
64
|
+
</SQL>
|
65
|
+
<SQL dialect="luciddb">
|
66
|
+
"fname" || ' ' || "lname"
|
67
|
+
</SQL>
|
68
|
+
<SQL dialect="generic">
|
69
|
+
fullname
|
70
|
+
</SQL>
|
71
|
+
</NameExpression>
|
72
|
+
<OrdinalExpression>
|
73
|
+
<SQL dialect="oracle">
|
74
|
+
fname || ' ' || lname
|
75
|
+
</SQL>
|
76
|
+
<SQL dialect="postgresql">
|
77
|
+
"fname" || ' ' || "lname"
|
78
|
+
</SQL>
|
79
|
+
<SQL dialect="mysql">
|
80
|
+
CONCAT(`customers`.`fname`, ' ', `customers`.`lname`)
|
81
|
+
</SQL>
|
82
|
+
<SQL dialect="luciddb">
|
83
|
+
"fname" || ' ' || "lname"
|
84
|
+
</SQL>
|
85
|
+
<SQL dialect="generic">
|
86
|
+
fullname
|
87
|
+
</SQL>
|
88
|
+
</OrdinalExpression>
|
89
|
+
<Property name="Gender" column="gender"/>
|
90
|
+
</Level>
|
91
|
+
</Hierarchy>
|
92
|
+
</Dimension>
|
93
|
+
<Dimension name="Gender" foreignKey="customer_id">
|
94
|
+
<Hierarchy hasAll="true" allMemberName="All Gender" primaryKey="id">
|
95
|
+
<Table name="customers"/>
|
96
|
+
<Level name="Gender" column="gender" uniqueMembers="true"/>
|
97
|
+
</Hierarchy>
|
98
|
+
</Dimension>
|
99
|
+
|
100
|
+
<Measure name="Unit Sales" column="unit_sales" aggregator="sum"
|
101
|
+
formatString="Standard"/>
|
102
|
+
<Measure name="Store Cost" column="store_cost" aggregator="sum"
|
103
|
+
formatString="#,###.00"/>
|
104
|
+
<Measure name="Store Sales" column="store_sales" aggregator="sum"
|
105
|
+
formatString="#,###.00"/>
|
106
|
+
<Measure name="Sales Count" column="product_id" aggregator="count"
|
107
|
+
formatString="#,###"/>
|
108
|
+
<Measure name="Customer Count" column="customer_id"
|
109
|
+
aggregator="distinct-count" formatString="#,###"/>
|
110
|
+
<CalculatedMember
|
111
|
+
name="Profit"
|
112
|
+
dimension="Measures">
|
113
|
+
<Formula>[Measures].[Store Sales] - [Measures].[Store Cost]</Formula>
|
114
|
+
<CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
|
115
|
+
</CalculatedMember>
|
116
|
+
<CalculatedMember
|
117
|
+
name="Profit last Period"
|
118
|
+
dimension="Measures"
|
119
|
+
formula="COALESCEEMPTY((Measures.[Profit], [Time].[Time].PREVMEMBER), Measures.[Profit])"
|
120
|
+
visible="false">
|
121
|
+
<CalculatedMemberProperty name="FORMAT_STRING" value="$#,##0.00"/>
|
122
|
+
<CalculatedMemberProperty name="MEMBER_ORDINAL" value="18"/>
|
123
|
+
</CalculatedMember>
|
124
|
+
<CalculatedMember
|
125
|
+
name="Profit Growth"
|
126
|
+
dimension="Measures"
|
127
|
+
formula="([Measures].[Profit] - [Measures].[Profit last Period]) / [Measures].[Profit last Period]"
|
128
|
+
visible="true"
|
129
|
+
caption="Gewinn-Wachstum">
|
130
|
+
<CalculatedMemberProperty name="FORMAT_STRING" value="0.0%"/>
|
131
|
+
</CalculatedMember>
|
132
|
+
</Cube>
|
133
|
+
|
134
|
+
</Schema>
|