I’ve recently made an embarassing discovery:
Yes. In all of my professional work with PL/SQL (and that has been quite a bit, in the banking industry), I have never really used a WHILE
loop – at least not that I recall. The idea of a WHILE
loop is simple, and it is available in most languages, like PL/SQL:
WHILE condition LOOP {...statements...} END LOOP;
Or Java:
while (condition) statement
So, why have I simply never used it?
Most loops iterate on collections
In hindsight, it’s crazy to think that it took Java until version 5 to introduce the foreach loop:
String[] strings = { "a", "b", "c" }; for (String s : strings) System.out.println(s);
It is some of Java’s most useful syntax sugar for the equivalent loop that uses a local loop variable that we simply don’t care about:
String[] strings = { "a", "b", "c" }; for (int i = 0; i < strings.length; i++) System.out.println(strings[i]);
Let’s be honest. When do we really want this loop variable? Hardly ever. Sometimes, we need to access the next string along with the current one, and we want to stick to the imperative paradigm for some reason (when we could do it more easily with functional programming APIs). But that’s it. Most loops simply iterate the entire collection in a very dumb and straightforward way.
SQL is all about collections
In SQL, everything is a table (see SQL trick #1 in this article), just like in relational algebra, everything is a set.
Now, PL/SQL is a useful procedural language that “builds around” the SQL language in the Oracle database. Some of the main reasons to do things in PL/SQL (rather than e.g. in Java) are:
- Performance (the most important reason), e.g. when doing ETL or reporting
- Logic needs to be “hidden” in the database (e.g. for security reasons)
- Logic needs to be reused among different systems that all access the database
Much like Java’s foreach loop, PL/SQL has the ability to define implicit cursors (as opposed to explicit ones)
As a PL/SQL developer, when I want to loop over a cursor, I have at least these options:
Explicit cursors
DECLARE -- The loop variable row all_objects%ROWTYPE; -- The cursor specification CURSOR c IS SELECT * FROM all_objects; BEGIN OPEN c; LOOP FETCH c INTO row; EXIT WHEN c%NOTFOUND; dbms_output.put_line(row.object_name); END LOOP; CLOSE c; END;
The above would correspond to the following boring Java code that we wrote time and again prior to Java 5 (in fact, without the generics):
Iterator<Row> c = ... // SELECT * FROM all_objects while (c.hasNext()) { Row row = c.next(); System.out.println(row.objectName); }
The while loop is absolutely boring to write. Just like with the loop variable, we really don’t care about the current state of the iterator. We want to iterate over the whole collection, and at each iteration, we don’t care where we’re currently at.
Note that in PL/SQL, it is common practice to use an infinite loop syntax and break out of the loop when the cursor is exhausted (see above). In Java, this would be the corresponding logic, which is even worse to write:
Iterator<Row> c = ... // SELECT * FROM all_objects for (;;) { if (!c.hasNext()) break; Row row = c.next(); System.out.println(row.objectName); }
Implicit cursors
Here’s how many PL/SQL developers do things most of the time:
BEGIN FOR row IN (SELECT * FROM all_objects) LOOP dbms_output.put_line(row.object_name); END LOOP; END;
The cursor is really an Iterable
in terms of Java collections. An Iterable
is a specification of what collection (Iterator
) will be produced when the control flow reaches the loop. I.e. a lazy collection.
It’s very natural to implement external iteration in the above way.
If you’re using jOOQ to write SQL in Java (and you should), you can apply the same pattern in Java as well, as jOOQ’s ResultQuery type extends Iterable
, which means it can be used as an Iterator
source in Java’s foreach loop:
for (AllObjectsRecord row : ctx.selectFrom(ALL_OBJECTS)) System.out.println(row.getObjectName());
Yes, that’s it! Focus on the business logic only, which is the collection specification (the query) and what you do with each row (the println statement). None of that cursor noise!
OK, but why no WHILE?
If you love SQL as much as me, you probably do that because you like the idea of having a declarative programming language to declare sets of data, just like SQL does. If you write client code in PL/SQL or Java, you will thus like to continue working on the entire data set and continue thinking in terms of sets. The imperative programming paradigm that operates on the intermediate object, the cursor, is not your paradigm. You don’t care about the cursor. You don’t want to manage it, you don’t want to open / close it. You don’t want to keep track of its state.
Thus, you will choose the implicit cursor loop, or the foreach loop in Java (or some Java 8 Stream functionality).
As you do that more often, you will run into less and less situations where the WHILE
loop is useful. Until you forget about its mere existence.
WHILE LOOP, you won’t be missed.
Filed under: sql Tagged: External iteration, iteration, LOOP, PL/SQL, sql, WHILE, WHILE LOOP Image may be NSFW.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
Clik here to view.
