Querying object views
x, September 13, 2001 - 8:53 pm UTC
Thanks a lot for a speedy response....
I needed it badly...
Thanks again
Need another example
Tommy W., December 23, 2003 - 12:26 pm UTC
I have the following tables with a one to many relationship between
c_hdr_common_t and c_li_exc_t.
SQL> desc msdss.c_hdr_common_t
Name Null? Type
----------------------------------------- -------- ------------
C_HDR_PD_DT NOT NULL DATE
B_SYS_ID NOT NULL NUMBER(9)
C_TCN_NUM NOT NULL CHAR(17)
C_TOT_REIMB_AMT NUMBER(11,2)
..................
SQL> desc msdss.c_li_exc_t
Name Null? Type
----------------------------------------- -------- -----------
C_HDR_PD_DT NOT NULL DATE
B_SYS_ID NOT NULL NUMBER(9)
C_TCN_NUM NOT NULL CHAR(17)
C_LI_NUM NOT NULL NUMBER(4)
R_CLM_EXC_CD NOT NULL CHAR(4)
..............
I want to be able to create an object view (or maybe something else) that will
allow me to return 1 occurence of c_hdr_common_t that matches a list of R_CLM_EXC_CD's.
such as:
SELECT a.B_SYS_ID,a.C_HDR_PD_DT,a.C_TCN_NUM,a.
FROM msdss.clm_hdr_view a
WHERE c_hdr_pd_dt = '22-DEC-2003'
AND R_CLM_EXC_CD IN ('0423','0230')
I have tried creating the object views below, but still can't get it to the point of returning
one occurence. Simply adding DISTINCT to the above query is not an option. I want to be able to use
this view to group by and sum on other data in c_hdr_common_t.
CREATE TYPE msdss.clm_exc_t AS OBJECT
(
R_CLM_EXC_CD CHAR(4)
);
CREATE TYPE msdss.clm_exc_list_t AS TABLE OF clm_exc_t;
CREATE TYPE msdss.clm_hdr_t AS OBJECT
( C_HDR_PD_DT DATE,
B_SYS_ID NUMBER(9),
C_TCN_NUM CHAR(17),
clm_exc_list clm_exc_list_t
);
CREATE VIEW msdss.clm_hdr_view OF clm_hdr_t WITH OBJECT IDENTIFIER (C_HDR_PD_DT,B_SYS_ID,C_TCN_NUM) AS
SELECT a.C_HDR_PD_DT,a.B_SYS_ID,a.C_TCN_NUM,
CAST( MULTISET (
SELECT DISTINCT(b.R_CLM_EXC_CD)
FROM msdss.c_li_exc_t b
WHERE a.C_HDR_PD_DT = b.C_HDR_PD_DT
AND a.B_SYS_ID = b.B_SYS_ID
AND a.C_TCN_NUM = b.C_TCN_NUM)
AS clm_exc_list_t)
AS clm_exc_list
FROM msdss.c_hdr_common_t a
thanks.
December 23, 2003 - 4:56 pm UTC
is the goal to get the records from the HDR table that have a set of children records which completely cover the "in list"??
is that the goal (rather then show me the proposed -- but not working -- solution, phrase the question with a little more detail -- tell us exactly what the desired output is and what the inputs are).
If you say "given 0423, 0230 -- i would like all of the HRD records that have a child record for each of those codes", we can do that.
example
Tommy W, December 24, 2003 - 9:45 am UTC
"If you say "given 0423, 0230 -- i would like all of the HRD records that have a child record for each of those codes"
That's what I'm looking for, but I need all the logic hidden in a view, so the join of the two tables appears to be flattened, and the criteria can be expressed as R_CLM_EXC_CD IN ('0423','0230')
Also, if the HRD has more than one child that matches the criteria, I only want to see one HDR.
ie.. it is possible that a HDR can have child records with values like (0423,0230,0423)
thanks
December 24, 2003 - 10:24 am UTC
you are trying to apply SET semantics (in) to a single row -- ain't going to work.
this is not something you can "hide in a view", not going to happen.
example
Tommy W., December 24, 2003 - 10:58 am UTC
Given that I need to be able to use ad-hoc reporting tools to query this data, and a view will not work, and I would prefer not to create a new table/materialized view, what would be your recommendation.
thanks
December 24, 2003 - 11:15 am UTC
this is NOT going to happen in a view. I don't know what to tell you. I don't know the capabilities of your tool.
The query is going to be:
select hdr.columns...
from hdr, dtl
where hdr.key = dtl.key
and dtl.column in ( 'a','b','c')
group by hdr.columns....
having count(*) = 3
for example of
select ....
from hdr
where key in ( select key from dtl where column in ( 'a','b' ) group by key having count(*) = 2 ) )
see how the INLIST changes.
see how the count(*) = changes.
this is not going to be a view. I can two step it like this:
create view v
as
select *
from hdr
where key in ( select key
from dtl
where column in ( select * from gtt )
group by key
having count(*) = (select count(*) from gtt) ) )
/
then the user must fill gtt (stands for global temporary table) with the values of interest before running the query against the view.
Another way would be to use Oracle text (believe it or not). Would the ad-hoc tools be able to use the CONTAINS operator?
example
Tommy W, December 24, 2003 - 11:44 am UTC
The adhoc tool is Business Objects. I'm not the Business Objects designer, but I believe you can define an object using any available sql.
December 24, 2003 - 1:28 pm UTC
sure, you can define an object -- but -- BO isn't going to query it nor will it be what you would term "fast" since your query is on what would be the nested table.
this is not going to happen in a view in any way that is
a) usable
b) performant
BO is going to need to not use a view, it'll query hdr and dtl and it'll be the query above.
sorry -- but I don't see any efficient or effective alternative here.
we can use text to index this and use the contains clause -- but your back to "bo is database independent, it isn't going to recognize most features provided by the database"
Same thing but using a Pl/SQl Table
Suleiman Akbar, December 25, 2003 - 11:35 am UTC
Tom,
It's nice to see ur replies everytime u answer to all IT nerds...pls. keep up the good work.
Request u to pls. have a look for my problem...
pls. find the problem enclosed beneath.
Question)
Declare
TYPE col1 Is Table of <tab.column_name> Index By Binary_Integer;
TYPE col2 Is Table of <tab.column_name> Index By Binary_Integer;
pCol1 col1;
pCol2 col2;
pCol3 col2;
Begin
Select <pk_col_name> Bulk Collect Into pCol1 From <tab1> Where <unq_key_col> = <value>;
Select <pk_col_name> Bulk Collect Into pCol2 From <tab2> Where <col_name> = <value>;
-- Would like to make u aware that pCol1 has 100 rows.
-- and pCol2 has only 4 rows.
-- I want to load remaining 96 rows into pCol3...
j := 1;
For i in 1..pCol1.Count Loop
If pCol1(i) <> pCol2(i) Then
pCol3(j) := pCol1;
j := j+1;
end If;
End Loop;
End;
-- But it's giving me some error...don't know what's wrong in this code... I should execute it but when I debug this with Pl/SQL developer, I have noticed that after comparing the 4 values of pCol2 it's returning it as NULL and it's going to a no_data_found exception again and again..
Tom request u to solve my query at the earliest...
Hope to see ur reply ASAP..
Suleiman khatib atavur
December 25, 2003 - 12:02 pm UTC
your logic is a bit "botched" there. you are using I as the index to both pcol1 and pcol2 -- but pcol1 has 100 entries whereas pcol2 has 4!
anyway, here are two approaches
ops$tkyte@ORA9IR2> create or replace procedure method_1
2 as
3 type array is table of number index by binary_integer;
4
5 l_col1 array;
6 l_col2 array;
7 l_col3 array;
8
9 function is_in( p_array in array, p_value in number ) return boolean
10 is
11 begin
12 for i in 1 .. p_array.count
13 loop
14 if ( p_array(i) = p_value )
15 then
16 return TRUE;
17 end if;
18 end loop;
19 return FALSE;
20 end is_in;
21 begin
22 select object_id bulk collect into l_col1 from all_objects where rownum <= 100;
23 select object_id bulk collect into l_col2 from all_objects where rownum <= 4;
24
25 for i in 1 .. l_col1.count
26 loop
27 if ( NOT is_in( l_col2, l_col1(i) ) )
28 then
29 l_col3(l_col3.count+1) := l_col1(i);
30 end if;
31 end loop;
32
33 dbms_output.put_line( 'added ' || l_col3.count || ' array entries' );
34 end;
35 /
Procedure created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace type myArrayType as table of number
2 /
Type created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> create or replace procedure method_2
2 as
3 l_col1 myarrayType;
4 l_col2 myarrayType;
5 l_col3 myarrayType;
6 begin
7 select object_id bulk collect into l_col1 from all_objects where rownum <= 100;
8 select object_id bulk collect into l_col2 from all_objects where rownum <= 4;
9
10 select * bulk collect into l_col3
11 from ( select * from TABLE( cast( l_col1 as myArrayType ) )
12 MINUS
13 select * from TABLE( cast( l_col2 as myArrayType ) )
14 );
15
16 dbms_output.put_line( 'added ' || l_col3.count || ' array entries' );
17 end;
18 /
Procedure created.
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> exec method_1
added 96 array entries
PL/SQL procedure successfully completed.
ops$tkyte@ORA9IR2> exec method_2
added 96 array entries
PL/SQL procedure successfully completed.