1 package body BSC_AW_ADAPTER_DIM AS
2 /*$Header: BSCAWADB.pls 120.20 2006/11/04 10:54:24 amitgupt noship $*/
3
4 --given a array of dim, first get the full list of dim as parent child
5 --and then group them into dim
6 --p_dim_level_list is a set of BSC dim levels
7 procedure create_dim(p_dim_level_list dbms_sql.varchar2_table) is
8 l_affected_kpi dbms_sql.varchar2_table;
9 Begin
10 create_dim(p_dim_level_list,l_affected_kpi);
11 Exception when others then
12 log_n('Exception in create_dim '||sqlerrm);
13 raise;
14 End;
15
16 /*
17 if create_dim has to end up re-creating a dim, then the affected kpi are returned. these affected kpi have been
18 dropped so the dim can be recreated. mostly, p_affected_kpi should be empty
19 */
20 procedure create_dim(
21 p_dim_level_list dbms_sql.varchar2_table,
22 p_affected_kpi in out nocopy dbms_sql.varchar2_table
23 ) is
24 --
25 l_dim_parent_child dim_parent_child_tb;
26 l_dim_levels levels_tv;
27 --
28 Begin
29 get_all_dim_levels(p_dim_level_list,l_dim_parent_child,l_dim_levels);
30 --l_dim_levels contains the level name and id. will be used to generate the dim name
31 group_levels_into_sets(l_dim_parent_child);
32 create_dim(l_dim_parent_child,l_dim_levels,g_dimensions);
33 create_std_dim(g_dimensions); --this creates the type and projection dim
34 if g_debug then
35 dmp_g_dimensions(g_dimensions);
36 end if;
37 implement_dim_aw(g_dimensions,p_affected_kpi);
38 if g_debug then
39 log_n('create_dim complete '||bsc_aw_utility.get_time);
40 end if;
41 Exception when others then
42 log_n('Exception in create_dim '||sqlerrm);
43 raise;
44 End;
45
46 --get the parent child level relation and the properties of the levels
47 --excluding the position
48 --position is later calculated
49 --needs to be reset later
50 procedure get_all_dim_levels(
51 p_dim_level_list dbms_sql.varchar2_table,
52 p_dim_parent_child out nocopy dim_parent_child_tb,
53 p_dim_levels out nocopy levels_tv
54 ) is
55 Begin
56 if g_debug then
57 log_n('In get_all_dim_levels'||bsc_aw_utility.get_time);
58 end if;
59 --get all the parent child relations for the levels
60 bsc_aw_bsc_metadata.get_all_parent_child(p_dim_level_list,p_dim_parent_child,p_dim_levels);
61 if g_debug then
62 log_n('p_dim_parent_child');
63 for i in 1..p_dim_parent_child.count loop
64 log(p_dim_parent_child(i).parent_level||'('||p_dim_parent_child(i).parent_pk||') '||
65 p_dim_parent_child(i).child_level||'('||p_dim_parent_child(i).child_fk||')');
66 end loop;
67 end if;
68 Exception when others then
69 log_n('Exception in get_all_dim_levels '||sqlerrm);
70 raise;
71 End;
72
73 procedure group_levels_into_sets(
74 p_dim_parent_child in out nocopy dim_parent_child_tb
75 ) is
76 --
77 l_level_considered dbms_sql.varchar2_table;
78 l_set number;
79 l_flag boolean;
80 l_level varchar2(100);
81 --
82 Begin
83 l_level_considered.delete;
84 l_set:=0;
85 --loop completed when there are no more parent child combinations that need a set number assigned
86 loop
87 --get the first empty set
88 l_flag:=false;
89 for i in 1..p_dim_parent_child.count loop
90 if p_dim_parent_child(i).level_set is null then
91 l_level:=p_dim_parent_child(i).child_level;
92 l_flag:=true;
93 exit;
94 end if;
95 end loop;
96 --see if we can exit
97 if l_flag=false then
98 --all work complete
99 exit;
100 end if;
101 l_set:=l_set+1;
102 assign_set_to_level(p_dim_parent_child,l_level_considered,l_level,l_set);
103 end loop;
104 Exception when others then
105 log_n('Exception in group_levels_into_sets '||sqlerrm);
106 raise;
107 End;
108
109 --assign a set number to this level (p_level). then for each parent and child, see if a set is already assigned.
110 --if not, call this procedure recursively for those levels
111 procedure assign_set_to_level(
112 p_dim_parent_child in out nocopy dim_parent_child_tb,
113 p_level_considered in out nocopy dbms_sql.varchar2_table,
114 p_level varchar2,
115 p_set number
116 ) is
117 Begin
118 if bsc_aw_utility.in_array(p_level_considered,p_level) then
119 return;
120 end if;
121 for i in 1..p_dim_parent_child.count loop
122 if p_dim_parent_child(i).child_level=p_level then
123 p_dim_parent_child(i).level_set:=p_set;
124 p_level_considered(p_level_considered.count+1):=p_level;
125 end if;
126 end loop;
127 --for each parent, set the level_set number
128 for i in 1..p_dim_parent_child.count loop
129 if p_dim_parent_child(i).child_level=p_level then
130 if p_dim_parent_child(i).parent_level is not null and p_dim_parent_child(i).parent_level<>p_dim_parent_child(i).child_level then
131 assign_set_to_level(p_dim_parent_child,p_level_considered,p_dim_parent_child(i).parent_level,p_set);
132 end if;
133 end if;
134 end loop;
135 --for each child, set the level_set number
136 for i in 1..p_dim_parent_child.count loop
137 if p_dim_parent_child(i).parent_level=p_level then
138 if p_dim_parent_child(i).child_level is not null and p_dim_parent_child(i).parent_level<>p_dim_parent_child(i).child_level then
139 --child cannot be null...still no harm
140 assign_set_to_level(p_dim_parent_child,p_level_considered,p_dim_parent_child(i).child_level,p_set);
141 end if;
142 end if;
143 end loop;
144 Exception when others then
145 log_n('Exception in assign_set_to_level '||sqlerrm);
146 raise;
147 End;
148
149 /*
150 create_dim is passed an array of information. this api first creates the dim structure in memory
151 by using the level set info
152 */
153 procedure create_dim(
154 p_dim_parent_child dim_parent_child_tb,
155 p_dim_levels levels_tv,
156 p_dimensions out nocopy dimension_tb
157 ) is
158 --
159 l_max_set number;
160 l_level varchar2(100);
161 l_id number;
162 l_count number;
163 l_dim dimension_r;
164 --
165 TYPE CurTyp IS REF CURSOR;
166 cv CurTyp;
167 --
168 Begin
169 l_max_set:=0;
170 for i in 1..p_dim_parent_child.count loop
171 if p_dim_parent_child(i).level_set>l_max_set then
172 l_max_set:=p_dim_parent_child(i).level_set;
173 end if;
174 end loop;
175 --l_max_set is the number of dimensions
176 for i in 1..l_max_set loop
177 l_count:=0;
178 --bug fix 5636695
179 -- we have used a new public var here, so as to take an empty structure and fill in
180 -- the issue here was we had level values and parent child values retained from the previous
181 -- kpi run p_dimensions... which was causing problem
182 --- this will clear the previous entries from the structure
183 l_dim.level_groups.delete;
184 bsc_aw_utility.delete_table('bsc_aw_temp_vn',null);
185 for j in 1..p_dim_parent_child.count loop
186 if p_dim_parent_child(j).level_set=i then
187 l_level:=p_dim_parent_child(j).child_level;
188 l_id:=p_dim_levels(l_level).level_id;
189 execute immediate 'insert into bsc_aw_temp_vn(name,id) values(:1,:2)' using l_level,l_id;
190 l_count:=l_count+1;
191 l_dim.level_groups(1).parent_child(l_count):=p_dim_parent_child(j);
192 end if;
193 end loop;
194 l_count:=0;
195 g_stmt:='select distinct name,id from bsc_aw_temp_vn order by id';
196 open cv for g_stmt;
197 loop
198 fetch cv into l_level,l_id;
199 exit when cv%notfound;
200 l_count:=l_count+1;
201 l_dim.level_groups(1).levels(l_count):=p_dim_levels(l_level);
202 --p_dim_levels will have the level name, id, position(set_level_position api), pk, fk etc
203 --new dim all have default 1 level group
204 end loop;
205 close cv;
206 --all dim have at-least 2 levels. the top level is zero code level. this means all dim are concat dim
207 --if this is a single level dim vs multi level dim
208 --the name of the concat dim does not contain the zero codes or the rec levels
209 /*
210 we ran into an error where the name of the object ran to greater than 64 chars and AW errored creating the object
211 AW allows max of 64 chars in a name. so we use the string of all level ids and then create a hash value and use the
212 hash value. the hash value is starting from 100 to 1073741824
213 we trust that the hash value for a given string does not change from db version to version. tested on 9i and 10g.
214 its consistent.
215 */
216 p_dimensions(i) := l_dim;
217 p_dimensions(i).corrected:='N';
218 p_dimensions(i).concat:='Y';
219 make_dim_name(p_dimensions(i),get_dim_name_hash_string(p_dimensions(i)));
220 p_dimensions(i).dim_type:='custom';
221 p_dimensions(i).relation_name:=p_dimensions(i).dim_name||'.rel';
222 p_dimensions(i).level_groups(1).level_group_name:=get_default_lg_name;
223 --set the level position. level positions are useful to see if we need to aggregate on the fly
224 set_level_position(p_dimensions(i));
225 --if a dim is a recursive dim, we have no zero code level. the reason is that the top node is zero code
226 set_dim_recursive(p_dimensions(i));
227 get_kpi_for_dim(p_dimensions(i));
228 if p_dimensions(i).recursive='Y' then
229 set_rec_dim_properties(p_dimensions(i));--sets normal hier as default implementation
230 create_virtual_rec_level(p_dimensions(i));
231 create_rec_data_source(p_dimensions(i));
232 else
233 create_virtual_zero_code_level(p_dimensions(i));--simply creating the metadata
234 create_data_source(p_dimensions(i));
235 end if;
236 --set the dim properties
237 set_dim_properties(p_dimensions(i));
238 end loop;
239 Exception when others then
240 log_n('Exception in create_dim '||sqlerrm);
241 raise;
242 End;
243
244 function get_dim_name_hash_string(p_dimension dimension_r) return varchar2 is
245 l_hash_string varchar2(4000);
246 Begin
247 l_hash_string:='DIM';
248 for i in 1..p_dimension.level_groups.count loop
249 for j in 1..p_dimension.level_groups(i).levels.count loop
250 l_hash_string:=l_hash_string||'.'||p_dimension.level_groups(i).levels(j).level_id;
251 end loop;
252 end loop;
253 --add the time to make it unique
254 l_hash_string:=l_hash_string||'.'||bsc_aw_utility.get_dbms_time;
255 return l_hash_string;
256 Exception when others then
257 log_n('Exception in get_dim_name_hash_string '||sqlerrm);
258 raise;
259 End;
260
261 procedure make_dim_name(p_dimension in out nocopy dimension_r,p_hash_string varchar2) is
262 l_hash_value varchar2(200);
263 Begin
264 p_dimension.dim_name:='BSC_CC';
265 l_hash_value:=bsc_aw_utility.get_hash_value(p_hash_string,100,1073741824);
266 p_dimension.dim_name:=p_dimension.dim_name||'_'||l_hash_value;
267 Exception when others then
268 log_n('Exception in make_dim_name '||sqlerrm);
269 raise;
270 End;
271
272 procedure set_dim_properties(p_dim in out nocopy dimension_r) is
273 Begin
274 if p_dim.dim_type<>'std' and p_dim.level_groups(1).data_source.data_source is not null then --DBI dim
275 p_dim.dim_type:='dbi';
276 end if;
277 --here dim are normal. in bsc_aw_calendar module, we have time dim being created
278 p_dim.property:='dimension type=normal,dimension source type='||p_dim.dim_type||',corrected='||p_dim.corrected||',';
279 --as old dim ages, the corrected flag is set to yes
280 if p_dim.recursive='Y' then
281 p_dim.property:=p_dim.property||'recursive,';
282 if p_dim.recursive_norm_hier='Y' then
283 p_dim.property:=p_dim.property||'normal hier,';
284 --also the denorm source, child col and parent col. we need it in the load dim module to load
285 --norm hier into bsc_aw_temp_pc
286 --note>>>the denorm_data_source is like (select a,b from CC). it has comma inside. if in bscawldb.pls, we try
287 --to bsc_aw_utility.get_parameter_value(l_dim_property,'denorm source',','), we will get (select a since the stmt
288 --is cutoff at the first , so we will replace the , with *^ and later, in bscawldb.pls, replace the *^ with ,
289 --note>>>p_dim.level_groups(1).data_source.data_source and p_dim.level_groups(1).data_source.denorm_data_source go together
290 if p_dim.level_groups(1).data_source.data_source is not null then
291 p_dim.property:=p_dim.property||'denorm source='||replace(p_dim.level_groups(1).data_source.denorm_data_source,',','*^')||',';
292 p_dim.property:=p_dim.property||'child col='||p_dim.level_groups(1).data_source.child_col||',parent col='||
293 p_dim.level_groups(1).data_source.parent_col||',';
294 end if;
295 end if;
296 end if;
297 if p_dim.level_groups.count>1 or p_dim.level_groups(1).levels.count>1 then
298 p_dim.property:=p_dim.property||'multi level,';
299 end if;
300 for i in 1..p_dim.level_groups.count loop
301 if p_dim.level_groups(i).zero_levels.count>0 then
302 p_dim.property:=p_dim.property||'zero code,';
303 exit;
304 end if;
305 end loop;
306 p_dim.property:=p_dim.property||'relation name='||p_dim.relation_name||',';
307 p_dim.property:=p_dim.property||'level name dim='||p_dim.level_name_dim||',';
308 Exception when others then
309 log_n('Exception in set_dim_properties '||sqlerrm);
310 raise;
311 End;
312
313 procedure reset_dimension_r(p_dim in out nocopy dimension_r) is
314 Begin
315 p_dim.level_groups(1).levels.delete;
316 p_dim.level_groups(1).parent_child.delete;
317 p_dim.level_groups(1).zero_levels.delete;
318 p_dim.level_groups(1).rec_levels.delete;
319 p_dim.recursive:='N';
320 p_dim.recursive_norm_hier:='N';
321 p_dim.kpi_for_dim.delete;
322 Exception when others then
323 log_n('Exception in reset_dimension_r '||sqlerrm);
324 raise;
325 End;
326
327 procedure set_level_position(
328 p_dimension in out nocopy dimension_r
329 ) is
330 --
331 l_flag boolean;
332 --
333 Begin
334 if p_dimension.level_groups(1).levels.count=1 then
335 --single level and recursive dim
336 p_dimension.level_groups(1).levels(1).position:=1;
337 else
338 --multi level dim
339 --get the lowest levels. they are the seed levels. then set the positions
340 for i in 1..p_dimension.level_groups(1).levels.count loop
341 --for each level, see if its a child. if its a child, start setting the position
342 l_flag:=false;
343 for j in 1..p_dimension.level_groups(1).parent_child.count loop
344 if p_dimension.level_groups(1).parent_child(j).parent_level=p_dimension.level_groups(1).levels(i).level_name then
345 l_flag:=true;
346 exit;
347 end if;
348 end loop;
349 if l_flag=false then
350 set_level_position(p_dimension,p_dimension.level_groups(1).levels(i).level_name,1);
351 end if;
352 end loop;
353 end if;
354 Exception when others then
355 log_n('Exception in set_level_position '||sqlerrm);
356 raise;
357 End;
358
359 /*
360 consider this
361 1 - 2 - 3
362 8 - 7 - 6 - 5 - 4 - 3
363 8 - 9 - 10
364 8 - 9 - 3
365
366 lowest level have position 1. we also need to handle rec dim
367 rec dim are handled like this:
368 say only first 2 levels are pre-agg, larry and john wookey. the reports asks for cliff. then all we need to do it to limit the relation
369 dim.level to the value of cliff and call the aggregation. the entry for cliff has all the denorm values of employees under cliff in it.
370 so setting the position is not reqd for rec dim
371 */
372 procedure set_level_position(
373 p_dimension in out nocopy dimension_r,
374 p_level varchar2,
375 p_position number
376 ) is
377 --
378 l_level_index number;
379 --
380 Begin
381 --set the position
382 if g_debug then
383 log_n('In set_level_position, p_level='||p_level||' p_position='||p_position);
384 end if;
385 if p_level is null then
386 return;
387 end if;
388 for i in 1..p_dimension.level_groups(1).levels.count loop
389 if p_dimension.level_groups(1).levels(i).level_name=p_level then
390 l_level_index:=i;
391 exit;
392 end if;
393 end loop;
394 if p_dimension.level_groups(1).levels(l_level_index).position is not null
395 and p_dimension.level_groups(1).levels(l_level_index).position>=p_position then
396 return;
397 end if;
398 p_dimension.level_groups(1).levels(l_level_index).position:=p_position;
399 --call the routine recursively for all parents
403 and p_dimension.level_groups(1).parent_child(i).parent_level<>p_dimension.level_groups(1).parent_child(i).child_level then
400 for i in 1..p_dimension.level_groups(1).parent_child.count loop
401 if p_dimension.level_groups(1).parent_child(i).child_level=p_level
402 and p_dimension.level_groups(1).parent_child(i).parent_level is not null
404 set_level_position(p_dimension,p_dimension.level_groups(1).parent_child(i).parent_level,p_position+1);
405 end if;
406 end loop;
407 Exception when others then
408 log_n('Exception in set_level_position '||sqlerrm);
409 raise;
410 End;
411
412 /*
413 find all the kpi implemented in AW that have this dim
414 this reads BSC metadata. so its giving an idea of kpi that maynot be implemented as yet
415 but will be. this means there may be some kpi already implemented that no longer has this dim.
416 this kpi will not be picked up since we are reading bsc metadata
417 kpi_for_dim_r holds the kpi and dimset info
418 */
419 procedure get_kpi_for_dim(p_dimension in out nocopy dimension_r) is
420 Begin
421 bsc_aw_bsc_metadata.get_kpi_for_dim(p_dimension);
422 Exception when others then
423 log_n('Exception in get_kpi_for_dim '||sqlerrm);
424 raise;
425 End;
426
427 /*
428 zero code level are virtual levels that are going to be created
429 its the top levels for any dim
430 if we have
431 comp >- prod >- prod family
432 comp >- prod >- manager
433 we will have 2 zero code levels. final hierarchy is
434 comp >- prod >- prod family >- prod family zero
435 comp >- prod >- manager >- manager zero
436
437 This api is not invoked for recursive dimensions
438
439 new:
440 we do not need zero code levels. this will cause huge problems in olap table fn views. if we have zero code level
441 and regular level, on which will the olap table fn be based? we hit the zero code mv for zero values and regular
442 values.
443
444 zero code is implemented as simply a virtual level. the name is in dim.level_groups(1).levels. in the relation we will have for the
445 top level
446 |
447 zero| country(0) country(0)...
448 |
449 ----------------country---------------------->
450
451 New: we need zero code levels for all levels. imagine that a kpi has only city dim. in this case, we will have zero code
452 for city level since its the top level.
453
454 city zero| city(0)...
455 |
456 ctry zero| country(0) country(0)...
457 |
458 ---city-------------country---------------------->
459
460 */
461 procedure create_virtual_zero_code_level(
462 p_dimension in out nocopy dimension_r
463 )is
464 Begin
465 for i in 1..p_dimension.level_groups(1).levels.count loop
466 p_dimension.level_groups(1).zero_levels(p_dimension.level_groups(1).zero_levels.count+1).level_name:=p_dimension.level_groups(1).levels(i).level_name||'_ZERO';
467 p_dimension.level_groups(1).zero_levels(p_dimension.level_groups(1).zero_levels.count).child_level_name:=p_dimension.level_groups(1).levels(i).level_name;
468 end loop;
469 Exception when others then
470 log_n('Exception in create_virtual_zero_code_level '||sqlerrm);
471 raise;
472 End;
473
474 /*
475 called only for rec dim
476 creates a parent level. this level contains all entries of the child level. child level will maintain fact data for each
477 dim level value, like expense for each employee. the rolled up value = sum of all child values + its own value
478 */
479 procedure create_virtual_rec_level(
480 p_dimension in out nocopy dimension_r
481 )is
482 Begin
483 p_dimension.level_groups(1).rec_levels(1).level_name:=p_dimension.level_groups(1).levels(1).level_name||'_PARENT';
484 p_dimension.level_groups(1).rec_levels(1).child_level_name:=p_dimension.level_groups(1).levels(1).level_name;
485 Exception when others then
486 log_n('Exception in create_virtual_rec_level '||sqlerrm);
487 raise;
488 End;
489
490 /*if this is a bsc rec dim, we cannot have denorm implementation. only norm impl
491 */
492 procedure set_rec_dim_properties(p_dimension in out nocopy dimension_r) is
493 Begin
494 p_dimension.recursive_norm_hier:='Y'; --default
495 Exception when others then
496 log_n('Exception in set_rec_dim_properties '||sqlerrm);
497 raise;
498 End;
499
500 /*
501 rec dim have one level. 2 data sources are necessary. one for the key, like employee. the other is the relation
502 in a denorm fashion, employee,manager
503 we have inc program same as initial program for now
504 rec data source can be null if this is native bsc rec dim
505 */
506 procedure create_rec_data_source(
507 p_dimension in out nocopy dimension_r
508 ) is
509 Begin
510 bsc_aw_bsc_metadata.create_rec_data_source(p_dimension);
511 p_dimension.initial_load_program:='load_'||p_dimension.dim_name||'.initial';
512 p_dimension.inc_load_program:='load_'||p_dimension.dim_name||'.initial';
513 Exception when others then
514 log_n('Exception in create_rec_data_source '||sqlerrm);
515 raise;
516 End;
517
518 /*
519 this procedure creates the data source for dbi dimensions
520 */
521 procedure create_data_source(
522 p_dimension in out nocopy dimension_r
523 ) is
524 Begin
525 bsc_aw_bsc_metadata.create_data_source(p_dimension);
526 p_dimension.initial_load_program:='load_'||p_dimension.dim_name||'.initial';
527 p_dimension.inc_load_program:='load_'||p_dimension.dim_name||'.inc';
528 Exception when others then
529 log_n('Exception in create_data_source '||sqlerrm);
530 raise;
531 End;
532
533 /*
534 updates the metadata and then creates the aw objects for new dim
535 the logic is as follows:
536
537 */
538 procedure implement_dim_aw(
539 p_dimensions in out nocopy dimension_tb,
543 --
540 p_affected_kpi in out nocopy dbms_sql.varchar2_table
541 ) is
542 --
544 Begin
545 if g_debug then
546 log_n('In implement_dim_aw');
547 end if;
548 for i in 1..p_dimensions.count loop
549 implement_dim_aw(p_dimensions(i),p_affected_kpi);
550 end loop;
551 Exception when others then
552 log_n('Exception in implement_dim_aw '||sqlerrm);
553 raise;
554 End;
555
556 procedure implement_dim_aw(
557 p_dimension in out nocopy dimension_r,
558 p_affected_kpi in out nocopy dbms_sql.varchar2_table
559 ) is
560 --
561 l_dim_create varchar2(100);
562 l_recreate_option varchar2(100);
563 --
564 Begin
565 if g_debug then
566 log_n('In implement_dim_aw dimension='||p_dimension.dim_name||', dim type='||p_dimension.dim_type);
567 end if;
568 --see if the dim already exists, or any old dim needs correction
569 if p_dimension.dim_type<>'std' then
570 correct_old_dim(p_dimension,l_dim_create);
571 else
572 if g_debug then
573 log('This is std dim. Check to see if dim exists...');
574 end if;
575 if bsc_aw_md_api.is_dim_present(p_dimension.dim_name)=false then
576 l_dim_create:='create all';
577 end if;
578 end if;
579 --
580 if p_dimension.dim_type='std' then
581 l_recreate_option:='RECREATE STD DIM';
582 else
583 l_recreate_option:='RECREATE DIM';
584 end if;
585 if bsc_aw_utility.get_parameter_value(bsc_aw_utility.g_options,l_recreate_option)='Y' then
586 if g_debug then
587 log('Dim needs to be force recreated');
588 end if;
589 l_dim_create:='create all';
590 elsif bsc_aw_utility.get_parameter_value(bsc_aw_utility.g_options,'RECREATE PROGRAM')='Y' then
591 if g_debug then
592 log('Dim needs to be force recreated');
593 end if;
594 l_dim_create:='create all';
595 end if;
596 if l_dim_create='create all' then
597 if p_dimension.dim_type<>'std' then
598 check_dim_name_conflict(p_dimension);--change the dim name if there is clash
599 end if;
600 create_dim_objects(p_dimension);
601 else
602 if g_debug then
603 log('Noop for dimension '||p_dimension.dim_name);
604 end if;
605 end if;
606 Exception when others then
607 log_n('Exception in implement_dim_aw '||sqlerrm);
608 raise;
609 End;
610
611 /*
612 we will keep this api around. what if we need to drop and recreate kpi in some case?
613 */
614 procedure drop_kpi_objects_for_dim(p_dim_name varchar2,p_affected_kpi in out nocopy dbms_sql.varchar2_table) is
615 --
616 l_kpi_list dbms_sql.varchar2_table;
617 --
618 Begin
619 --get_kpi_for_dim gives the list of kpi already implemented in AW for this dim
620 bsc_aw_md_api.get_kpi_for_dim(p_dim_name,l_kpi_list);
621 bsc_aw_utility.merge_array(p_affected_kpi,l_kpi_list);
622 for i in 1..l_kpi_list.count loop
623 bsc_aw_adapter_kpi.drop_kpi_objects(l_kpi_list(i));
624 bsc_aw_md_api.mark_kpi_recreate(l_kpi_list(i));
625 end loop;
626 Exception when others then
627 log_n('Exception in drop_kpi_objects_for_dim '||sqlerrm);
628 raise;
629 End;
630
631 /*
632 have to drop in this order
633 1. relations and variables
634 2. concat dim
635 3. dim levels
636 4. others like programs
637 */
638 procedure drop_dim(p_dim_name varchar2) is
639 --
640 l_objects bsc_aw_md_wrapper.bsc_olap_object_tb;
641 l_flag dbms_sql.varchar2_table;
642 --
643 Begin
644 bsc_aw_md_api.get_dim_olap_objects(p_dim_name,l_objects,'all');
645 for i in 1..l_objects.count loop
646 if l_objects(i).olap_object_type is null then
647 l_flag(i):='Y';
648 else
649 l_flag(i):='N';
650 end if;
651 end loop;
652 --do not drop dim levels. with the concept of level groups, the dim levels are not blown away
653 for i in 1..l_objects.count loop
654 if l_objects(i).object_type='dimension level' then
655 l_flag(i):='Y'; -- do not drop dim levels. they are standalone dim for snow flaks. they are shared across concat dim
656 end if;
657 end loop;
658 for i in 1..l_objects.count loop
659 if l_flag(i)='N' and (l_objects(i).olap_object_type='relation' or l_objects(i).olap_object_type='variable') then
660 bsc_aw_utility.delete_aw_object(l_objects(i).object);
661 l_flag(i):='Y';
662 end if;
663 end loop;
664 for i in 1..l_objects.count loop
665 if l_flag(i)='N' and l_objects(i).object_type='concat dimension' then
666 bsc_aw_utility.delete_aw_object(l_objects(i).object);
667 l_flag(i):='Y';
668 end if;
669 end loop;
670 for i in 1..l_objects.count loop
671 if l_flag(i)='N' and l_objects(i).object_type='dimension' then
672 bsc_aw_utility.delete_aw_object(l_objects(i).object);
673 l_flag(i):='Y';
674 end if;
675 end loop;
676 for i in 1..l_objects.count loop
677 if l_flag(i)='N' then
678 bsc_aw_utility.delete_aw_object(l_objects(i).object);
679 l_flag(i):='Y';
680 end if;
681 end loop;
682 bsc_aw_md_api.drop_dim(p_dim_name);--this will delete all child objects in metadata
683 Exception when others then
684 log_n('Exception in drop_dim '||sqlerrm);
685 raise;
686 End;
687
688 /*see if any of the levels have a cc dim . if yes, drop them. for the levels, find the old cc dim,
689 for the ccdim, find the kpi drop the kpi structures, mark kpi for recreate, drop old cc dim
690 This is a specialized api. used only to drop the old cc dim for the levels
691 */
692 procedure drop_old_dim_for_level(p_dimension dimension_r,p_affected_kpi in out nocopy dbms_sql.varchar2_table) is
693 --
694 l_dim_list dbms_sql.varchar2_table;
698 --its best to have same structure for all dim. single level dim also have concat dimensions
695 --
696 Begin
697 --for single level dim, there is one level, itself
699 if g_debug then
700 log('In drop_old_dim_for_level '||p_dimension.dim_name);
701 end if;
702 bsc_aw_md_api.get_ccdim_for_levels(p_dimension,l_dim_list);
703 if g_debug then
704 for i in 1..l_dim_list.count loop
705 log('Old CC Dim to be dropped are '||l_dim_list(i));
706 end loop;
707 end if;
708 for i in 1..l_dim_list.count loop
709 drop_kpi_objects_for_dim(l_dim_list(i),p_affected_kpi);
710 drop_dim(l_dim_list(i));
711 end loop;
712 Exception when others then
713 log_n('Exception in drop_old_dim_for_level '||sqlerrm);
714 raise;
715 End;
716
717 /*
718 to create a dim
719 create the level dim
720 if level count> 1
721 create the cc dim
722 create the dim with the level names
723 create relation
724 endif
725 create initial load program
726 create inc refresh program
727 */
728 procedure create_dim_objects(p_dimension in out nocopy dimension_r) is
729 Begin
730 bsc_aw_utility.add_sqlerror(-34340,'ignore',null);
731 bsc_aw_utility.add_sqlerror(-36656,'ignore',null);
732 --all info to create a dim should be in p_dimension
733 create_dim_for_levels(p_dimension);
734 --if there is only 1 level and this level=dim name then we dont create cc dim or relations
735 --this is true for TYPE and PROJECTION dim
736 if not(p_dimension.level_groups(1).levels.count=1 and p_dimension.level_groups(1).levels(1).level_name=p_dimension.dim_name) then
737 create_ccdim(p_dimension);
738 create_level_name_dim(p_dimension);
739 create_relation(p_dimension);
740 end if;
741 create_dim_program(p_dimension);
742 --bug fix 5636695
743 -- calling this api here will fill the correct values in property attribute
744 -- including level name dim
745 set_dim_properties(p_dimension);
746 bsc_aw_md_api.create_dim_objects(p_dimension);
747 bsc_aw_utility.remove_sqlerror(-34340,'ignore');
748 bsc_aw_utility.remove_sqlerror(-36656,'ignore');
749 Exception when others then
750 log_n('Exception in create_dim_objects '||sqlerrm);
751 raise;
752 End;
753
754 /*
755 create dim
756 create filter and limit bool variables
757 create the first value "0"
758 */
759 procedure create_dim_for_levels(p_dimension in out nocopy dimension_r) is
760 --
761 l_dim_data_type varchar2(100);
762 --
763 Begin
764 for i in 1..p_dimension.level_groups(1).levels.count loop
765 --in the prototype in gsitst, we found that dim must be text always for performance
766 --dim datatype is always text. we ran perf prototype and found that with text, we have the
767 --best aggregation perf
768 l_dim_data_type:='TEXT';
769 g_stmt:='dfn '||p_dimension.level_groups(1).levels(i).level_name||' dimension '||l_dim_data_type;
770 bsc_aw_dbms_aw.execute(g_stmt);
771 p_dimension.level_groups(1).levels(i).filter_variable:=p_dimension.level_groups(1).levels(i).level_name||'.filter.bool';
772 p_dimension.level_groups(1).levels(i).limit_variable:=p_dimension.level_groups(1).levels(i).level_name||'.LB';
773 g_stmt:='dfn '||p_dimension.level_groups(1).levels(i).filter_variable||' variable boolean <'||
774 p_dimension.level_groups(1).levels(i).level_name||'>';
775 bsc_aw_dbms_aw.execute(g_stmt);
776 g_stmt:='dfn '||p_dimension.level_groups(1).levels(i).limit_variable||' variable boolean <'||
777 p_dimension.level_groups(1).levels(i).level_name||'>';
778 bsc_aw_dbms_aw.execute(g_stmt);
779 --if std dim, do not add 0
780 if p_dimension.dim_type<>'std' then
781 g_stmt:='maintain '||p_dimension.level_groups(1).levels(i).level_name||' merge ''0''';
782 bsc_aw_dbms_aw.execute(g_stmt);
783 end if;
784 --see if there are seed values to enter
785 --if seed value is a text, it will be entered as '''seedvalue''' . see create_projection_dim
786 for j in 1..p_dimension.level_groups(1).levels(i).seed_values.count loop
787 g_stmt:='maintain '||p_dimension.level_groups(1).levels(i).level_name||' merge '||p_dimension.level_groups(1).levels(i).seed_values(j);
788 bsc_aw_dbms_aw.execute(g_stmt);
789 end loop;
790 end loop;
791 --for the recursive levels
792 for i in 1..p_dimension.level_groups(1).rec_levels.count loop
793 g_stmt:='dfn '||p_dimension.level_groups(1).rec_levels(i).level_name||' dimension '||l_dim_data_type;
794 bsc_aw_dbms_aw.execute(g_stmt);
795 end loop;
796 Exception when others then
797 log_n('Exception in create_dim_for_levels '||sqlerrm);
798 raise;
799 End;
800
801 procedure create_ccdim(p_dimension in out nocopy dimension_r) is
802 l_levels dbms_sql.varchar2_table;
803 Begin
804 g_stmt:='dfn '||p_dimension.dim_name||' dimension concat(';
805 --normal levels
806 for i in 1..p_dimension.level_groups(1).levels.count loop
807 g_stmt:=g_stmt||p_dimension.level_groups(1).levels(i).level_name||',';
808 l_levels(l_levels.count+1):=p_dimension.level_groups(1).levels(i).level_name;
809 end loop;
810 --rec levels
811 for i in 1..p_dimension.level_groups(1).rec_levels.count loop
812 g_stmt:=g_stmt||p_dimension.level_groups(1).rec_levels(i).level_name||',';
813 l_levels(l_levels.count+1):=p_dimension.level_groups(1).rec_levels(i).level_name;
814 end loop;
815 g_stmt:=substr(g_stmt,1,length(g_stmt)-1);
816 g_stmt:=g_stmt||')';
817 bsc_aw_dbms_aw.execute(g_stmt);
818 --add the levels. this is reqd when dim merge happens
819 for i in 1..l_levels.count loop
820 g_stmt:='CHGDFN '||p_dimension.dim_name||' base add '||l_levels(i);
821 bsc_aw_dbms_aw.execute(g_stmt); --we have added ORA-36656 to ignore list
822 end loop;
823 p_dimension.filter_variable:=p_dimension.dim_name||'.filter.bool';
827 bsc_aw_dbms_aw.execute(g_stmt);
824 p_dimension.limit_variable:=p_dimension.dim_name||'.LB';
825 p_dimension.base_value_cube:=p_dimension.dim_name||'.BV';
826 g_stmt:='dfn '||p_dimension.filter_variable||' variable boolean <'||p_dimension.dim_name||'>';
828 g_stmt:='dfn '||p_dimension.limit_variable||' variable boolean <'||p_dimension.dim_name||'>';
829 bsc_aw_dbms_aw.execute(g_stmt);
830 g_stmt:='dfn '||p_dimension.base_value_cube||' variable TEXT <'||p_dimension.dim_name||'>';
831 bsc_aw_dbms_aw.execute(g_stmt);
832 Exception when others then
833 log_n('Exception in create_ccdim '||sqlerrm);
834 raise;
835 End;
836
837 /*
838 when creating the level names, for zero code, we add the names of each zero code level
839 instead of just one "ZERO". the reason is that we may have more than 1 zero code level and
840 we may wish to aggregate on only one of them
841
842 Rec dim have 2 imp. denorm imp and norm imp
843 for denorm imp:
844 for rec dim, the level name dim will contain the values of the dim
845 if we look at the relation, the X axis is cc dim values.
846 the Y axis is the individual level values, ex: employee
847
848 for norm imp:
849 we have the relation which stores the self relation and norm relation
850 a
851 b c
852 d e
853 is represented as
854 rel: A B C D E A A B B
855 dim: a b c d e B C D E
856 we have one more axis in normal hier of rec dim. this axis contains level_name_dim and has values '1', '2' etc
857 depending on how many parents a child has. this extra dim is to take care of cases when a child can have multiple parents
858 if in a dim, the max parents a child has is 3, level_name_dim contains '1', '2' and '3'
859 for non rec dim, the Y axis is the name of the level
860 */
861 procedure create_level_name_dim(p_dimension in out nocopy dimension_r) is
862 Begin
863 p_dimension.level_name_dim:=p_dimension.dim_name||'.levels';
864 g_stmt:='dfn '||p_dimension.level_name_dim||' dimension text';
865 bsc_aw_dbms_aw.execute(g_stmt);
866 if p_dimension.recursive='Y' then
867 if p_dimension.recursive_norm_hier='N' then
868 --we create the cube that is used to store the position of the level values
869 --larry will have 1, john wookey 2 etc. before agg we do limit .levels to .levels.position LE adv_sum_profile
870 --this name .position is assumes in bsc_aw_load_kpi.limit_dim_levels
871 p_dimension.rec_level_position_cube:=p_dimension.dim_name||'.levels.position';
872 g_stmt:='dfn '||p_dimension.rec_level_position_cube||' number<'||p_dimension.level_name_dim||'>';
873 bsc_aw_dbms_aw.execute(g_stmt);
874 else
875 g_stmt:='maintain '||p_dimension.level_name_dim||' merge ''1'''; --default
876 bsc_aw_dbms_aw.execute(g_stmt);
877 end if;
878 else
879 for i in 1..p_dimension.level_groups(1).parent_child.count loop
880 if p_dimension.level_groups(1).parent_child(i).parent_level is not null
881 and p_dimension.level_groups(1).parent_child(i).child_level is not null then
882 g_stmt:='maintain '||p_dimension.level_name_dim||' merge '''||p_dimension.level_groups(1).parent_child(i).parent_level||'.'||
883 p_dimension.level_groups(1).parent_child(i).child_level||'''';
884 bsc_aw_dbms_aw.execute(g_stmt);
885 end if;
886 end loop;
887 --zero code
888 for i in 1..p_dimension.level_groups(1).zero_levels.count loop
889 g_stmt:='maintain '||p_dimension.level_name_dim||' merge '''||p_dimension.level_groups(1).zero_levels(i).level_name||'.'||
890 p_dimension.level_groups(1).zero_levels(i).child_level_name||'''';
891 bsc_aw_dbms_aw.execute(g_stmt);
892 end loop;
893 end if;
894 --create level name dim for each level
895 if p_dimension.dim_type <> 'std' then
896 for i in 1..p_dimension.level_groups(1).levels.count loop
897 p_dimension.level_groups(1).levels(i).level_name_dim:=p_dimension.level_groups(1).levels(i).level_name||'.levels';
898 g_stmt:='dfn '||p_dimension.level_groups(1).levels(i).level_name_dim||' dimension text';
899 bsc_aw_dbms_aw.execute(g_stmt);
900 g_stmt:='maintain '||p_dimension.level_groups(1).levels(i).level_name_dim||' merge '''||
901 get_zero_level(p_dimension,p_dimension.level_groups(1).levels(i).level_name).level_name||'.'||
902 p_dimension.level_groups(1).levels(i).level_name||'''';
903 bsc_aw_dbms_aw.execute(g_stmt);
904 end loop;
905 end if;
906 --
907 Exception when others then
908 log_n('Exception in create_level_name_dim '||sqlerrm);
909 raise;
910 End;
911
912 /*for normal rec hier, level name dim contains ''1'' ''2'' etc. for denorm, its the level values themselves
913 */
914 procedure create_relation(p_dimension in out nocopy dimension_r) is
915 Begin
916 g_stmt:='dfn '||p_dimension.relation_name||' relation '||p_dimension.dim_name||'<'||p_dimension.dim_name||' '||p_dimension.level_name_dim||'>';
917 bsc_aw_dbms_aw.execute(g_stmt);
918 --create each level's relation
919 if p_dimension.dim_type <> 'std' then
920 for i in 1..p_dimension.level_groups(1).levels.count loop
921 p_dimension.level_groups(1).levels(i).relation_name:=p_dimension.level_groups(1).levels(i).level_name||'.rel';
922 g_stmt:='dfn '||p_dimension.level_groups(1).levels(i).relation_name||' relation '||p_dimension.level_groups(1).levels(i).level_name||'<'||
923 p_dimension.level_groups(1).levels(i).level_name||' '||p_dimension.level_groups(1).levels(i).level_name_dim||'>';
924 bsc_aw_dbms_aw.execute(g_stmt);
925 end loop;
926 end if;
927 Exception when others then
928 log_n('Exception in create_relation '||sqlerrm);
929 raise;
930 End;
931
932 procedure create_dim_program(p_dimension dimension_r) is
933 Begin
934 --recursive dim do not have initial and inc programs. they only have initial program. the delta data is
935 --prepared in bsc loader in temp tables.
936 if p_dimension.recursive='Y' then
940 create_dim_program_rec_norm(p_dimension,'initial');
937 if p_dimension.recursive_norm_hier='N' then --denorm implementation
938 create_dim_program_rec(p_dimension,'initial');
939 else --norm hier normalization
941 end if;
942 else
943 create_dim_program(p_dimension,'initial');
944 create_dim_program(p_dimension,'inc');
945 end if;
946 Exception when others then
947 log_n('Exception in create_dim_program '||sqlerrm);
948 raise;
949 End;
950
951 /*
952 This api is only called for NON rec dims
953 */
954 procedure create_dim_program(p_dimension dimension_r,p_mode varchar2) is
955 --
956 l_pgm varchar2(300);
957 --
958 Begin
959 --when this api is called, there must not be a program in the workspace
960 g_commands.delete;
961 if p_mode='initial' then
962 l_pgm:=p_dimension.initial_load_program;
963 else
964 l_pgm:=p_dimension.inc_load_program;
965 end if;
966 if l_pgm is not null then
967 bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_pgm||' program');
968 bsc_aw_utility.add_g_commands(g_commands,'allstat');
969 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB=false');
970 for i in 1..p_dimension.level_groups.count loop
971 create_dim_program(p_dimension,p_dimension.level_groups(i),p_mode);
972 end loop;
973 --base value
974 --base value cubes will be used in the olap table functions for the kpi
975 if p_dimension.base_value_cube is not null then
976 bsc_aw_utility.add_g_commands(g_commands,p_dimension.base_value_cube||'=baseval('||p_dimension.dim_name||')');
977 end if;
978 --
979 bsc_aw_utility.exec_program_commands(l_pgm,g_commands);
980 end if;
981 Exception when others then
982 log_n('Exception in create_dim_program '||sqlerrm);
983 raise;
984 End;
985
986 procedure create_dim_program(p_dimension dimension_r,p_level_group level_group_r,p_mode varchar2) is
987 --
988 l_levels levels_tb;
989 l_parent_child dim_parent_child_tb;
990 l_zero_levels zero_levels_tb;
991 l_snowflake_levels levels_tb;
992 Begin
993 --if p_level_group.data_source.data_source is not null, then p_level_group.data_source.inc_data_source is also not null
994 if p_level_group.data_source.data_source is not null then
995 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
996 --this is where we cannot assume that the data source has the same name as the levels.
997 --this is for DBI dimensions (non rec)
998 --we will assume that in data_source.pk_col the order is an exact match to p_level_group.levels
999 l_levels.delete;
1000 l_parent_child.delete;
1001 l_zero_levels.delete;
1002 l_snowflake_levels.delete;
1003 --
1004 l_levels:=p_level_group.levels;
1005 if p_dimension.dim_type <> 'std' then
1006 l_snowflake_levels:=p_level_group.levels;
1007 end if;
1008 l_zero_levels:=p_level_group.zero_levels;
1009 for i in 1..p_level_group.parent_child.count loop
1010 if p_level_group.parent_child(i).parent_level is not null and p_level_group.parent_child(i).child_level is not null then
1011 l_parent_child(l_parent_child.count+1):=p_level_group.parent_child(i);
1012 end if;
1013 end loop;
1014 for i in 1..p_level_group.data_source.pk_col.count loop
1015 bsc_aw_utility.add_g_commands(g_commands,p_level_group.data_source.pk_col(i)||', --');
1016 end loop;
1017 bsc_aw_utility.trim_g_commands(g_commands,4,' --');
1018 bsc_aw_utility.add_g_commands(g_commands,'from --');
1019 if p_mode='initial' then
1020 bsc_aw_utility.add_g_commands(g_commands,p_level_group.data_source.data_source);
1021 else
1022 bsc_aw_utility.add_g_commands(g_commands,p_level_group.data_source.inc_data_source);
1023 end if;
1024 --there is no where clause. the where clause is in the data_source
1025 create_dim_program(p_dimension,l_levels,l_parent_child,l_zero_levels,l_snowflake_levels);
1026 else
1027 --default construction of the data source. this is for bsc dimensions.
1028 for i in 1..p_level_group.levels.count loop
1029 l_levels.delete;
1030 l_parent_child.delete;
1031 l_zero_levels.delete;
1032 l_snowflake_levels.delete;
1033 --
1034 l_levels(l_levels.count+1):=p_level_group.levels(i);
1035 if p_dimension.dim_type <> 'std' then
1036 l_snowflake_levels(l_snowflake_levels.count+1):=p_level_group.levels(i);
1037 end if;
1038 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
1039 bsc_aw_utility.add_g_commands(g_commands,nvl(p_level_group.levels(i).level_name||'.'||p_level_group.levels(i).pk.pk,'CODE')||', --');
1040 for j in 1..p_level_group.parent_child.count loop
1041 if p_level_group.parent_child(j).child_level=p_level_group.levels(i).level_name and p_level_group.parent_child(j).parent_level is not null then
1042 l_parent_child(l_parent_child.count+1):=p_level_group.parent_child(j);
1043 l_levels(l_levels.count+1):=get_level(p_dimension,p_level_group.parent_child(j).parent_level);
1044 bsc_aw_utility.add_g_commands(g_commands,p_level_group.parent_child(j).child_level||'.'||p_level_group.parent_child(j).child_fk||', --');
1045 end if;
1046 end loop;
1047 bsc_aw_utility.trim_g_commands(g_commands,4,' --');
1048 bsc_aw_utility.add_g_commands(g_commands,'from --');
1049 bsc_aw_utility.add_g_commands(g_commands,p_level_group.levels(i).level_name);
1050 for j in 1..p_level_group.zero_levels.count loop
1051 if p_level_group.zero_levels(j).child_level_name=p_level_group.levels(i).level_name and p_level_group.zero_levels(j).level_name is not null then
1052 l_zero_levels(l_zero_levels.count+1):=p_level_group.zero_levels(j);
1053 end if;
1054 end loop;
1055 create_dim_program(p_dimension,l_levels,l_parent_child,l_zero_levels,l_snowflake_levels);
1059 --
1056 end loop;
1057 end if;
1058 --setting the kpi limit cubes is now done outside the program in bsc_aw_load_dim.set_kpi_limit_variables
1060 /*deletes for dimensions
1061 delete are handled in the following way
1062 delete table has 2 columns. dim_level and delete_value. say we have geog dim. city,state,country
1063 we want to delete all cities in ca and ca
1064 the table has
1065 'city' 'SF'
1066 'city' 'LA'
1067 'state' 'CA'
1068 for each level in the dim, we see if there are delete values. if there are we do the following
1069 mark limit cubes for the parent value for re-agg.
1070 in our case, we will mark state of ca and country of usa for re-agg
1071 the dim values are deleted in dim load module
1072 */
1073 --p_level_group.levels(i).level_name
1074 bsc_aw_utility.add_g_commands(g_commands,'allstat');
1075 if p_level_group.levels.count>1 then
1076 for i in 1..p_level_group.levels.count loop
1077 --we only need these for levels that have parents.
1078 if level_has_parents(p_level_group.parent_child,p_level_group.levels(i).level_name) then
1079 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select delete_value from bsc_aw_dim_delete '||
1080 ' where dim_level=\'''||p_level_group.levels(i).level_name||'\''');
1081 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1082 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1083 /*5064802. we need to handle the case where the dim value in bsc_aw_dim_delete does not exist in aw dim. go on append mode. then
1084 dim loader delete will delete them */
1085 bsc_aw_utility.add_g_commands(g_commands,':append '||p_level_group.levels(i).level_name||' --');
1086 bsc_aw_utility.add_g_commands(g_commands,'then --');
1087 for j in 1..p_level_group.parent_child.count loop
1088 if p_level_group.parent_child(j).child_level=p_level_group.levels(i).level_name
1089 and p_level_group.parent_child(j).parent_level is not null then
1090 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB('||p_dimension.dim_name||' '||
1091 p_dimension.relation_name||'('||p_dimension.dim_name||' '||p_level_group.parent_child(j).child_level||' '||
1092 p_dimension.level_name_dim||' \'''||p_level_group.parent_child(j).parent_level||'.'||
1093 p_level_group.parent_child(j).child_level||
1094 '\''))=TRUE --');
1095 --setting of kpi limit cubes is done in bsc_aw_load_dim.set_kpi_limit_variables
1096 end if;
1097 end loop;
1098 bsc_aw_utility.trim_g_commands(g_commands,3,null);
1099 bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
1100 bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
1101 end if;
1102 end loop;
1103 end if;
1104 Exception when others then
1105 log_n('Exception in create_dim_program '||sqlerrm);
1106 raise;
1107 End;
1108
1109 procedure create_dim_program(
1110 p_dimension dimension_r,
1111 p_levels levels_tb,
1112 p_parent_child dim_parent_child_tb,
1113 p_zero_levels zero_levels_tb,
1114 p_snowflake_levels levels_tb
1115 ) is
1116 Begin
1117 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1118 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1119 for i in 1..p_levels.count loop
1120 bsc_aw_utility.add_g_commands(g_commands,':append '||p_levels(i).level_name||' --');
1121 end loop;
1122 /*
1123 initial hier was A>- B>- C, it changed to A>- C
1124 in this case, we need to reaggregate for A and B
1125 the bottom relation part is true for BSC as well as a non rec dbi dim
1126 there was a bug here. we were marking A and B. this will reagg for A and C correctly, but not for B. we had to mark the
1127 children for B, only then data is aggregated for B correctly. the way around this is to mark the parents only. B and C.
1128 after we load the dim, we setthe kpi limit cubes. there, we today to limit dim to dim.LB, then for all the kpi limit cubes
1129 set kpi.LB=true. instead, we will have limit dim to dim.LB, then limit dim to children using dim.rel, then we set the kpi
1130 limit cubes
1131 */
1132 if p_parent_child.count>0 or p_zero_levels.count>0 or p_snowflake_levels.count>0 then
1133 bsc_aw_utility.add_g_commands(g_commands,'then --');
1134 --see if the relations have any change
1135 for i in 1..p_parent_child.count loop
1136 if p_parent_child(i).parent_level is not null then
1137 bsc_aw_utility.add_g_commands(g_commands,'if '||p_dimension.relation_name||'('||p_dimension.dim_name||' '||p_parent_child(i).child_level||' '||
1138 p_dimension.level_name_dim||' \'''||p_parent_child(i).parent_level||'.'||p_parent_child(i).child_level||'\'') ne NA --');
1139 bsc_aw_utility.add_g_commands(g_commands,'AND '||p_dimension.relation_name||'('||p_dimension.dim_name||' '||p_parent_child(i).child_level||' '||
1140 p_dimension.level_name_dim||' \'''||p_parent_child(i).parent_level||'.'||p_parent_child(i).child_level||
1141 '\'') ne '||p_dimension.dim_name||'('||
1142 p_parent_child(i).parent_level||' '||p_parent_child(i).parent_level||') --');
1143 bsc_aw_utility.add_g_commands(g_commands,'then do --');
1144 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB('||p_dimension.dim_name||' '||p_dimension.relation_name||'('||
1145 p_dimension.dim_name||' '||p_parent_child(i).child_level||' '||p_dimension.level_name_dim||' \'''||
1146 p_parent_child(i).parent_level||'.'||p_parent_child(i).child_level||'\''))=TRUE --');
1147 --bug fix.initially, it was p_parent_child(i).child_level||')=TRUE --');
1148 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB('||p_dimension.dim_name||' '||p_parent_child(i).parent_level||')=TRUE --');
1149 bsc_aw_utility.add_g_commands(g_commands,'doend --');
1150 end if;
1151 end loop;
1152 --now, assign the new values to the rel
1153 for i in 1..p_parent_child.count loop
1154 if p_parent_child(i).parent_level is not null then
1158 p_parent_child(i).parent_level||' '||p_parent_child(i).parent_level||') --');
1155 bsc_aw_utility.add_g_commands(g_commands,p_dimension.relation_name||'('||p_dimension.dim_name||' '||p_parent_child(i).child_level||' '||
1156 p_dimension.level_name_dim||' \'''||p_parent_child(i).parent_level||'.'||p_parent_child(i).child_level||
1157 '\'')='||p_dimension.dim_name||'('||
1159 end if;
1160 end loop;
1161 --add the relations for zero code
1162 if p_zero_levels.count>0 then
1163 for i in 1..p_zero_levels.count loop
1164 --we have to make sure we eliminate circular relation. all the levels contain one row that is the zero row. for example city's 0
1165 --rolls to state 0 which rolls to country 0. we need to make sure that 0 is not the parent of zero
1166 /* error looks like this:
1167 ORA-36036: (XSMHIERCK01) One or more loops have been detected in relationship BSC_AW!BSC_CCDIM_100_101_102_103.REL over
1168 BSC_AW!BSC_CCDIM_100_101_102_103. The 1 items involved are <BSC_D_PRODUCT_FAMILY_AW: 0>.
1169 */
1170 bsc_aw_utility.add_g_commands(g_commands,'if '||p_zero_levels(i).child_level_name||' NE \''0\'' --');
1171 bsc_aw_utility.add_g_commands(g_commands,'then do --');
1172 bsc_aw_utility.add_g_commands(g_commands,p_dimension.relation_name||'('||p_dimension.dim_name||' '||p_zero_levels(i).child_level_name||' '||
1173 p_dimension.level_name_dim||' \'''||p_zero_levels(i).level_name||'.'||p_zero_levels(i).child_level_name||
1174 '\'')='||p_dimension.dim_name||'('||
1175 p_zero_levels(i).child_level_name||' \''0\'') --');
1176 bsc_aw_utility.add_g_commands(g_commands,'doend --');
1177 end loop;
1178 end if;
1179 --snowflake relation. we need to populate the levels's relation that maps the levels to the zero code
1180 --in the future we may need to see if we need to create relations with other levels
1181 --but zero code will still be there.
1182 for i in 1..p_snowflake_levels.count loop
1183 if p_snowflake_levels(i).relation_name is not null then
1184 bsc_aw_utility.add_g_commands(g_commands,'if '||p_snowflake_levels(i).level_name||' NE \''0\'' --');
1185 bsc_aw_utility.add_g_commands(g_commands,'then do --');
1186 bsc_aw_utility.add_g_commands(g_commands,p_snowflake_levels(i).relation_name||'('||p_snowflake_levels(i).level_name_dim||
1187 ' \'''||get_zero_level(p_dimension,p_snowflake_levels(i).level_name).level_name||'.'||p_snowflake_levels(i).level_name||'\'')='||
1188 p_snowflake_levels(i).level_name||'('||p_snowflake_levels(i).level_name||' \''0\'') --');
1189 bsc_aw_utility.add_g_commands(g_commands,'doend --');
1190 end if;
1191 end loop;
1192 end if;
1193 bsc_aw_utility.trim_g_commands(g_commands,3,null);
1194 bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
1195 bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
1196 Exception when others then
1197 log_n('Exception in create_dim_program '||sqlerrm);
1198 raise;
1199 End;
1200
1201 function level_has_parents(
1202 p_parent_child dim_parent_child_tb,
1203 p_level_name varchar2) return boolean is
1204 Begin
1205 for i in 1..p_parent_child.count loop
1206 if p_parent_child(i).child_level=p_level_name and p_parent_child(i).parent_level is not null then
1207 return true;
1208 end if;
1209 end loop;
1210 return false;
1211 Exception when others then
1212 log_n('Exception in level_has_parents '||sqlerrm);
1213 raise;
1214 End;
1215
1216 /*This api is only called for rec dims ONLY implemented in denorm way
1217 denorm implementation possible only for dbi based rec dim
1218 */
1219 procedure create_dim_program_rec(p_dimension dimension_r,p_mode varchar2) is
1220 l_pgm varchar2(300);
1221 Begin
1222 g_commands.delete;
1223 if p_dimension.initial_load_program is not null then
1224 l_pgm:=p_dimension.initial_load_program;
1225 bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_pgm||' program');
1226 bsc_aw_utility.add_g_commands(g_commands,'allstat');
1227 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB=false');
1228 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
1229 --in rec dim, there must be only ONE real level. then there is a virtual rec level
1230 --we select twice since we append to the real and virtual dim
1231 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.pk_col(1)||' code1, --');
1232 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.pk_col(1)||' code2 --');
1233 bsc_aw_utility.add_g_commands(g_commands,'from --');
1234 --for rec dim, we full refresh each time
1235 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.data_source);
1236 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1237 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1238 bsc_aw_utility.add_g_commands(g_commands,':append '||p_dimension.level_groups(1).levels(1).level_name||' --');
1239 bsc_aw_utility.add_g_commands(g_commands,':append '||p_dimension.level_groups(1).rec_levels(1).level_name||' ');
1240 bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
1241 bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
1242 --now, the child parent relations
1243 --we select parent_col twice for the virtual dim and also the name dim.
1244 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
1245 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.child_col||','||
1246 p_dimension.level_groups(1).data_source.parent_col||','||
1247 p_dimension.level_groups(1).data_source.parent_col||','||p_dimension.level_groups(1).data_source.position_col||' --');
1248 bsc_aw_utility.add_g_commands(g_commands,'from --');
1249 --relation fully refreshed each time. see notes
1250 --this does not mean kpi will need full agg. dim load will figure out if there is hier change
1254 bsc_aw_utility.add_g_commands(g_commands,':match '||p_dimension.level_groups(1).levels(1).level_name||' --');
1251 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.denorm_data_source);
1252 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1253 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1255 bsc_aw_utility.add_g_commands(g_commands,':match '||p_dimension.level_groups(1).rec_levels(1).level_name||' --');
1256 bsc_aw_utility.add_g_commands(g_commands,':append '||p_dimension.level_name_dim||' --');
1257 bsc_aw_utility.add_g_commands(g_commands,':'||p_dimension.rec_level_position_cube||' --');
1258 bsc_aw_utility.add_g_commands(g_commands,'then '||p_dimension.relation_name||'('||p_dimension.dim_name||' '||
1259 p_dimension.level_groups(1).levels(1).level_name||')='||
1260 p_dimension.dim_name||'('||p_dimension.level_groups(1).rec_levels(1).level_name||' '||p_dimension.level_groups(1).rec_levels(1).level_name||')');
1261 bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
1262 bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
1263 --set the value of the old relations to NA. these parent child relations no longer exist
1264 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
1265 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.parent_col||', --');
1266 bsc_aw_utility.add_g_commands(g_commands,'1, --');
1267 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.child_col||', --');
1268 bsc_aw_utility.add_g_commands(g_commands,'1, --');
1269 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.parent_col||' --');
1270 bsc_aw_utility.add_g_commands(g_commands,'from --');
1271 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.denorm_change_data_source);
1272 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1273 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1274 bsc_aw_utility.add_g_commands(g_commands,':match '||p_dimension.level_groups(1).levels(1).level_name||' --');
1275 bsc_aw_utility.add_g_commands(g_commands,':'||p_dimension.dim_name||'.LB('||
1276 p_dimension.dim_name||' '||p_dimension.level_groups(1).levels(1).level_name||') --');
1277 --we set kpi limit cubes in bsc_aw_load_dim.set_kpi_limit_variables
1278 --mark change for managers
1279 bsc_aw_utility.add_g_commands(g_commands,':match '||p_dimension.level_groups(1).levels(1).level_name||' --');
1280 bsc_aw_utility.add_g_commands(g_commands,':'||p_dimension.dim_name||'.LB('||
1281 p_dimension.dim_name||' '||p_dimension.level_groups(1).levels(1).level_name||') --');
1282 --mark change for employees
1283 bsc_aw_utility.add_g_commands(g_commands,':match '||p_dimension.level_name_dim||' --');
1284 bsc_aw_utility.add_g_commands(g_commands,'then '||p_dimension.relation_name||'('||p_dimension.dim_name||' '||
1285 p_dimension.level_groups(1).levels(1).level_name||')=NA ');
1286 --base value cubes will be used in the olap table functions for the kpi
1287 if p_dimension.base_value_cube is not null then
1288 bsc_aw_utility.add_g_commands(g_commands,p_dimension.base_value_cube||'=baseval('||p_dimension.dim_name||')');
1289 end if;
1290 bsc_aw_utility.exec_program_commands(l_pgm,g_commands);
1291 end if;
1292 Exception when others then
1293 log_n('Exception in create_dim_program_rec '||sqlerrm);
1294 raise;
1295 End;
1296
1297 /*if the rec dim is implemented with normal hier. this is the default implementation
1298 */
1299 procedure create_dim_program_rec_norm(p_dimension dimension_r,p_mode varchar2) is
1300 l_pgm varchar2(300);
1301 Begin
1302 --if the temp variable does not exist, create it.
1303 bsc_aw_dbms_aw.execute_ne('dfn temp_text text');
1304 g_commands.delete;
1305 if p_dimension.initial_load_program is not null then
1306 l_pgm:=p_dimension.initial_load_program;
1307 bsc_aw_utility.add_g_commands(g_commands,'dfn '||l_pgm||' program');
1308 bsc_aw_utility.add_g_commands(g_commands,'allstat');
1309 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB=false');
1310 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
1311 --in rec dim, there must be only ONE real level. then there is a virtual rec level
1312 --we select twice since we append to the real and virtual dim
1313 if p_dimension.level_groups(1).data_source.data_source is not null then --dbi dimension
1314 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.pk_col(1)||' code1, --');
1315 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.pk_col(1)||' code2 --');
1316 else
1317 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).levels(1).pk.pk||' code1, --');
1318 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).levels(1).pk.pk||' code2 --');
1319 end if;
1320 bsc_aw_utility.add_g_commands(g_commands,'from --');
1321 --for rec dim, we full refresh each time
1322 if p_dimension.level_groups(1).data_source.data_source is not null then
1323 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).data_source.data_source);
1324 else
1325 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).levels(1).level_name);
1326 end if;
1327 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1328 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1329 bsc_aw_utility.add_g_commands(g_commands,':append '||p_dimension.level_groups(1).levels(1).level_name||' --');
1330 bsc_aw_utility.add_g_commands(g_commands,':append '||p_dimension.level_groups(1).rec_levels(1).level_name||' --');
1331 bsc_aw_utility.add_g_commands(g_commands,'then --');
1332 bsc_aw_utility.add_g_commands(g_commands,p_dimension.relation_name||'('||
1333 p_dimension.dim_name||' '||p_dimension.level_groups(1).levels(1).level_name||' '||p_dimension.level_name_dim||' \''1\'')='||
1334 p_dimension.dim_name||'('||p_dimension.level_groups(1).rec_levels(1).level_name||' '||p_dimension.level_groups(1).rec_levels(1).level_name||')');
1338 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
1335 bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
1336 bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
1337 --now, the child parent relations
1339 if p_dimension.level_groups(1).data_source.data_source is not null then
1340 bsc_aw_utility.add_g_commands(g_commands,'child,parent,to_char(id) from bsc_aw_temp_pc');
1341 else
1342 --chil fk is the parent col and parent pk is the child col
1343 bsc_aw_utility.add_g_commands(g_commands,p_dimension.level_groups(1).parent_child(1).parent_pk||','||
1344 p_dimension.level_groups(1).parent_child(1).child_fk||',to_char(rank() over(partition by '||p_dimension.level_groups(1).parent_child(1).parent_pk||' '||
1345 'order by '||p_dimension.level_groups(1).parent_child(1).child_fk||')) id --');
1346 bsc_aw_utility.add_g_commands(g_commands,'from '||p_dimension.level_groups(1).levels(1).level_name||' where '||
1347 p_dimension.level_groups(1).parent_child(1).child_fk||' is not null');
1348 end if;
1349 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1350 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1351 bsc_aw_utility.add_g_commands(g_commands,':match '||p_dimension.level_groups(1).rec_levels(1).level_name||' --');
1352 bsc_aw_utility.add_g_commands(g_commands,':temp_text --');
1353 bsc_aw_utility.add_g_commands(g_commands,':append '||p_dimension.level_name_dim||' --');
1354 bsc_aw_utility.add_g_commands(g_commands,'then --');
1355 bsc_aw_utility.add_g_commands(g_commands,'if '||p_dimension.relation_name||'('||
1356 p_dimension.dim_name||' '||p_dimension.level_groups(1).rec_levels(1).level_name||') NE NA AND '||
1357 p_dimension.relation_name||'('||
1358 p_dimension.dim_name||' '||p_dimension.level_groups(1).rec_levels(1).level_name||') NE '||
1359 p_dimension.dim_name||'('||p_dimension.level_groups(1).rec_levels(1).level_name||' temp_text) --');
1360 bsc_aw_utility.add_g_commands(g_commands,'then do --');
1361 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB('||p_dimension.dim_name||' '||
1362 p_dimension.relation_name||'('||p_dimension.dim_name||' '||p_dimension.level_groups(1).rec_levels(1).level_name||'))=TRUE --');
1363 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB('||
1364 p_dimension.level_groups(1).rec_levels(1).level_name||' temp_text)=TRUE --');
1365 bsc_aw_utility.add_g_commands(g_commands,'doend --');
1366 bsc_aw_utility.add_g_commands(g_commands,p_dimension.relation_name||'('||
1367 p_dimension.dim_name||' '||p_dimension.level_groups(1).rec_levels(1).level_name||')='||
1368 p_dimension.dim_name||'('||p_dimension.level_groups(1).rec_levels(1).level_name||' temp_text)');
1369 bsc_aw_utility.add_g_commands(g_commands,'sql close c1');
1370 bsc_aw_utility.add_g_commands(g_commands,'sql cleanup');
1371 --handle dim delete. this is just like for normal dim
1372 --if there are deletes, we have to mark the parents for these values for re-agg
1373 --for rec, dim the delete values are loaded into bsc_aw_dim_delete with the real level name, not the virtual parent
1374 --level name
1375 bsc_aw_utility.add_g_commands(g_commands,'sql declare c1 cursor for select --');
1376 bsc_aw_utility.add_g_commands(g_commands,'delete_value from bsc_aw_dim_delete '||
1377 ' where dim_level=\'''||p_dimension.level_groups(1).levels(1).level_name||'\''');
1378 bsc_aw_utility.add_g_commands(g_commands,'sql open c1');
1379 bsc_aw_utility.add_g_commands(g_commands,'sql fetch c1 loop into --');
1380 bsc_aw_utility.add_g_commands(g_commands,':match '||p_dimension.level_groups(1).rec_levels(1).level_name||' --');
1381 bsc_aw_utility.add_g_commands(g_commands,'then --');
1382 bsc_aw_utility.add_g_commands(g_commands,p_dimension.dim_name||'.LB('||p_dimension.dim_name||' '||
1383 p_dimension.relation_name||'('||p_dimension.dim_name||' '||p_dimension.level_groups(1).rec_levels(1).level_name||'))=TRUE ');
1384 --base value cubes will be used in the olap table functions for the kpi
1385 if p_dimension.base_value_cube is not null then
1386 bsc_aw_utility.add_g_commands(g_commands,p_dimension.base_value_cube||'=baseval('||p_dimension.dim_name||')');
1387 end if;
1388 bsc_aw_utility.exec_program_commands(l_pgm,g_commands);
1389 end if;
1390 Exception when others then
1391 log_n('Exception in create_dim_program_rec_norm '||sqlerrm);
1392 raise;
1393 End;
1394
1395 procedure dmp_g_dimensions(p_dimensions dimension_tb) is
1396 Begin
1397 log('----------------------');
1398 for i in 1..p_dimensions.count loop
1399 dmp_dimension(p_dimensions(i));
1400 end loop;
1401 Exception when others then
1402 log_n('Exception in dmp_g_dimensions '||sqlerrm);
1403 raise;
1404 End;
1405
1406 procedure dmp_dimension(p_dim dimension_r) is
1407 Begin
1408 log('====');
1409 log('Dimension dmp');
1410 log('Dimension : '||p_dim.dim_name||' Rel:'||p_dim.relation_name||' rec:'||p_dim.recursive||
1411 ' Imp with Norm Hier:'||p_dim.recursive_norm_hier);
1412 log('Property: '||p_dim.property);
1413 for i in 1..p_dim.level_groups.count loop
1414 dmp_level_group(p_dim.level_groups(i));
1415 end loop;
1416 log('KPI for dim:-');
1417 for i in 1..p_dim.kpi_for_dim.count loop
1418 log(p_dim.kpi_for_dim(i).kpi);
1419 log(' KPI Dimsets for KPI:-');
1420 for j in 1..p_dim.kpi_for_dim(i).dim_set.count loop
1421 log(' '||p_dim.kpi_for_dim(i).dim_set(j));
1422 end loop;
1423 end loop;
1424 log('====');
1425 Exception when others then
1426 log_n('Exception in dmp_dimension '||sqlerrm);
1427 raise;
1428 End;
1429
1430 procedure dmp_level_group(p_level_group level_group_r) is
1431 Begin
1432 log('Level group '||p_level_group.level_group_name);
1433 log('Levels:-');
1434 for i in 1..p_level_group.levels.count loop
1435 log(p_level_group.levels(i).level_name||' id='||p_level_group.levels(i).level_id||' position='||
1439 log('Zero Levels:-');
1436 p_level_group.levels(i).position||' property='||p_level_group.levels(i).property||' pk='||
1437 p_level_group.levels(i).pk.pk||' datatype='||p_level_group.levels(i).pk.data_type);
1438 end loop;
1440 for i in 1..p_level_group.zero_levels.count loop
1441 log(p_level_group.zero_levels(i).level_name||' child level name='||
1442 p_level_group.zero_levels(i).child_level_name);
1443 end loop;
1444 log('Recursive Levels:-');
1445 for i in 1..p_level_group.rec_levels.count loop
1446 log(p_level_group.rec_levels(i).level_name);
1447 end loop;
1448 log('Parent Child:-');
1449 for i in 1..p_level_group.parent_child.count loop
1450 log(p_level_group.parent_child(i).parent_level||'('||p_level_group.parent_child(i).parent_pk||') '||
1451 p_level_group.parent_child(i).child_level||'('||p_level_group.parent_child(i).child_fk||') '||
1452 p_level_group.parent_child(i).level_set);
1453 end loop;
1454 log('Data Source:-');
1455 for i in 1..p_level_group.data_source.dim_name.count loop
1456 log(p_level_group.data_source.pk_col(i)||' -> '||p_level_group.data_source.dim_name(i));
1457 end loop;
1458 log('Initial data source='||p_level_group.data_source.data_source);
1459 log('Inc data source='||p_level_group.data_source.inc_data_source);
1460 log('denorm child col='||p_level_group.data_source.child_col||', denorm parent col='||
1461 p_level_group.data_source.parent_col||', denorm position col='||p_level_group.data_source.position_col);
1462 log('Initial denorm data source='||p_level_group.data_source.denorm_data_source);
1463 log('Change denorm data source='||p_level_group.data_source.denorm_change_data_source);
1464 log('---');
1465 Exception when others then
1466 log_n('Exception in dmp_level_group '||sqlerrm);
1467 raise;
1468 End;
1469
1470 /*
1471 this creates the std dim
1472 TYPE
1473 PROJECTION
1474 these dim are part of every kpi. in the kpi adapter, each kpi is also given these 2 dimensions
1475 */
1476 procedure create_std_dim(p_dimensions in out nocopy dimension_tb) is
1477 Begin
1478 create_type_dim(p_dimensions);
1479 create_projection_dim(p_dimensions);
1480 Exception when others then
1481 log_n('Exception in create_std_dim '||sqlerrm);
1482 raise;
1483 End;
1484
1485 --creates std type dim to the data structure
1486 procedure create_type_dim(p_dimensions in out nocopy dimension_tb) is
1487 l_dim dimension_r;
1488 Begin
1489 --bug fix 5636695
1490 -- we have used a new public var l_dim here, so as to take an empty structure and fill in
1491 -- the issue here was we had level values and parent child values retained from the previous
1492 -- kpi run p_dimensions... which was causing problem
1493 --- this will clear the previous entries from the structure
1494 l_dim.dim_name:='TYPE';
1495 l_dim.corrected:='N';
1496 l_dim.concat:='N';
1497 l_dim.dim_type:='std';
1498 l_dim.relation_name:=null;--not going to be used. type is single level dim
1499 l_dim.recursive:='N';
1500 l_dim.recursive_norm_hier:='N';
1501 l_dim.initial_load_program:='load_type.initial';
1502 l_dim.inc_load_program:='load_type.inc';
1503 --
1504 l_dim.level_groups(1).levels(1).level_name:='TYPE';
1505 l_dim.level_groups(1).levels(1).level_id:=1;
1506 l_dim.level_groups(1).levels(1).position:=1;
1507 l_dim.level_groups(1).levels(1).property:=null;
1508 l_dim.level_groups(1).levels(1).pk.pk:='type';
1509 l_dim.level_groups(1).levels(1).pk.data_type:='text';
1510 --
1511 l_dim.level_groups(1).parent_child(1).parent_level:=null;
1512 l_dim.level_groups(1).parent_child(1).child_level:='TYPE';
1513 l_dim.level_groups(1).parent_child(1).parent_pk:=null;
1514 l_dim.level_groups(1).parent_child(1).child_fk:=null;
1515 --
1516 l_dim.level_groups(1).data_source.dim_name(1):='TYPE';
1517 l_dim.level_groups(1).data_source.pk_col(1):='data_type';
1518 l_dim.level_groups(1).data_source.data_source:='(select distinct data_type from bsc_sys_benchmarks_b)';
1519 l_dim.level_groups(1).data_source.inc_data_source:='(select distinct data_type from bsc_sys_benchmarks_b)';
1520 --
1521 p_dimensions(p_dimensions.count+1):= l_dim;
1522 get_kpi_for_dim(p_dimensions(p_dimensions.count));
1523 set_dim_properties(p_dimensions(p_dimensions.count));
1524 Exception when others then
1525 log_n('Exception in create_type_dim '||sqlerrm);
1526 raise;
1527 End;
1528
1529 --creates std projection dim to the data structure
1530 procedure create_projection_dim(p_dimensions in out nocopy dimension_tb) is
1531 l_dim dimension_r;
1532 Begin
1533 --bug fix 5636695
1534 -- we have used a new public var l_dim here, so as to take an empty structure and fill in
1535 -- the issue here was we had level values and parent child values retained from the previous
1536 -- kpi run p_dimensions... which was causing problem
1537 --- this will clear the previous entries from the structure
1538 l_dim.dim_name:='PROJECTION';
1539 l_dim.corrected:='N';
1540 l_dim.concat:='N';
1541 l_dim.dim_type:='std';
1542 l_dim.relation_name:=null;--not going to be used. type is single level dim
1543 l_dim.recursive:='N';
1544 l_dim.recursive_norm_hier:='N';
1545 l_dim.initial_load_program:=null;--projection dim has 2 values, Y or N
1546 l_dim.inc_load_program:=null;
1547 --
1548 l_dim.level_groups(1).levels(1).level_name:='PROJECTION';
1549 l_dim.level_groups(1).levels(1).level_id:=1;
1550 l_dim.level_groups(1).levels(1).position:=1;
1551 l_dim.level_groups(1).levels(1).seed_values(1):='''Y''';
1552 l_dim.level_groups(1).levels(1).seed_values(2):='''N''';
1553 l_dim.level_groups(1).levels(1).property:=null;
1554 l_dim.level_groups(1).levels(1).pk.pk:='projection';
1555 l_dim.level_groups(1).levels(1).pk.data_type:='text';
1556 --
1557 l_dim.level_groups(1).parent_child(1).parent_level:=null;
1558 l_dim.level_groups(1).parent_child(1).child_level:='PROJECTION';
1562 --projection has no data source
1559 l_dim.level_groups(1).parent_child(1).parent_pk:=null;
1560 l_dim.level_groups(1).parent_child(1).child_fk:=null;
1561 --
1563 --
1564 p_dimensions(p_dimensions.count+1):= l_dim;
1565 get_kpi_for_dim(p_dimensions(p_dimensions.count));
1566 set_dim_properties(p_dimensions(p_dimensions.count));
1567 Exception when others then
1568 log_n('Exception in create_projection_dim '||sqlerrm);
1569 raise;
1570 End;
1571
1572 procedure create_dmp_program(p_dim_level varchar2,p_name varchar2) is
1573 Begin
1574 g_commands.delete;
1575 bsc_aw_utility.add_g_commands(g_commands,'dfn '||p_name||' program');
1576 bsc_aw_utility.add_g_commands(g_commands,'allstat');
1577 bsc_aw_utility.add_g_commands(g_commands,'sql prepare c1 from --');
1578 bsc_aw_utility.add_g_commands(g_commands,'insert into bsc_aw_dim_data values (\'''||p_dim_level||'\'',:'||p_dim_level||') DIRECT=YES');
1579 bsc_aw_utility.add_g_commands(g_commands,'for '||p_dim_level);
1580 bsc_aw_utility.add_g_commands(g_commands,'do');
1581 bsc_aw_utility.add_g_commands(g_commands,'sql execute c1');
1582 bsc_aw_utility.add_g_commands(g_commands,'if sqlcode ne 0');
1583 bsc_aw_utility.add_g_commands(g_commands,'then break');
1584 bsc_aw_utility.add_g_commands(g_commands,'doend');
1585 bsc_aw_utility.exec_program_commands(p_name,g_commands);
1586 Exception when others then
1587 log_n('Exception in create_dmp_program '||sqlerrm);
1588 raise;
1589 End;
1590
1591 function get_zero_level(p_dimension dimension_r,p_level varchar2) return zero_levels_r is
1592 l_zero_level zero_levels_r;
1593 Begin
1594 for i in 1..p_dimension.level_groups.count loop
1595 l_zero_level:=get_zero_level(p_dimension.level_groups(i),p_level);
1596 if l_zero_level.level_name is not null then
1597 return l_zero_level;
1598 end if;
1599 end loop;
1600 return null;
1601 Exception when others then
1602 log_n('Exception in get_zero_level '||sqlerrm);
1603 raise;
1604 End;
1605
1606 function get_zero_level(p_level_group level_group_r,p_level varchar2) return zero_levels_r is
1607 Begin
1608 for i in 1..p_level_group.zero_levels.count loop
1609 if p_level_group.zero_levels(i).child_level_name=p_level then
1610 return p_level_group.zero_levels(i);
1611 end if;
1612 end loop;
1613 return null;
1614 Exception when others then
1615 log_n('Exception in get_zero_level '||sqlerrm);
1616 raise;
1617 End;
1618
1619 /*
1620 given a dim, what are the kpi limit cubes. called in dim load
1621 */
1622 procedure get_dim_kpi_limit_cubes(
1623 p_dim varchar2,
1624 p_limit_cubes out nocopy dbms_sql.varchar2_table,
1625 p_aggregate_marker out nocopy dbms_sql.varchar2_table,
1626 p_reset_cubes out nocopy dbms_sql.varchar2_table
1627 ) is
1628 --
1629 l_olap_object_relation bsc_aw_md_wrapper.bsc_olap_object_relation_tb;
1630 Begin
1631 l_olap_object_relation.delete;
1632 bsc_aw_md_api.get_bsc_olap_object_relation(p_dim,'dimension',null,null,null,l_olap_object_relation);
1633 for i in 1..l_olap_object_relation.count loop
1634 --do this only if the limit cube is "actual" limit cube. not if its target limit cube
1635 if bsc_aw_utility.get_parameter_value(l_olap_object_relation(i).property1,'dim set type',',')='actual' then
1636 if l_olap_object_relation(i).relation_type='kpi limit cube' then
1637 p_limit_cubes(p_limit_cubes.count+1):=l_olap_object_relation(i).relation_object;
1638 elsif l_olap_object_relation(i).relation_type='kpi aggregate marker' then
1639 p_aggregate_marker(p_aggregate_marker.count+1):=l_olap_object_relation(i).relation_object;
1640 elsif l_olap_object_relation(i).relation_type='kpi reset cube' then
1641 p_reset_cubes(p_reset_cubes.count+1):=l_olap_object_relation(i).relation_object;
1642 end if;
1643 end if;
1644 end loop;
1645 Exception when others then
1646 log_n('Exception in get_dim_kpi_limit_cubes '||sqlerrm);
1647 raise;
1648 End;
1649
1650 /*
1651 this procedure needs to see if there are existing dim for the levels and then to see if
1652 1. we can merge into an existing dim
1653 2. we need to correct the existing dim
1654 p_dim is the new image of the dim
1655 for each level in p_dim, check to see the existing dim.
1656 if not already processed
1657 see if we can merge.
1658 if all the old dim levels are in new dim
1659 if each relation of old dim is in new dim
1660 if old dim.number of levels<new dim.number of levels and old dim.corrected='N'
1661 merge
1662 endif
1663 endif
1664 endif
1665 if merge
1666 merge_dim(old dim, new dim)
1667 else
1668 correct dim(old dim,p_flag) p_flag is corrected or noop
1669 endif
1670 endif
1671 --
1672 correct dim:
1673 invalidate any level not used by aw kpi
1674 invalidate any non existent relation
1675 if any of the above 2 happens
1676 create level groups
1677 correct level name dim / relation
1678 recreate program
1679 delete old metadata
1680 insert new metadata
1681 endif
1682
1683 merge:
1684 delete old metadata
1685 create dim with merge mode
1686 add level name dim / relation
1687 create new levels
1688 recreate program
1689 insert metadata
1690 --
1691 */
1692 procedure correct_old_dim(p_dim dimension_r,p_flag out nocopy varchar2) is
1693 l_old_dim dimension_tb;
1694 l_merge_dim dimension_tb;
1695 l_new_dim dimension_r;
1696 l_old_dim_list dbms_sql.varchar2_table;
1697 l_old_dim_action dbms_sql.varchar2_table;
1698 Begin
1699 if g_debug then
1700 log('correct_old_dim for '||p_dim.dim_name);
1701 end if;
1702 p_flag:='create all';
1703 l_new_dim:=p_dim;
1704 bsc_aw_md_api.get_ccdim_for_levels(p_dim,l_old_dim_list);
1708 if g_debug then
1705 if l_old_dim_list.count>0 then
1706 for i in 1..l_old_dim_list.count loop
1707 bsc_aw_md_api.get_dim_md(l_old_dim_list(i),l_old_dim(i));
1709 log('Old dim dmp');
1710 dmp_dimension(l_old_dim(i));
1711 end if;
1712 --
1713 check_old_dim_operation(l_old_dim(i),p_dim,l_old_dim_action(i));
1714 if l_old_dim_action(i)='drop' then
1715 drop_dim(l_old_dim(i).dim_name);
1716 elsif l_old_dim_action(i)='correct' then
1717 correct_dim(l_old_dim(i));--correct old dim
1718 end if;
1719 end loop;
1720 --see if there is no change to the dim
1721 for i in 1..l_old_dim_list.count loop
1722 if l_old_dim_action(i)='same' then
1723 p_flag:='noop';
1724 exit;
1725 end if;
1726 end loop;
1727 if p_flag<>'noop' then
1728 --see if merge needed.
1729 for i in 1..l_old_dim_list.count loop
1730 if l_old_dim_action(i)='merge' then
1731 l_merge_dim(l_merge_dim.count+1):=l_old_dim(i);
1732 end if;
1733 end loop;
1734 if l_merge_dim.count>0 then
1735 merge_dim(l_merge_dim,l_new_dim);--merge into the dim with the best level match. rest are corrected
1736 p_flag:='noop'; --for the new dim. we need no op since we have already merged new into old
1737 end if;
1738 end if;
1739 end if;
1740 if g_debug then
1741 log('For the new dimension '||p_dim.dim_name||', final action required is '||p_flag);
1742 end if;
1743 Exception when others then
1744 log_n('Exception in correct_old_dim '||sqlerrm);
1745 raise;
1746 End;
1747
1748 /*
1749 correct old dim. this is essentially disintegrating the old dim
1750 correction of a dim is with respect to the metadata that exists in the system, not with respect to new dim
1751 corrections can happen on dim that had been corrected in previous runs
1752 */
1753 procedure correct_dim(p_old_dim in out nocopy dimension_r) is
1754 l_old_level_groups level_group_tb;
1755 l_new_levels levels_tb;
1756 l_new_zero_levels zero_levels_tb;
1757 l_new_parent_child dim_parent_child_tb;
1758 l_new_level_groups level_group_tb;
1759 Begin
1760 if g_debug then
1761 log('Correct Old dim '||p_old_dim.dim_name);
1762 end if;
1763 l_old_level_groups:=p_old_dim.level_groups;
1764 --
1765 for i in 1..p_old_dim.level_groups.count loop
1766 correct_levels(p_old_dim.level_groups(i).levels,l_new_levels);
1767 p_old_dim.level_groups(i).levels:=l_new_levels;
1768 end loop;
1769 for i in 1..p_old_dim.level_groups.count loop
1770 correct_zero_levels(p_old_dim.level_groups(i).levels,p_old_dim.level_groups(i).zero_levels,l_new_zero_levels);
1771 p_old_dim.level_groups(i).zero_levels:=l_new_zero_levels;
1772 end loop;
1773 for i in 1..p_old_dim.level_groups.count loop
1774 correct_parent_child(p_old_dim.level_groups(i),p_old_dim.level_groups(i).parent_child,l_new_parent_child);
1775 p_old_dim.level_groups(i).parent_child:=l_new_parent_child;
1776 end loop;
1777 correct_level_name_dim(p_old_dim.level_name_dim,l_old_level_groups,p_old_dim.level_groups);
1778 correct_level_groups(p_old_dim.level_groups,l_new_level_groups);
1779 p_old_dim.level_groups.delete;
1780 for i in 1..l_new_level_groups.count loop
1781 p_old_dim.level_groups(p_old_dim.level_groups.count+1):=l_new_level_groups(i);
1782 end loop;
1783 --
1784 /*
1785 following steps in correction
1786 drop old metadata
1787 drop programs
1788 re-create programs
1789 */
1790 --set the property to corrected
1791 p_old_dim.corrected:='Y';
1792 set_dim_properties(p_old_dim);
1793 if g_debug then
1794 log('After correct levels,zero levels,parent child,level name dim and level groups');
1795 dmp_dimension(p_old_dim);
1796 end if;
1797 bsc_aw_md_api.drop_dim(p_old_dim.dim_name);
1798 create_dim_program(p_old_dim);
1799 bsc_aw_md_api.create_dim_objects(p_old_dim);
1800 Exception when others then
1801 log_n('Exception in correct_dim '||sqlerrm);
1802 raise;
1803 End;
1804
1805 /*
1806 there can be multiple dim for merge. D1 with 10 levels could have split into 3,3,2,1,1
1807 if now all 10 levels are together, the 5 new dim are candidates for merge. merge into the one with
1808 3 levels. all others are corrected
1809 */
1810 procedure merge_dim(p_old_dim in out nocopy dimension_tb,p_new_dim in out nocopy dimension_r) is
1811 l_new_levels dbms_sql.varchar2_table;
1812 l_number_match dbms_sql.number_table;
1813 l_max number;
1814 Begin
1815 for i in 1..p_new_dim.level_groups.count loop
1816 for j in 1..p_new_dim.level_groups(i).levels.count loop
1817 bsc_aw_utility.merge_value(l_new_levels,p_new_dim.level_groups(i).levels(j).level_name);
1818 end loop;
1819 end loop;
1820 --
1821 for i in 1..p_old_dim.count loop
1822 l_number_match(i):=0;
1823 for j in 1..p_old_dim(i).level_groups.count loop
1824 for k in 1..p_old_dim(i).level_groups(j).levels.count loop
1825 if bsc_aw_utility.in_array(l_new_levels,p_old_dim(i).level_groups(j).levels(k).level_name) then
1826 l_number_match(i):=l_number_match(i)+1;
1827 end if;
1828 end loop;
1829 end loop;
1830 if g_debug then
1831 log('For old dim '||p_old_dim(i).dim_name||', number of levels matching new dim='||l_number_match(i));
1832 end if;
1833 end loop;
1834 l_max:=bsc_aw_utility.get_max(l_number_match);
1835 for i in 1..p_old_dim.count loop
1836 if l_number_match(i)=l_max then
1837 merge_dim(p_old_dim(i),p_new_dim);
1838 --correct all others
1839 for j in 1..p_old_dim.count loop
1840 if i <> j then
1841 correct_dim(p_old_dim(j));
1842 end if;
1843 end loop;
1844 exit;
1845 end if;
1846 end loop;
1850 End;
1847 Exception when others then
1848 log_n('Exception in merge_dim '||sqlerrm);
1849 raise;
1851
1852 procedure merge_dim(p_old_dim dimension_r,p_new_dim in out nocopy dimension_r) is
1853 l_new_dim_name varchar2(200);
1854 Begin
1855 if g_debug then
1856 log('Merge dim Old dim '||p_old_dim.dim_name||', New dim '||p_new_dim.dim_name);
1857 end if;
1858 l_new_dim_name:=p_new_dim.dim_name;
1859 --change the names in new dim to that of the old
1860 p_new_dim.dim_name:=p_old_dim.dim_name;
1861 p_new_dim.dim_type:=p_old_dim.dim_type;
1862 p_new_dim.concat:=p_old_dim.concat;
1863 p_new_dim.property:=p_old_dim.property;
1864 p_new_dim.relation_name:=p_old_dim.relation_name;
1865 p_new_dim.level_name_dim:=p_old_dim.level_name_dim;
1866 p_new_dim.recursive:=p_old_dim.recursive;
1867 p_new_dim.recursive_norm_hier:=p_old_dim.recursive_norm_hier;
1868 p_new_dim.initial_load_program:=p_old_dim.initial_load_program;
1869 p_new_dim.inc_load_program:=p_old_dim.inc_load_program;
1870 p_new_dim.filter_variable:=p_old_dim.filter_variable;
1871 p_new_dim.limit_variable:=p_old_dim.limit_variable;
1872 p_new_dim.rec_level_position_cube:=p_old_dim.rec_level_position_cube;
1873 p_new_dim.base_value_cube:=p_old_dim.base_value_cube;
1874 for i in 1..p_new_dim.level_groups.count loop
1875 for j in 1..p_new_dim.level_groups(i).data_source.dim_name.count loop
1876 if p_new_dim.level_groups(i).data_source.dim_name(j)=l_new_dim_name then
1877 p_new_dim.level_groups(i).data_source.dim_name(j):=p_new_dim.dim_name;
1878 end if;
1879 end loop;
1880 end loop;
1881 --
1882 bsc_aw_md_api.drop_dim(p_old_dim.dim_name);--drop metadata
1883 create_dim_objects(p_new_dim);--creates objects and metadata
1884 Exception when others then
1885 log_n('Exception in merge_dim '||sqlerrm);
1886 raise;
1887 End;
1888
1889 /*
1890 remove levels that are no more used by aw kpi
1891 */
1892 procedure correct_levels(p_old_level levels_tb,p_new_level out nocopy levels_tb) is
1893 Begin
1894 for i in 1..p_old_level.count loop
1895 if bsc_aw_bsc_metadata.is_level_used_by_aw_kpi(p_old_level(i).level_name) then
1896 p_new_level(p_new_level.count+1):=p_old_level(i);
1897 end if;
1898 end loop;
1899 Exception when others then
1900 log_n('Exception in correct_levels '||sqlerrm);
1901 raise;
1902 End;
1903
1904 procedure correct_zero_levels(p_new_level levels_tb,p_old_zero_level zero_levels_tb,p_new_zero_level out nocopy zero_levels_tb) is
1905 l_levels dbms_sql.varchar2_table;
1906 Begin
1907 for i in 1..p_new_level.count loop
1908 l_levels(l_levels.count+1):=p_new_level(i).level_name;
1909 end loop;
1910 for i in 1..p_old_zero_level.count loop
1911 if bsc_aw_utility.in_array(l_levels,p_old_zero_level(i).child_level_name) then
1912 p_new_zero_level(p_new_zero_level.count+1):=p_old_zero_level(i);
1913 end if;
1914 end loop;
1915 Exception when others then
1916 log_n('Exception in correct_zero_levels '||sqlerrm);
1917 raise;
1918 End;
1919
1920 procedure correct_parent_child(p_level_group level_group_r,p_old_pc dim_parent_child_tb,p_new_pc out nocopy dim_parent_child_tb) is
1921 l_parents dbms_sql.varchar2_table;
1922 l_levels dbms_sql.varchar2_table;
1923 l_dim_levels dbms_sql.varchar2_table;
1924 Begin
1925 for i in 1..p_level_group.levels.count loop
1926 l_dim_levels(l_dim_levels.count+1):=p_level_group.levels(i).level_name;
1927 end loop;
1928 for i in 1..p_old_pc.count loop
1929 if bsc_aw_utility.in_array(l_dim_levels,p_old_pc(i).child_level) then
1930 bsc_aw_utility.merge_value(l_levels,p_old_pc(i).child_level);
1931 end if;
1932 end loop;
1933 for i in 1..l_levels.count loop
1934 l_parents.delete;
1935 bsc_aw_bsc_metadata.get_parent_level(l_levels(i),l_parents); --does not return top node
1936 for j in 1..p_old_pc.count loop
1937 if p_old_pc(j).child_level=l_levels(i) then
1938 --if p_old_pc(j).parent_level is null and l_parents.count=0
1939 --and bsc_aw_utility.in_array(l_dim_levels,p_old_pc(j).parent_level) then
1940 if p_old_pc(j).parent_level is null then
1941 p_new_pc(p_new_pc.count+1):=p_old_pc(j);
1942 elsif l_parents.count=0 then
1943 p_new_pc(p_new_pc.count+1):=p_old_pc(j);
1944 p_new_pc(p_new_pc.count).parent_level:=null;
1945 p_new_pc(p_new_pc.count).parent_pk:=null;
1946 p_new_pc(p_new_pc.count).child_fk:=null;
1947 elsif bsc_aw_utility.in_array(l_parents,p_old_pc(j).parent_level)
1948 and bsc_aw_utility.in_array(l_dim_levels,p_old_pc(j).parent_level) then
1949 p_new_pc(p_new_pc.count+1):=p_old_pc(j);
1950 else
1951 --this relation is no more valid
1952 null;
1953 end if;
1954 end if;
1955 end loop;
1956 end loop;
1957 Exception when others then
1958 log_n('Exception in correct_parent_child '||sqlerrm);
1959 raise;
1960 End;
1961
1962 procedure correct_level_name_dim(p_level_name_dim varchar2,p_old_level_groups level_group_tb,p_new_level_groups level_group_tb) is
1963 l_flag boolean;
1964 Begin
1965 for i in 1..p_old_level_groups.count loop
1966 for j in 1..p_old_level_groups(i).parent_child.count loop
1967 l_flag:=false;
1968 for k in 1..p_new_level_groups.count loop
1969 for m in 1..p_new_level_groups(k).parent_child.count loop
1970 if nvl(p_old_level_groups(i).parent_child(j).child_level,'^')=nvl(p_new_level_groups(k).parent_child(m).child_level,'^')
1971 and nvl(p_old_level_groups(i).parent_child(j).parent_level,'^')=nvl(p_new_level_groups(k).parent_child(m).parent_level,'^') then
1972 l_flag:=true;
1973 exit;
1974 end if;
1975 end loop;
1976 if l_flag then
1977 exit;
1978 end if;
1979 end loop;
1983 bsc_aw_dbms_aw.execute('maintain '||p_level_name_dim||' delete '''||p_old_level_groups(i).parent_child(j).parent_level||'.'||
1980 if l_flag=false then
1981 if p_old_level_groups(i).parent_child(j).child_level is not null and p_old_level_groups(i).parent_child(j).parent_level is not null then
1982 --remove this
1984 p_old_level_groups(i).parent_child(j).child_level||'''');
1985 end if;
1986 end if;
1987 end loop;
1988 --correct zero entries
1989 for j in 1..p_old_level_groups(i).zero_levels.count loop
1990 l_flag:=false;
1991 for k in 1..p_new_level_groups.count loop
1992 for m in 1..p_new_level_groups(k).zero_levels.count loop
1993 if p_old_level_groups(i).zero_levels(j).level_name=p_new_level_groups(k).zero_levels(m).level_name then
1994 l_flag:=true;
1995 exit;
1996 end if;
1997 end loop;
1998 if l_flag then
1999 exit;
2000 end if;
2001 end loop;
2002 if l_flag=false then
2003 bsc_aw_dbms_aw.execute('maintain '||p_level_name_dim||' delete '''||p_old_level_groups(i).zero_levels(j).level_name||'.'||
2004 p_old_level_groups(i).zero_levels(j).child_level_name||'''');
2005 end if;
2006 end loop;
2007 end loop;
2008 Exception when others then
2009 log_n('Exception in correct_level_name_dim '||sqlerrm);
2010 raise;
2011 End;
2012
2013 /*
2014 level groups are never going to merge. they can only break up. so the number of level groups can only rise
2015 look at each level group. if there is break in connection, break up the level group
2016 */
2017 procedure correct_level_groups(p_old_level_groups level_group_tb,p_new_level_groups out nocopy level_group_tb) is
2018 l_max_lg number;
2019 l_new_level_groups level_group_tb;
2020 Begin
2021 l_max_lg:=0;
2022 for i in 1..p_old_level_groups.count loop
2023 l_new_level_groups.delete;
2024 correct_level_groups(p_old_level_groups(i),l_new_level_groups);
2025 for j in 1..l_new_level_groups.count loop
2026 l_max_lg:=l_max_lg+1;
2027 l_new_level_groups(j).level_group_name:='level group.'||l_max_lg;
2028 p_new_level_groups(p_new_level_groups.count+1):=l_new_level_groups(j);
2029 end loop;
2030 end loop;
2031 Exception when others then
2032 log_n('Exception in correct_level_groups '||sqlerrm);
2033 raise;
2034 End;
2035
2036 procedure correct_level_groups(p_old_level_group level_group_r,p_new_level_groups out nocopy level_group_tb) is
2037 --
2038 l_max_set number;
2039 l_level_considered dbms_sql.varchar2_table;
2040 l_zero_level zero_levels_r;
2041 l_rec_level rec_levels_r;
2042 l_old_level_group level_group_r;
2043 Begin
2044 l_old_level_group:=p_old_level_group;
2045 for i in 1..l_old_level_group.parent_child.count loop
2046 l_old_level_group.parent_child(i).level_set:=null;
2047 end loop;
2048 group_levels_into_sets(l_old_level_group.parent_child);
2049 l_max_set:=0;
2050 for i in 1..l_old_level_group.parent_child.count loop
2051 if l_old_level_group.parent_child(i).level_set>l_max_set then
2052 l_max_set:=l_old_level_group.parent_child(i).level_set;
2053 end if;
2054 end loop;
2055 --
2056 if l_max_set=1 then --no level group split
2057 p_new_level_groups(p_new_level_groups.count+1):=l_old_level_group;
2058 else
2059 for i in 1..l_max_set loop
2060 p_new_level_groups(p_new_level_groups.count+1).level_group_name:=l_old_level_group.level_group_name;
2061 /*
2062 the following are determined
2063 levels,
2064 parent_child,
2065 zero_levels,
2066 rec_levels,
2067 the following are blindly copied.
2068 data_source,
2069 property
2070 */
2071 p_new_level_groups(p_new_level_groups.count).data_source:=l_old_level_group.data_source;
2072 p_new_level_groups(p_new_level_groups.count).property:=l_old_level_group.property;
2073 l_level_considered.delete;
2074 for j in 1..l_old_level_group.parent_child.count loop
2075 if l_old_level_group.parent_child(j).level_set=i then
2076 p_new_level_groups(p_new_level_groups.count).parent_child(p_new_level_groups(p_new_level_groups.count).parent_child.count+1):=
2077 l_old_level_group.parent_child(j);
2078 --
2079 if l_old_level_group.parent_child(j).child_level is not null
2080 and bsc_aw_utility.in_array(l_level_considered,l_old_level_group.parent_child(j).child_level)=false then
2081 p_new_level_groups(p_new_level_groups.count).levels(p_new_level_groups(p_new_level_groups.count).levels.count+1):=
2082 get_level(l_old_level_group,l_old_level_group.parent_child(j).child_level);
2083 l_zero_level:=get_zero_level(l_old_level_group,l_old_level_group.parent_child(j).child_level);
2084 if l_zero_level.level_name is not null then
2085 p_new_level_groups(p_new_level_groups.count).zero_levels(p_new_level_groups(p_new_level_groups.count).zero_levels.count+1):=
2086 l_zero_level;
2087 end if;
2088 l_rec_level:=get_rec_level(l_old_level_group,l_old_level_group.parent_child(j).child_level);
2089 if l_rec_level.level_name is not null then
2090 p_new_level_groups(p_new_level_groups.count).rec_levels(p_new_level_groups(p_new_level_groups.count).rec_levels.count+1):=
2091 l_rec_level;
2092 end if;
2093 l_level_considered(l_level_considered.count+1):=l_old_level_group.parent_child(j).child_level;
2094 end if;
2095 --
2096 if l_old_level_group.parent_child(j).parent_level is not null
2097 and bsc_aw_utility.in_array(l_level_considered,l_old_level_group.parent_child(j).parent_level)=false then
2098 p_new_level_groups(p_new_level_groups.count).levels(p_new_level_groups(p_new_level_groups.count).levels.count+1):=
2102 p_new_level_groups(p_new_level_groups.count).zero_levels(p_new_level_groups(p_new_level_groups.count).zero_levels.count+1):=
2099 get_level(l_old_level_group,l_old_level_group.parent_child(j).parent_level);
2100 l_zero_level:=get_zero_level(l_old_level_group,l_old_level_group.parent_child(j).parent_level);
2101 if l_zero_level.level_name is not null then
2103 l_zero_level;
2104 end if;
2105 l_rec_level:=get_rec_level(l_old_level_group,l_old_level_group.parent_child(j).parent_level);
2106 if l_rec_level.level_name is not null then
2107 p_new_level_groups(p_new_level_groups.count).rec_levels(p_new_level_groups(p_new_level_groups.count).rec_levels.count+1):=
2108 l_rec_level;
2109 end if;
2110 l_level_considered(l_level_considered.count+1):=l_old_level_group.parent_child(j).parent_level;
2111 end if;
2112 end if;
2113 end loop;
2114 end loop;
2115 end if;
2116 Exception when others then
2117 log_n('Exception in correct_level_groups '||sqlerrm);
2118 raise;
2119 End;
2120
2121 /*
2122 p_flag = correct, merge, noop or same
2123 p_flag is from the perspective of p_old_dim
2124 */
2125 procedure check_old_dim_operation(p_old_dim dimension_r,p_new_dim dimension_r,p_flag out nocopy varchar2) is
2126 l_level_list dbms_sql.varchar2_table;
2127 l_old_level_list dbms_sql.varchar2_table;
2128 l_level_group level_group_r;
2129 l_pc_comparison number;
2130 Begin
2131 if g_debug then
2132 log('check_old_dim_operation, check Old dim '||p_old_dim.dim_name||' with New dim '||p_new_dim.dim_name);
2133 end if;
2134 for i in 1..p_new_dim.level_groups.count loop
2135 for j in 1..p_new_dim.level_groups(i).levels.count loop
2136 l_level_list(l_level_list.count+1):=p_new_dim.level_groups(i).levels(j).level_name;
2137 end loop;
2138 end loop;
2139 for i in 1..p_old_dim.level_groups.count loop
2140 for j in 1..p_old_dim.level_groups(i).levels.count loop
2141 l_old_level_list(l_old_level_list.count+1):=p_old_dim.level_groups(i).levels(j).level_name;
2142 end loop;
2143 end loop;
2144 --see if the dim is un-used and can be dropped
2145 if p_flag is null then
2146 if p_old_dim.corrected='Y' and p_old_dim.kpi_for_dim.count=0 then
2147 p_flag:='drop';
2148 end if;
2149 if g_debug then
2150 if p_flag is not null then
2151 log('Dim '||p_old_dim.dim_name||' is already corrected and unused. Drop...');
2152 end if;
2153 end if;
2154 end if;
2155 --
2156 if p_flag is null then
2157 for i in 1..l_old_level_list.count loop
2158 if bsc_aw_utility.in_array(l_level_list,l_old_level_list(i))=false then -- no merge possible. correction reqd
2159 p_flag:='correct';
2160 exit;
2161 end if;
2162 end loop;
2163 if p_flag is not null then
2164 if g_debug then
2165 log('All levels of old not in new.p_flag='||p_flag);
2166 end if;
2167 end if;
2168 end if;
2169 --
2170 if p_flag is null then --check to see if all old relations exist in the new one
2171 for i in 1..p_old_dim.level_groups.count loop --we check each level group
2172 l_level_group:=get_level_group(p_new_dim,p_old_dim.level_groups(i).levels(1).level_name);
2173 l_pc_comparison:=compare_pc_relations(l_level_group.parent_child,p_old_dim.level_groups(i).parent_child);
2174 if not(l_pc_comparison=0 or l_pc_comparison=2) then --old is NOT in new
2175 p_flag:='correct';
2176 exit;
2177 elsif l_pc_comparison=2 and p_old_dim.corrected='N' then
2178 p_flag:='merge';
2179 end if;
2180 end loop;
2181 if p_flag is not null then
2182 if g_debug then
2183 log('Checked old vs new level relations.p_flag='||p_flag);
2184 end if;
2185 end if;
2186 end if;
2187 if p_flag is null then
2188 if p_old_dim.corrected='N' then --old and new dim are the same. no change.
2189 p_flag:='same';
2190 else
2191 p_flag:='noop'; --no op reqd on old dim (which is a corrected dim)
2192 end if;
2193 end if;
2194 if g_debug then
2195 log('Final flag '||p_flag);
2196 end if;
2197 Exception when others then
2198 log_n('Exception in check_old_dim_operation '||sqlerrm);
2199 raise;
2200 End;
2201
2202 /*
2203 given a level, get the level group
2204 note>>> one level can only belong to one level group
2205 */
2206 function get_level_group(p_dim dimension_r,p_level varchar2) return level_group_r is
2207 Begin
2208 for i in 1..p_dim.level_groups.count loop
2209 for j in 1..p_dim.level_groups(i).levels.count loop
2210 if p_dim.level_groups(i).levels(j).level_name=p_level then
2211 return p_dim.level_groups(i);
2212 end if;
2213 end loop;
2214 end loop;
2215 return null;
2216 Exception when others then
2217 log_n('Exception in get_level_group '||sqlerrm);
2218 raise;
2219 End;
2220
2221 /*
2222 -1 : 2 rel diff
2223 0 : 2 rel same
2224 1 : 1 is in 2
2225 2: 2 is in 1
2226 */
2227 function compare_pc_relations(p_pc_1 dim_parent_child_tb,p_pc_2 dim_parent_child_tb) return number is
2228 --
2229 l_pc_1 bsc_aw_utility.parent_child_tb;
2230 l_pc_2 bsc_aw_utility.parent_child_tb;
2231 Begin
2232 for i in 1..p_pc_1.count loop
2233 l_pc_1(i).parent:=p_pc_1(i).parent_level;
2234 l_pc_1(i).child:=p_pc_1(i).child_level;
2235 end loop;
2236 for i in 1..p_pc_2.count loop
2237 l_pc_2(i).parent:=p_pc_2(i).parent_level;
2238 l_pc_2(i).child:=p_pc_2(i).child_level;
2239 end loop;
2240 return bsc_aw_utility.compare_pc_relations(l_pc_1,l_pc_2);
2241 Exception when others then
2242 log_n('Exception in compare_pc_relations '||sqlerrm);
2246 function get_level(p_dimension dimension_r,p_level varchar2) return levels_r is
2243 raise;
2244 End;
2245
2247 l_level levels_r;
2248 Begin
2249 for i in 1..p_dimension.level_groups.count loop
2250 l_level:=get_level(p_dimension.level_groups(i),p_level);
2251 if l_level.level_name is not null then
2252 return l_level;
2253 end if;
2254 end loop;
2255 return null;
2256 Exception when others then
2257 log_n('Exception in get_level '||sqlerrm);
2258 raise;
2259 End;
2260
2261 function get_level(p_level_group level_group_r,p_level varchar2) return levels_r is
2262 Begin
2263 for i in 1..p_level_group.levels.count loop
2264 if p_level_group.levels(i).level_name=p_level then
2265 return p_level_group.levels(i);
2266 end if;
2267 end loop;
2268 return null;
2269 Exception when others then
2270 log_n('Exception in get_level '||sqlerrm);
2271 raise;
2272 End;
2273
2274 function get_rec_level(p_level_group level_group_r,p_level varchar2) return rec_levels_r is
2275 Begin
2276 for i in 1..p_level_group.rec_levels.count loop
2277 if p_level_group.rec_levels(i).child_level_name=p_level then
2278 return p_level_group.rec_levels(i);
2279 end if;
2280 end loop;
2281 return null;
2282 Exception when others then
2283 log_n('Exception in get_rec_level '||sqlerrm);
2284 raise;
2285 End;
2286
2287 procedure check_dim_name_conflict(p_dimension in out nocopy dimension_r) is
2288 l_count number;
2289 Begin
2290 l_count:=0;
2291 loop --till we get unique name
2292 if l_count>bsc_aw_utility.g_infinite_loop then
2293 log('Infinite loop detected in check_dim_name_conflict');
2294 raise bsc_aw_utility.g_exception;
2295 end if;
2296 if bsc_aw_md_api.is_dim_present(p_dimension.dim_name)=false then --no name conflict
2297 exit;
2298 end if;
2299 l_count:=l_count+1;
2300 make_dim_name(p_dimension,get_dim_name_hash_string(p_dimension)||'.'||bsc_aw_utility.get_dbms_time);
2301 end loop;
2302 if g_debug then
2303 log('check_dim_name_conflict, final dim name '||p_dimension.dim_name);
2304 end if;
2305 Exception when others then
2306 log_n('Exception in check_dim_name_conflict '||sqlerrm);
2307 raise;
2308 End;
2309
2310 function get_default_lg_name return varchar2 is
2311 Begin
2312 return 'level group.1';
2313 Exception when others then
2314 log_n('Exception in get_default_lg_name '||sqlerrm);
2315 raise;
2316 End;
2317
2318 function get_std_dim_list return dbms_sql.varchar2_table is
2319 l_dim dbms_sql.varchar2_table;
2320 Begin
2321 l_dim(1):='TYPE';
2322 l_dim(2):='PROJECTION';
2323 return l_dim;
2324 Exception when others then
2325 log_n('Exception in get_std_dim_list '||sqlerrm);
2326 raise;
2327 End;
2328
2329 function get_preloaded_dim_list return dbms_sql.varchar2_table is
2330 l_dim dbms_sql.varchar2_table;
2331 Begin
2332 l_dim(1):='PROJECTION';
2333 return l_dim;
2334 Exception when others then
2335 log_n('Exception in get_preloaded_dim_list '||sqlerrm);
2336 raise;
2337 End;
2338
2339 /*given a set of child levels and parent levels, find the hier subset that includes all of them */
2340 function get_hier_subset(p_parent_child dim_parent_child_tb,p_parent_level dbms_sql.varchar2_table,
2341 p_child_level dbms_sql.varchar2_table) return dim_parent_child_tb is
2342 l_pc_subset dim_parent_child_tb;
2343 l_pc_subset_temp dim_parent_child_tb;
2344 Begin
2345 for i in 1..p_child_level.count loop
2346 for j in 1..p_parent_level.count loop
2347 l_pc_subset_temp.delete;
2348 l_pc_subset_temp:=get_hier_subset(p_parent_child,p_parent_level(j),p_child_level(i));
2349 if l_pc_subset_temp.count>0 then
2350 merge_hier(l_pc_subset,l_pc_subset_temp);
2351 end if;
2352 end loop;
2353 end loop;
2354 return l_pc_subset;
2355 Exception when others then
2356 log_n('Exception in get_hier_subset '||sqlerrm);
2357 raise;
2358 End;
2359
2360 /*merges the entries from p_pc_subset_merge into p_pc_subset */
2361 procedure merge_hier(p_pc_subset in out nocopy dim_parent_child_tb,p_pc_subset_merge dim_parent_child_tb) is
2362 l_pc_subset dim_parent_child_tb;
2363 flag boolean;
2364 Begin
2365 for i in 1..p_pc_subset_merge.count loop
2366 flag:=false;
2367 for j in 1..p_pc_subset.count loop
2368 if nvl(p_pc_subset(j).parent_level,'^')=nvl(p_pc_subset_merge(i).parent_level,'^')
2369 and nvl(p_pc_subset(j).child_level,'^')=nvl(p_pc_subset_merge(i).child_level,'^')
2370 and nvl(p_pc_subset(j).parent_pk,'^')=nvl(p_pc_subset_merge(i).parent_pk,'^')
2371 and nvl(p_pc_subset(j).child_fk,'^')=nvl(p_pc_subset_merge(i).child_fk,'^') then
2372 flag:=true;
2373 exit;
2374 end if;
2375 end loop;
2376 if flag=false then
2377 l_pc_subset(l_pc_subset.count+1):=p_pc_subset_merge(i);
2378 end if;
2379 end loop;
2380 for i in 1..l_pc_subset.count loop
2381 p_pc_subset(p_pc_subset.count+1):=l_pc_subset(i);
2382 end loop;
2383 Exception when others then
2384 log_n('Exception in merge_hier '||sqlerrm);
2385 raise;
2386 End;
2387
2388 /*given a parent child hier and the parent and child level, tries to create a subset hier. if child does not roll to the parent, return table
2389 is empty. go from child to parent*/
2390 function get_hier_subset(p_parent_child dim_parent_child_tb,p_parent_level varchar2,p_child_level varchar2) return dim_parent_child_tb is
2391 l_pc_subset dim_parent_child_tb;
2392 Begin
2393 check_parent(p_parent_child,p_child_level,p_parent_level,l_pc_subset);
2394 return l_pc_subset;
2395 Exception when others then
2396 log_n('Exception in get_hier_subset '||sqlerrm);
2400 procedure check_parent(
2397 raise;
2398 End;
2399
2401 p_parent_child dim_parent_child_tb,
2402 p_child_level varchar2,
2403 p_check_level varchar2,
2404 p_pc_subset out nocopy dim_parent_child_tb
2405 ) is
2406 --
2407 l_pc_subset dim_parent_child_tb;
2408 Begin
2409 for i in 1..p_parent_child.count loop
2410 if p_parent_child(i).child_level=p_child_level and p_parent_child(i).parent_level is not null then
2411 if p_parent_child(i).parent_level=p_check_level then
2412 p_pc_subset(p_pc_subset.count+1):=p_parent_child(i);
2413 exit;
2414 else
2415 check_parent(p_parent_child,p_parent_child(i).parent_level,p_check_level,l_pc_subset);
2416 if l_pc_subset.count>0 then
2417 for j in 1..l_pc_subset.count loop
2418 p_pc_subset(p_pc_subset.count+1):=l_pc_subset(j);
2419 end loop;
2420 p_pc_subset(p_pc_subset.count+1):=p_parent_child(i);
2421 exit;
2422 end if;
2423 end if;
2424 end if;
2425 end loop;
2426 Exception when others then
2427 log_n('Exception in check_parent '||sqlerrm);
2428 raise;
2429 End;
2430
2431 procedure set_dim_recursive(p_dimension in out nocopy dimension_r) is
2432 Begin
2433 bsc_aw_bsc_metadata.set_dim_recursive(p_dimension);
2434 if p_dimension.recursive is null or p_dimension.recursive='N' then --do one more check
2435 if p_dimension.level_groups(1).parent_child.count=1
2436 and p_dimension.level_groups(1).parent_child(1).parent_level=p_dimension.level_groups(1).parent_child(1).child_level then
2437 p_dimension.recursive:='Y';
2438 p_dimension.recursive_norm_hier:='Y';
2439 end if;
2440 end if;
2441 if g_debug then
2442 if p_dimension.recursive='Y' then
2443 log('Dimension '||p_dimension.dim_name||' is recursive');
2444 end if;
2445 end if;
2446 Exception when others then
2447 log_n('Exception in set_dim_recursive '||sqlerrm);
2448 raise;
2449 End;
2450
2451 /*if any level is view based, return Y*/
2452 function check_dim_view_based(p_dim varchar2) return varchar2 is
2453 l_oo bsc_aw_md_wrapper.bsc_olap_object_tb;
2454 Begin
2455 bsc_aw_md_api.get_bsc_olap_object(null,'dimension level',p_dim,'dimension',l_oo);
2456 for i in 1..l_oo.count loop
2457 if bsc_aw_utility.get_parameter_value(l_oo(i).property1,'level source',',')='view' then
2458 return 'Y';
2459 end if;
2460 end loop;
2461 return 'N';
2462 Exception when others then
2463 log_n('Exception in check_dim_view_based '||sqlerrm);
2464 raise;
2465 End;
2466
2467 procedure upgrade(p_new_version number,p_old_version number) is
2468 l_action bsc_aw_utility.boolean_table;
2469 Begin
2470 init_all;
2471 if g_debug then
2472 log('Dim upgrade New='||p_new_version||', Old='||p_old_version||bsc_aw_utility.get_time);
2473 end if;
2474 if p_new_version>p_old_version then
2475 if p_old_version<2 then
2476 /*upgrade to handle 5064802 */
2477 bsc_aw_load_dim.upgrade_load_sync_all_dim;
2478 end if;
2479 end if;
2480 Exception when others then
2481 log_n('Exception in upgrade '||sqlerrm);
2482 raise;
2483 End;
2484
2485 -------------------------
2486 procedure init_all is
2487 Begin
2488 g_debug:=bsc_aw_utility.g_debug;
2489 null;
2490 Exception when others then
2491 log_n('Exception in init_all '||sqlerrm);
2492 raise;
2493 End;
2494
2495 procedure log(p_message varchar2) is
2496 Begin
2497 bsc_aw_utility.log(p_message);
2498 Exception when others then
2499 null;
2500 End;
2501
2502 procedure log_n(p_message varchar2) is
2503 Begin
2504 log(' ');
2505 log(p_message);
2506 Exception when others then
2507 null;
2508 End;
2509
2510 END BSC_AW_ADAPTER_DIM;