12.6 Collection Functions

Oracle Database 10g supplies a number of functions that are useful when working with nested table collections. For example, if you are interested in the number of elements in a given collection, you can use the CARDINALITY function:

SELECT co.order_nbr, co.cust_nbr, co.order_dt,

  CARDINALITY(co.order_items) number_of_items
FROM cust_order_c co; ORDER_NBR CUST_NBR ORDER_DT NUMBER_OF_ITEMS ---------- ---------- --------- --------------- 1000 9568 21-MAR-01 3

Compare this with the following query, which obtains the same results without the benefit of the CARDINALITY function:

SELECT co.order_nbr, co.cust_nbr, co.order_dt,

  COUNT(*) number_of_items

FROM cust_order_c co, TABLE(co.order_items) oi

GROUP BY co.order_nbr, co.cust_nbr, co.order_dt;



 ORDER_NBR   CUST_NBR ORDER_DT  NUMBER_OF_ITEMS

---------- ---------- --------- ---------------

      1000       9568 21-MAR-01               3

If you would like to perform set operations on multiple collections, there are functions that perform the equivalent of UNION, UNION ALL, MINUS, and INTERSECT. To illustrate these functions, we will add another row to the cust_order_c table and then perform set operations against the two rows in the table:

INSERT INTO cust_order_c (order_nbr, cust_nbr, sales_emp_id,

  order_dt, sale_price, order_items)

VALUES (1001, 9679, 275, TO_DATE('15-DEC-2003','DD-MON-YYYY'), 8645, 

  line_item_tbl(

    line_item_obj('A675-015', 25),

    line_item_obj('TX-475-A2', 7)));

Here's a look at our two sets of line items:

ORDER_ITEMS(PART_NBR, QUANTITY)

-----------------------------------------------------------------------

LINE_ITEM_TBL(LINE_ITEM_OBJ('A675-015', 25), 

              LINE_ITEM_OBJ('GX5-2786-A2', 1), 

              LINE_ITEM_OBJ('X378-9JT-2', 3))



LINE_ITEM_TBL(LINE_ITEM_OBJ('A675-015', 25), 

              LINE_ITEM_OBJ('TX-475-A2', 7))

As you can see, the two sets of line items share one common element (quantity 25 of part number A675-015). The next query demonstrates how the MULTISET UNION DISTINCT function can be used to build a new instance of line_item_tbl with the distinct set of line items:

SELECT co_1.order_items 

  MULTISET UNION DISTINCT

  co_2.order_items distinct_items

FROM cust_order_c co_1, cust_order_c co_2

WHERE co_1.order_nbr = 1000 and co_2.order_nbr = 1001;



DISTINCT_ITEMS(PART_NBR, QUANTITY)

--------------------------------------------------------------------------

LINE_ITEM_TBL(LINE_ITEM_OBJ('A675-015', 25), 

              LINE_ITEM_OBJ('GX5-2786-A2', 1), 

              LINE_ITEM_OBJ('X378-9JT-2', 3), 

              LINE_ITEM_OBJ('TX-475-A2', 7))

If you want the non-distinct union of line items from the two sets, simply replace the keyword DISTINCT with ALL:

SELECT co_1.order_items 

  MULTISET UNION ALL

  co_2.order_items all_items

FROM cust_order_c co_1, cust_order_c co_2

WHERE co_1.order_nbr = 1000 and co_2.order_nbr = 1001;



ALL_ITEMS(PART_NBR, QUANTITY)

--------------------------------------------------------------------------

LINE_ITEM_TBL(LINE_ITEM_OBJ('A675-015', 25), 

              LINE_ITEM_OBJ('GX5-2786-A2', 1), 

              LINE_ITEM_OBJ('X378-9JT-2', 3), 

              LINE_ITEM_OBJ('A675-015', 25), 

              LINE_ITEM_OBJ('TX-475-A2', 7))

As you would expect, the common line item now appears twice in the all_items collection.

If you want the functionality of the MINUS set operator, you can use the MULTISET EXCEPT function. The keyword EXCEPT is used rather than MINUS, to conform to the ANSI/ISO SQL standard:

SELECT co_1.order_items 

  MULTISET EXCEPT

  co_2.order_items diff_items

FROM cust_order_c co_1, cust_order_c co_2

WHERE co_1.order_nbr = 1000 and co_2.order_nbr = 1001;



DIFF_ITEMS(PART_NBR, QUANTITY)

--------------------------------------------------------------------------

LINE_ITEM_TBL(LINE_ITEM_OBJ('GX5-2786-A2', 1), 

              LINE_ITEM_OBJ('X378-9JT-2', 3))

Finally, if you desire to generate the intersection between the two sets, you can use the MULTISET INTERSECT function:

SELECT co_1.order_items 

  MULTISET INTERSECT

  co_2.order_items common_items

FROM cust_order_c co_1, cust_order_c co_2

WHERE co_1.order_nbr = 1000 and co_2.order_nbr = 1001;



COMMON_ITEMS(PART_NBR,



 QUANTITY)

--------------------------------------------------------------------------

LINE_ITEM_TBL(LINE_ITEM_OBJ('A675-015', 25))