Cursors
Cursors
Cursors
CURSORS
• Declaration
• Open and position the pointer on the first record
• Load the current line
• Close the cursor
In Oracle, the cursor is a pointer (identifier) towards the memory called context.
The implicit cursor is automatically created and managed by the system for a number of
commands (create, alter, insert, delete etc.).
The explicit cursor is automatically created and managed by the programmer, especially
for Select statements.
The cursor mechanism is the RDBMS solution for passing from dealing with data as a set
(table) to dealing with data at record level. The cursor is an area of internal memory in
which a set of tuples is brought and from which a record can be extracted for processing.
The cursor is based on a retrieval that is stored in the DB dictionary.
The attributes for the implicit cursor are:
• SQL%ROWCOUNT
• SQL%FOUND
• SQL%NOTFOUND
Examples:
Delete a row from Product_information table and count the number of rows deleted.
DECLARE
no NUMBER(2);
BEGIN
DELETE FROM product_information
WHERE product_id=3001;
no:=SQL%ROWCOUNT;
DBMS_OUTPUT.PUT_LINE (no || ' rows deleted');
COMMIT;
END;
Try to modify the name of the product 113. If the product doesn’t exist (the UPDATE
command doesn’t modify anything), display a message.
BEGIN
UPDATE product_information
SET product_name='PC'
WHERE product_id=113;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE('The product 113 doesn''t exist');
END IF;
END;
Delete a customer whose id is given by the user through a substitution variable.
ACCEPT var_id PROMPT 'Give an id for the customer:'
VARIABLE no varchar2(100)
DECLARE
BEGIN
DELETE FROM customers WHERE customer_id=&var_id; --211
:no:=TO_CHAR(SQL%ROWCOUNT)||' deleted rows';
END;
/
PRINT no
Rollback;
EXPLICIT CURSOR
▪ It is used for individually processing each line (record) that is loaded in the memory
by a SELECT statement.
▪ The set of rows returned by the SELECT query is called result set.
▪ The cursor keeps a pointer to the current line in a result set.
Verifying the state of an explicit cursor is made using the following attributes:
• cursor_name%ISOPEN - returns TRUE if the cursor is opened;
• cursor_name%NOTFOUND - returns TRUE if the most recent FETCH
didn’t return any row;
• cursor_name%FOUND – the complement of %NOTFOUND;
• cursor_name%ROWCOUNT – the number of rows returned up until the
current moment.
For a higher flexibility, cursors with parameters can be used. They send the values of the
actual parameters in SQL queries. The declaration of such a cursor is made like this:
Example: Display the products that have a total ordered quantity larger than a value
received as parameter.
DECLARE
CURSOR c_prod (p_val NUMBER) IS
select p.product_id prod, sum(quantity) total_quantity
from product_information p, order_items o
where p.product_id=o.product_id
group by p.product_id
HAVING sum(quantity)>p_val
ORDER BY total_quantity desc;
v_val NUMBER(5);
rec_prod c_prod%rowtype;
BEGIN
v_val:=50;
DBMS_OUTPUT.PUT_LINE('The products that have a total ordered quantity larger
than '|| v_val);
IF NOT c_prod%ISOPEN THEN
OPEN c_prod (v_val);
END IF;
LOOP
FETCH c_prod into rec_prod;
EXIT WHEN c_prod%notfound;
DBMS_OUTPUT.PUT_LINE(rec_prod.total_quantity||' pieces of product
'||rec_prod.prod||' were ordered');
END LOOP;
CLOSE c_prod;
END;
OPTIONAL
FOR UPDATE clause
▪ FOR UPDATE clause is added in the query associated with the cursor in order to
block the affected rows when the cursor is opened.
Example: For Orders table update the order_date by decreasing it by one week. Use FOR
UPDATE and WHERE CURRENT OF clauses.
DECLARE
CURSOR c_update IS
SELECT *
FROM orders
FOR UPDATE OF order_date NOWAIT;
BEGIN
FOR rec IN c_update LOOP
DBMS_OUTPUT.PUT_LINE('The order '||rec.order_id||' has the date:
'||rec.order_date);
UPDATE orders
SET order_date=order_date-7
WHERE CURRENT OF c_update;
DBMS_OUTPUT.PUT_LINE('The order '||rec.order_id||' has the date:
'||rec.order_date);
END LOOP;
END;
/
Homework:
1. Display all the customers and their orders. Use a cursor to load the customer’s name
and another cursor with parameter to load their orders.
declare
cursor c1 is select * from customers;
cursor c2 (cust_id number) is select order_id from orders where
customer_id=cust_id;
begin
for rec in c1 loop
dbms_output.put_line('The customer '||rec.cust_first_name||' '||rec.cust_last_name||'
has the following orders:');
for var in c2(rec.customer_id) loop
dbms_output.put_line(var.order_id);
end loop;
end loop;
end;
2. Display the orders that have the largest value. Stop after the first 5 orders.
declare
cursor c is
select o.order_id o_id, sum(quantity*unit_price) val from orders o, order_items i
where i.order_id=o.order_id group by o.order_id order by 2 desc;
type order_rec is record (id_o orders.order_id%type, val number);
ord order_rec;
begin
open c;
loop
fetch c into ord;
dbms_output.put_line('The order '||ord.id_o||' has the value: '||ord.val);
exit when c%notfound or c%rowcount=5;
end loop;
close c;
end;