• Tidak ada hasil yang ditemukan

Types of Cursor Loops

Dalam dokumen Book MySQL Stored Procedure Programming (Halaman 131-134)

We can use any of the three looping constructs (simple loop,WHILEloop, andREPEAT UNTILloop) to iterate through the rows returned by a cursor. In each case, we need to construct the loop so that the loop will terminate when the “last row variable” is set by theNOT FOUND handler.

Consider the cursor and theNOT FOUND handler shown in Example 5-9.

The simplest construct is theLOOP-LEAVE-END LOOPsequence. In this case, our cursor loop would look like that shown in Example 5-10.

The logic of Example 5-10 is simple: we open the cursor and then iteratively fetch the rows. If we try to fetch beyond the end of the result set, the handler setsno_more_

departmentsto 1 and we call theLEAVEstatement to terminate the loop. Finally, we close the cursor and reset theno_more_departments variable.

TheWHILEloop is very familiar to programmers and might therefore seem like a natu- ral choice for constructing a cursor loop. In fact, however, you will very likely find that the REPEAT UNTIL loop is a more appropriate construct for a cursor loop. The REPEAT always executes its body at least once before evaluating the continuation expression. In the context of cursor processing, we usually will want to fetch at least once before checking to see if we are done processing the cursor’s result set. Hence, using the REPEAT UNTIL loop can produce more readable code, as shown in Example 5-11.

Example 5-9. Cursor declaration with associated handler DECLARE dept_csr CURSOR FOR

SELECT department_id,department_name, location FROM departments;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_departments=1;

Example 5-10. A LOOP-LEAVE-END LOOP cursor loop OPEN dept_csr;

dept_loop1:LOOP

FETCH dept_csr INTO l_department_id,l_department_name,l_location;

IF no_more_departments=1 THEN LEAVE dept_loop1;

END IF;

SET l_department_count=l_department_count+1;

END LOOP;

CLOSE dept_csr;

SET no_more_departments=0;

However, this loop only works because we did nothing with each row fetched by the cursor. Fetching rows from a cursor just for the heck of it is very unusual—it is far more common to do something with the rows returned. For instance, in our first LOOP-LEAVE-END LOOPexample, we at least counted the rows returned by the cursor.

However, since the final fetch returns no rows, we need a way to avoid processing after that final fetch. So in fact, even if we use theREPEAT UNTILloop, we still need a LEAVE statement to avoid processing the nonexistent row returned (or rather, not returned) by the final fetch. Thus, if we want to count the number of rows returned by the cursor (or do anything else with the results) we will need to include loop labels and a LEAVE statement, as in the amended version of our previous example, shown in Example 5-12.

Example 5-11. Cursor loop with REPEAT UNTIL loop DECLARE dept_csr CURSOR FOR

SELECT department_id,department_name, location FROM departments;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_departments=1;

SET no_more_departments=0;

OPEN dept_csr;

REPEAT

FETCH dept_csr INTO l_department_id,l_department_name,l_location;

UNTIL no_more_departments END REPEAT;

CLOSE dept_csr;

SET no_more_departments=0;

Example 5-12. Most REPEAT UNTIL loops also need a LEAVE statement DECLARE dept_csr CURSOR FOR

SELECT department_id,department_name, location FROM departments;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_departments=1;

SET no_more_departments=0;

OPEN dept_csr;

dept_loop:REPEAT

FETCH dept_csr INTO l_department_id,l_department_name,l_location;

IF no_more_departments THEN LEAVE dept_loop;

END IF;

SET l_department_count=l_department_count+1;

UNTIL no_more_departments END REPEAT dept_loop;

CLOSE dept_csr;

SET no_more_departments=0;

The necessity of including a LEAVE statement in almost every REPEAT UNTIL loop makes the presence of the UNTIL clause redundant—although it arguably improves readability and protects you against the possibility of an infinite loop if your LEAVE statement fails to execute (perhaps you miscoded the IFclause). In the end, valid cursor loops can be established in either fashion, and there is no compelling case to recommend one style over the other. All we can say is that your code as a whole will be more readable if you use a consistent style for all of your cursor loops.

An alternative to aLEAVEstatement would be anIFstatement that executes whatever post-processing occurs once we determine that theFETCH has reached the end of the result set. Example 5-13 shows how we could construct this loop for our example. In this case, anIFstatement is added that performs row processing only if theno_more_

departments variable has not been set.

The third style of cursor loop involves theWHILE-END WHILE loop.WHILEevaluates its condition before the first execution of the loop, so it is a less logical choice than REPEAT-UNTILorLOOP-END LOOP, since logically we cannot know if we have reached the end of the cursor until we have fetched at least one row. On the other hand,WHILEis probably the looping construct used in the widest variety of other programming lan- guages, so it might confer a clearer understanding of the program’s intentions to those who are not familiar with the MySQL stored program language.

In any case, theWHILEloop also requires aLEAVEstatement if there is any processing of the cursor results attempted within the loop, so the code in Example 5-14 looks very similar to our previous examples.

Example 5-13. Using an IF block as an alternative to a LEAVE statement in a REPEAT UNTIL cursor loop

DECLARE dept_csr CURSOR FOR

SELECT department_id,department_name, location FROM departments;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET no_more_departments=1;

SET no_more_departments=0;

OPEN dept_csr;

dept_loop:REPEAT

FETCH dept_csr INTO l_department_id,l_department_name,l_location;

IF no_more_departments=0 THEN

SET l_department_count=l_department_count+1;

END IF;

UNTIL no_more_departments END REPEAT dept_loop;

CLOSE dept_csr;

SET no_more_departments=0;

Dalam dokumen Book MySQL Stored Procedure Programming (Halaman 131-134)