Method Description Array Varray Nest. Tbl
EXISTS(n) Returns TRUE if element 'n' No Yes[1],[2] Yes[1],[2]
exists, otherwise FALSE
COUNT Returns the current number of Yes[3] Yes[3] Yes[3]
elements in a collection
LIMIT Returns the maximum size of a Yes[5] Yes[4] Yes[5]
collection. Useful if one is
using a TYPE stored in the
Database, and one is not sure
what the limit for this Varray
may be.
FIRST Returns the first or last Yes[6] Yes[7] Yes[8]
LAST subscript value in a collection,
or NULL if the collection is empty.
PRIOR(sub) Returns the item whose subscript
NEXT(sub) is right before 'sub' (PRIOR) Yes[9] Yes[9] Yes[9]
or right after 'sub' (NEXT), or
NULL if there is no next or prior
element.
TRIM TRIM removes one element from No Yes[10] Yes[10]
TRIM(n) the (high) end of a collection.
TRIM(n) removes 'n' elements from
the end of a collection.
DELETE DELETE removes all elements Yes[10] Yes[10] Yes[10]
DELETE(n) a collection. DELETE(n) removes
DELETE(n,m) the element with subscript 'n' from
a collection. DELETE(n,m) deletes
element 'n' (low) through 'm' (high).
If 'm' is greater than 'n', nothing
is deleted, and no error is raised.
EXTEND Add a null element to the (high) No Yes[10] Yes{10]
EXTEND(n) end of the collection. EXTEND(n)
EXTEND(n,i) adds 'n' null elements to the end
of the collection. And EXTEND(n,i)
adds 'n' copies of the 'i-th' element.
--------------------------
[1] One way to skip around missing elements in a sparse nested table.
[2] Another way to avoid the SUBSCRIPT_OUTSIDE_LIMIT error.
[3] For Varrays, COUNT always equals LAST. With Nested Tables, if you TRIM
or DELETE an element, the COUNT is reduced accordingly. With Associative
Arrays, you don't even have to do a DELETE (since you can load an array up
sparsely). In other words, if you create an array V, and assign V(1), V(3),
V(5), the COUNT is 3.
[4] A Varray has an absolute maximum size, which is set by it's TYPE statement.
Thus, once a PL/SQL block starts executing, the value returned by LIMIT is known.
The number of elements actually in the Varray will often be less than this absolute
LIMIT, so COUNT will usually be less than LIMIT.
[5] But really only useful for Varrays, as Associative Arrays and Nested
tables always return NULL.
[6] If an Associative Array is indexed by a VARCHAR variable, what is first
and last depend on the character set and sort order. Since numeric
Associative Arrays can be entered with any subscript value, LAST can be
greater than COUNT, even if nothing has been deleted.
[7] For Varrays, FIRST always = 1 and LAST always = COUNT.
[8] For Nested Tables, FIRST can be greater than 1 if beginning elements are
deleted. If nothing has been deleted (in the middle) LAST = COUNT. If
something has been deleted, then LAST < COUNT
[9] As with FIRST and LAST, which of all the subscripts of the collection is
the previous or the subsequent may depend on the sort order of the character
set. For integer subscripts, there is no such dependency, but exactly what
subscripts are in the collection can cause some surprises. For example, if
one loads up a PL/SQL table with subscripts 2, 8, 3, 12, 15, 19, 1 (in that
order), then PRIOR(12) is the element whose subscript is 8, and not the
element whose subscript is 3.
[10] The TRIM, DELETE, and EXTEND methods are complicated, especially when
one uses them in tandem. A complete discussion of these is being defered to a
later posting.
Well, let's now look at some more of these methods, as applied to Associative Arrays. We are adding an additional complication to the requirements of the previous post: We only want the first value, the year-ending values, and the very last value. So, we do this the quick-and-dirty way: we take what we already have, and then go and delete what we no longer want.
If not very elegant, it does provide an excuse for using the DELETE method:
Listing-3
1 alter session set nls_date_format = 'yyyymmdd';
2
3 DECLARE
4 type amortTableLine is record (
5 ToInterest number(12,2),
6 ToPrincipal number(12,2),
7 EndingBalance number(12,2)
8 );
9 type amortTableType is table of amortTableLine
10 index by varchar2(9);
11
12 amortTable amortTabletype;
13
14 p_LoanAmount number(10,2);
15 p_InterestRate number;
16 p_loanTerm number(2,0);
17 p_effectiveDate date;
18 p_payment number(7,2);
19 v_pmtNumber number;
20
21 v_pmtDate date;
22 v_pmtDateIdx varchar2(9); /* Because we are using it as an index */
23 v_pmtDateJan varchar2(9); /* Lower range of dates we are going to*/
24 /* delete (typically, will be in January*/
25 v_pmtDateNov varchar2(9); /* November of the year of v_pmtDateJan*/
26 v_monthlyRate number;
27 v_totalInt number(13,2);
28 v_totalPmt number(13,2);
29 v_currentPrinc number(8,2);
30 BEGIN
31 p_LoanAmount := 100000;
32 p_InterestRate := 6.5;
33 p_loanTerm := 30;
34 p_effectiveDate := to_date('20090315','yyyymmdd');
35 p_payment := 632.07;
36 v_pmtDateIdx := to_char(add_months(p_effectiveDate,1)); /* Deliberately using the session's date mask */
37 v_monthlyRate := p_InterestRate / 1200;
38
39 amortTable(v_pmtDateIdx).ToInterest := p_LoanAmount * v_monthlyRate;
40 amortTable(v_pmtDateIdx).ToPrincipal := p_payment - amortTable(v_pmtDateIdx).ToInterest;
41 amortTable(v_pmtDateIdx).EndingBalance := p_LoanAmount - amortTable(v_pmtDateIdx).ToPrincipal;
42 v_totalInt := amortTable(v_pmtDateIdx).ToInterest;
43 v_totalPmt := p_payment;
44 v_pmtDate := add_months(p_effectiveDate,2);
45 v_pmtDateIdx := to_char(v_pmtDate);
46
47 WHILE (v_pmtDate < add_months(p_effectiveDate,p_loanTerm * 12)) LOOP
48 amortTable(v_pmtDateIdx).ToInterest := amortTable(amortTable.prior(v_pmtDateIdx)).EndingBalance * v_monthlyRate;
49 amortTable(v_pmtDateIdx).ToPrincipal := p_payment - amortTable(v_pmtDateIdx).ToInterest;
50 amortTable(v_pmtDateIdx).EndingBalance := amortTable(amortTable.prior(v_pmtDateIdx)).EndingBalance - amortTable(v_pmtDateIdx).ToPrincipal;
51 v_totalInt := v_totalInt + amortTable(v_pmtDateIdx).ToInterest;
52 v_totalPmt := v_totalPmt + p_payment;
53 v_pmtDate := add_months(v_pmtDate,1);
54 v_pmtDateIdx := to_char(v_pmtDate);
55 END LOOP;
56 amortTable(v_pmtDateIdx).ToInterest := amortTable(amortTable.prior(v_pmtDateIdx)).EndingBalance * v_monthlyRate;
57 amortTable(v_pmtDateIdx).ToPrincipal := amortTable(amortTable.prior(v_pmtDateIdx)).EndingBalance;
58 amortTable(v_pmtDateIdx).EndingBalance := 0;
59 v_totalInt := v_totalInt + amortTable(v_pmtDateIdx).ToInterest;
60 v_totalPmt := v_totalPmt + amortTable(v_pmtDateIdx).ToPrincipal + amortTable(v_pmtDateIdx).ToInterest;
61
62 /*Just to Illustrate the DELETE method, we will here delete */
63 /*Everything except the 1st line, the last line, and the */
64 /*end of the month. */
65 v_pmtDateJan := amortTable.next(amortTable.first);
66 v_pmtDateNov := substr(v_pmtDateJan,1,4)||'11'||substr(v_pmtDateJan,7,2);
67 WHILE (v_pmtDateNov <= amortTable.last) LOOP
68 amortTable.delete(v_pmtDateJan, v_pmtDateNov);
69 v_pmtDateJan := amortTable.next(amortTable.next(v_pmtDateNov));
70 v_pmtDateNov := substr(v_pmtDateJan,1,4)||'11'||substr(v_pmtDateJan,7,2);
71 END LOOP;
72 v_pmtDateNov := amortTable.prior(amortTable.last);
73 amortTable.delete(v_pmtDateJan, v_pmtDateNov);
74
75 v_pmtDateIdx := amortTable.first;
76 WHILE (v_pmtDateIdx <= amortTable.last) LOOP
77 dbms_output.put_line(v_pmtDateIdx||' '||
78 amortTable(v_pmtDateIdx).ToInterest||' '||
79 amortTable(v_pmtDateIdx).ToPrincipal||' '||
80 amortTable(v_pmtDateIdx).EndingBalance);
81 v_pmtDateIdx := amortTable.next(v_pmtDateIdx);
82 END LOOP;
83
84* END;
Lines 23-25: The plan is to use the DELETE(n,m) form of the delete function.
Since our index is a character string of the form 'yyyymmdd', 'n' will have
usually have the form 'yyyy01dd' (will be in January, except for the first set)
and 'm' will usually be of the form 'yyyy11dd' (will be in November) except
for the final year, where it could be any month.
Line 66: Here we start to have something different from the last posting. We
want to keep the first subscript, and start deleting from the second to the
end of the year.
Lines 68-72: We have set up our loop variables, and use them here.
Here is the output:
20090415 541.67 90.4 99909.6
20091215 537.67 94.4 99168.51
20101215 531.35 100.72 97995.06
20111215 524.61 107.46 96743.03
20121215 517.41 114.66 95407.15
20131215 509.73 122.34 93981.82
20141215 501.54 130.53 92461.03
20151215 492.8 139.27 90838.38
20161215 483.47 148.6 89107.05
20171215 473.52 158.55 87259.77
20181215 462.9 169.17 85288.79
20191215 451.57 180.5 83185.81
20201215 439.48 192.59 80941.99
20211215 426.58 205.49 78547.89
20221215 412.82 219.25 75993.44
20231215 398.14 233.93 73267.96
20241215 382.47 249.6 70359.91
20251215 365.75 266.32 67257.11
20261215 347.92 284.15 63946.51
20271215 328.89 303.18 60414.21
20281215 308.58 323.49 56645.32
20291215 286.92 345.15 52624.03
20301215 263.8 368.27 48333.43
20311215 239.14 392.93 43755.48
20321215 212.82 419.25 38870.92
20331215 184.74 447.33 33659.22
20341215 154.79 477.28 28098.51
20351215 122.82 509.25 22165.38
20361215 88.72 543.35 15834.9
20371215 52.33 579.74 9080.48
20381215 13.5 618.57 1873.67
20390315 3.39 626.46 0