Reputation: 1062
I'm building nested tree and I need to get data for the next row in cursor, using Oracle. And I still need current row, so looping forward is not a solution. Example:
OPEN emp_cv FOR sql_stmt;
LOOP
FETCH emp_cv INTO v_rcod,v_rname,v_level;
EXIT WHEN emp_cv%NOTFOUND;
/*here lies the code for getting v_next_level*/
if v_next_level > v_level then
/*code here*/
elsif v_next_level < v_level then
/*code here*/
else
/*code here*/
end if;
END LOOP;
CLOSE emp_cv;
Upvotes: 8
Views: 17399
Reputation: 1062
I did it this way. I'm building a tree in a step backwards. I have to check for the first iteration.
OPEN emp_cv FOR sql_stmt;
LOOP
if emp_cv%notfound then
/*some code*/
exit;
end if;
FETCH emp_cv INTO v_new_level;
if not b_first_time then
if v_new_level > v_level then
/*some code*/
elsif v_new_level < v_level then
/*some code*/
else
/*code*/
end if;
else
b_first_time:=false;
end if;
v_level:=v_new_level;
END LOOP;
CLOSE emp_cv;
Upvotes: 3
Reputation: 6866
Use LEAD and LAG Functions
LEAD has the ability to compute an expression on the next rows (rows which are going to come after the current row) and return the value to the current row. The general syntax of LEAD is shown below:
LEAD (sql_expr, offset, default) OVER (analytic_clause)
sql_expr is the expression to compute from the leading row.
offset is the index of the leading row relative to the current row.offset is a positive integer with default 1.
default is the value to return if the points to a row outside the partition range.
The syntax of LAG is similar except that the offset for LAG goes into the previous rows.
SELECT deptno, empno, sal,
LEAD(sal, 1, 0) OVER (PARTITION BY dept ORDER BY sal DESC) NEXT_LOW_SAL,
LAG(sal, 1, 0) OVER (PARTITION BY dept ORDER BY sal DESC) PREV_HIGH_SAL
FROM emp
WHERE deptno IN (10, 20)
ORDER BY deptno, sal DESC;
DEPTNO EMPNO SAL NEXT_LOWER_SAL PREV_HIGHER_SAL
------- ------ ----- -------------- ---------------
10 7839 5000 2450 0
10 7782 2450 1300 5000
10 7934 1300 0 2450
20 7788 3000 3000 0
20 7902 3000 2975 3000
20 7566 2975 1100 3000
20 7876 1100 800 2975
20 7369 800 0 1100
8 rows selected.
Upvotes: 20
Reputation: 41075
would it be better to store the previous level and use that. something along the lines of
/* set to a value lesser than the lowest value possible for level
am assuming 0 is the lowest value possible */
v_previous_level := -1;
OPEN emp_cv FOR sql_stmt;
LOOP
FETCH emp_cv INTO v_rcod,v_rname,v_level;
EXIT WHEN emp_cv%NOTFOUND;
/* you'd probably have to update v_previous_level in one of
these conditions (depends on your logic) */
if v_previous_level > v_level then
/*code here*/
elsif v_previous_level < v_level then
/*code here*/
else
/*code here*/
end if;
END LOOP;
CLOSE emp_cv;
Upvotes: 2