Database Programming With PL/SQL: Introduction To Explicit Cursors
Database Programming With PL/SQL: Introduction To Explicit Cursors
Declared by the programmer for queries that return more than one row
Disables a cursor, releases the context area, and undefines the active
set
Defined automatically by Oracle for all SQL DML statements, and for
SELECT statements that return only one row
Statement that retrieves the current row and advances the cursor to
the next row either until there are no more rows or until a specified
condition is met
Try It / Solve It
1. In your own words, explain the difference between implicit and explicit cursors.
2. Which SQL statement can use either an explicit or an implicit cursor, as needed?
3. List two circumstances in which you would use an explicit cursor.
A. Write a PL/SQL block to declare a cursor called currencies_cur. The cursor will be
used to read and display all rows from the CURRENCIES table. You will need to
retrieve currency_code and currency_name, ordered by ascending currency_name.
B. Add a statement to open the currencies_cur cursor.
C. Add variable declarations and an executable statement to read ONE row through the
currencies_cur cursor into local variables.
D. Add a statement to display the fetched row, and a statement to close the currencies_cur
cursor.
E. Run your block to confirm that it works. It should display: AFA Afghani.
F. Your code so far displays only one row. Modify your code so that it fetches and displays
all the rows, using a LOOP and EXIT statement. Test your modified block. It should fetch
and display each row in the CURRENCIES table. If it doesn't, check that your EXIT
statement is in the correct place in the code.
G. Write and test a PL/SQL block to read and display all the rows in the COUNTRIES table
for all countries in region 5 (South America region). For each selected country, display
the country_name, national_holiday_date, and national_holiday_name. Display only
those countries having a national holiday date that is not null. Save your code (you will
need it in the next practice).
6. Write a PL/SQL block to read and display the names of world regions, with a count
of the number of countries in each region. Include only those regions having at least
10 countries. Order your output by ascending region name.
Database Programming with PL/SQL
Try It / Solve It
1. Describe two benefits of using a cursor FOR loop.
2. Modify the following PL/SQL block so that it uses a cursor FOR loop. Keep the explicit
cursor declaration in the DECLARE section. Test your changes.
DECLARE
CURSOR countries_cur IS
SELECT country_name, national_holiday_name, national_holiday_date
FROM countries
WHERE region_id = 5;
countries_rec countries_cur%ROWTYPE;
BEGIN
OPEN countries_cur;
LOOP
FETCH countries_cur INTO
countries_rec; EXIT WHEN
countries_cur%NOTFOUND;
DBMS_OUTPUT.PUT_LINE ('Country: ' || countries_rec.country_name
|| ' National holiday: '|| countries_rec.national_holiday_name
|| ', held on: '|| countries_rec.national_holiday_date);
END LOOP;
CLOSE countries_cur;
END;
3. Modify your answer to question 2 to declare the cursor using a subquery in the FOR…LOOP
statement, rather than in the declaration section. Test your changes again.
4. Using the COUNTRIES table, write a cursor that returns countries with a highest_elevation
greater than 8,000 m. For each country, display the country_name, highest_elevation, and
climate. Use a cursor FOR loop, declaring the cursor using a subquery in the FOR…LOOP
statement.
5. This question uses a join of the SPOKEN_LANGUAGES and COUNTRIES tables with a
GROUP BY and HAVING clause.
Write a PL/SQL block to fetch and display all the countries that have more than six spoken
languages. For each such country, display country_name and the number of spoken
languages. Use a cursor FOR loop, but declare the cursor explicitly in the DECLARE
section. After all the rows have been fetched and displayed, display an extra row showing
the total number of countries having more than six languages. (Hint: Declare a variable to
hold the value of %ROWCOUNT.)
6. Why did your block in question 4 need to declare the cursor explicitly, instead of declaring it
as a subquery in the FOR…LOOP statement?
Database Programming with PL/SQL
Try It / Solve It
1. Describe the benefit of using one or more parameters with a cursor.
2. Write a PL/SQL block to display the country name and the area of each country in a chosen
region. The region_id should be passed to the cursor as a parameter. Test your block using
two region_ids: 5 (South America) and 30 (Eastern Asia). Do not use a cursor FOR loop.
3. Modify your answer to question 2 to use a cursor FOR loop. You must still declare the
cursor explicitly in the DECLARE section. Test it again using regions 5 and 30.
4. Modify your answer to question 3 to display the country_name and area of each country in a
chosen region that has an area greater than a specific value. The region_id and specific
area should be passed to the cursor as two parameters. Test your block twice using
region_id 5 (South America): the first time with area = 200000 and the second time with
area = 1000000.
5. Modify your answer to question 4 to fetch and display two sets of countries in a
single execution of the block. You should open and close the cursor twice, passing
different parameter values to it each time. Before each set of output rows, display
the message “Region: <region_id> Minimum Area: <area>”., for example “Region: 5
Minimum Area: 200000”. Test your changes using (5, 200000) and (30, 500000).
Database Programming with PL/SQL
5-5: Using Cursors FOR UPDATE – Lesson 4
Practice Activities
Try It / Solve It
In this Practice you will INSERT and later UPDATE rows in a new table: PROPOSED_RAISES,
which will store details of salary increases proposed for suitable employees. Create this table by
executing the following SQL statement:
NUMBER(8,2)); 2
1. Write a PL/SQL block that inserts a row into PROPOSED_RAISES for each eligible
employee. The eligible employees are those whose salary is below a chosen value. The
salary value is passed as a parameter to the cursor. For each eligible employee, insert a
row into PROPOSED_RAISES with date_proposed = today’s date, date_appoved null, and
proposed_new_salary 5% greater than the current salary. The cursor should LOCK the
employees rows so that no one can modify the employee data while the cursor is open. Test
your code using a chosen salary value of 5000.
2. SELECT from the PROPOSED_RAISES table to see the results of your INSERT
statements. There should be 15 rows. If you run your block in question 1 more than once,
make sure the PROPOSED_RAISES table is empty before each test.
SELECT * FROM proposed_raises;
3. Imagine these proposed salary increases have been approved by company management.
A. Write and execute a PL/SQL block to read each row from the PROPOSED_RAISES
table. For each row, UPDATE the date_approved column with today’s date. Use the
WHERE CURRENT OF... syntax to UPDATE each row. After running your code,
SELECT from the PROPOSED_RAISES table to view the updated data.
B. Management has now decided that employees in department 50 cannot have a
salary increase after all. Modify your code from question 3 to DELETE employees in
department 50 from PROPOSED_RAISES. This could be done by a simple DML
statement (DELETE FROM proposed_raises WHERE department_id = 50;), but we
want to do it using a FOR UPDATE cursor. Test your code, and view the
PROPOSED_RAISES table again to check that the rows have been deleted.
4. Since Oracle Academy's Application Express automatically commits changes, complete the
following activity as if you were issuing the commands in an installed/local environment with
the ability to use COMMIT and ROLLBACK. The indicated errors and pauses will not
actually happen in the Oracle Academy's online Application Express.
We are going to set up two sessions into the same schema. From one of the sessions we
will manually update an employee row NOT COMMITING. From the other session we will try
to update everyone’s salary, again NOT COMMITING. You should see the difference
between NOWAIT and WAIT when using FOR UPDATE.
In preparation, create a copy of the employees table by executing the following SQL
statement. You should use the UPD_EMPS table for the rest of this exercise.
A. Open a second session in a new browser window and connect to your schema.
B. In your first session, update employee_id 200 (Jennifer Whalen) so the stored first
name is Jenny. DO NOT COMMIT. You now have a lock on row 200 that will last
indefinitely.
C. In your second session, write a PL/SQL block to give every employee in UPD_EMPS
a $1 salary raise. Your cursor should be declared FOR UPDATE NOWAIT. Execute
your code. What happens?
D. Still in your second session, modify your block to remove the NOWAIT attribute from
the cursor declaration. Re-execute the block. What happens this time?
E. After waiting a minute or so, switch to your first session and COMMIT the update to
Jennifer Whalen’s row. Then switch back to your second session. What happened?
1. Write and run a PL/SQL block which produces a listing of departments and their employees.
Use the DEPARTMENTS and EMPLOYEES tables. In a cursor FOR loop, retrieve and
display the department_id and department_name for each department, and display a
second line containing '-
---------' as a separator. In a nested cursor FOR loop, retrieve and display the first_name,
last_name, and salary of each employee in that department, followed by a blank line at the
end of each department. Order the departments by department_id, and the employees in
each department by last_name.
You will need to declare two cursors, one to fetch and display the departments, the second
to fetch and display the employees in that department, passing the department_id as a
parameter. Your output should look something like this (only the first few departments are
shown): 10 Administration
-----------------------------
Jennifer Whalen 4400
20 Marketing
-----------------------------
Pat Fay 6000
Michael Hartstein 13000
50 Shipping
-----------------------------
Curtis Davies 3400
Randall Matos 2600
Kevin Mourgos 5800
Trenna Rajs 3500
Peter Vargas 2500
2. Write and run a PL/SQL block which produces a report listing world regions, countries in
those regions, and the land area and population for each country.
You will need two cursors: an outer loop cursor which fetches and displays rows from the
REGIONS table, and an inner loop cursor which fetches and displays rows from the
COUNTRIES table for countries in that region, passing the region_id as a parameter.
Restrict your regions to those in the Americas (region_name like ‘%America%’). Order your
output by region_name, and by country_name within each region.
Your output should look something like this (only the first two regions are shown):
13 Central America
-----------------------------
Belize 22966 287730
Republic of Costa Rica 51100 4075261
Republic of El Salvador 21040 6822378
Republic of Guatemala 108890 12293545
Republic of Honduras 112090 7326496
Republic of Nicaragua 129494 5570129
Republic of Panama 78200 3191319
United Mexican States 1972550 107449525
21 North America
-----------------------------
Bermuda 53 65773
Canada 9984670 33098932
Greenland 2166086 56361
Territorial Collectivity of Saint Pierre and Miquelon 242 7026
United States of America 9631420 298444215
3. Modify your block from question 2 to display the names of official spoken languages in each
country. You will need three cursors and three loops. The first two cursors should fetch and
display regions and countries, as in question 2. The innermost loop should accept a
country_id as a parameter, and fetch and display the name of each official language, using
a join of the SPOKEN_LANGUAGES table and the LANGUAGES table.
Within each country, the languages should be ordered by language_name. Test your block,
restricting regions to those in the Americas.
Your output should look something like this (only the first two regions are shown):
13 Central America
-----------------------------
Belize 22966 287730
--- English
Republic of Costa Rica 51100 4075261
--- Spanish
Republic of El Salvador 21040 6822378
Republic of Guatemala 108890 12293545
Republic of Honduras 112090 7326496
Republic of Nicaragua 129494 5570129
--- Spanish
Republic of Panama 78200 3191319
--- Spanish
United Mexican States 1972550 107449525
21 North America
-----------------------------
Bermuda 53 65773
--- English
Canada 9984670 33098932
--- English
--- French
Greenland 2166086 56361
Territorial Collectivity of Saint Pierre and Miquelon 242 7026
--- French
United States of America 9631420 298444215
--- English