tag:blogger.com,1999:blog-6230959840389481677.post-29080386266799535202008-03-28T13:31:00.000-07:002008-04-01T14:29:28.602-07:00Más control sobre los LOOPS en 11gEn PL/SQL podemos salir de un LOOP con la cláusula EXIT. Típicamente la usamos para la condición de salida de un loop:<pre><span style="color: rgb(0, 153, 0);"> BEGIN</span><br /><span style="color: rgb(0, 153, 0);"> LOOP</span><br /><span style="color: rgb(0, 153, 0);"> ... </span><br /><span style="color: rgb(0, 153, 0);"> <span style="color: rgb(51, 51, 255);">EXIT</span> WHEN </span><span style="font-style: italic; color: rgb(0, 153, 0);">condición</span><span style="color: rgb(0, 153, 0);"> ;</span><br /><span style="color: rgb(0, 153, 0);"> END LOOP;</span><br /><span style="color: rgb(0, 153, 0);"> -- el </span><span style="font-style: italic; color: rgb(0, 153, 0);">control sigue aquí</span><br /><span style="color: rgb(0, 153, 0);"> ...</span><br /><span style="color: rgb(0, 153, 0);"> END;</span></pre>Ahora la versión 11g agrega un nivel intermedio: CONTINUE. Con esta sentencia, podemos cancelar la iteración del loop actual y pasar a la siguiente, sin abortar el loop. Puede usarse simplemente <span style="color: rgb(51, 51, 255);">CONTINUE</span> o <span style="color: rgb(51, 51, 255);">CONTINUE WHEN</span>. En este último caso podremos evitar el uso de la sentencia IF para controlar la condición de salida de la iteración.<br /><pre><span style="color: rgb(0, 153, 0);"> BEGIN</span><br /><span style="color: rgb(0, 153, 0);"> LOOP</span><br /><span style="color: rgb(0, 153, 0);"></span><span style="color: rgb(0, 153, 0);"> ...<br /> <span style="color: rgb(51, 51, 255);">CONTINUE WHEN</span> condicion; --vuelve al comienzo del loop<br /><br /> -- si condicion=true, esta parte no se ejecuta<br /> ...<br /></span><span style="color: rgb(0, 153, 0);"> END LOOP;</span><br /><span style="color: rgb(0, 153, 0);"></span><span style="font-style: italic; color: rgb(0, 153, 0);"></span><span style="color: rgb(0, 153, 0);"> END;</span></pre>Los programadores conservadores se preguntarán para que necesitamos esta sentencia, despues de todo siempre nos hemos arreglado con la cláusula IF-THEN-ELSE de modo de avanzar a la siguiente iteración. Es cierto, no lo necesitamos para hacer cosas que antes no podíamos, pero sí para simplificar el código y facilitar la lectura.<br /><br /><span style="font-weight: bold;">Un ejemplo con CONTINUE</span><br /><br />Hay un caso típico donde CONTINUE puede beneficiarnos en la claridad de código para el seguimiento de la lógica: cuando tenemos que hacer múltiples validaciones antes de procesar un registro.<br /><br />Imaginemos nuestro loop actual (muy simplificado), en donde para cada registro hacemos una serie de validaciones antes de procesarlo. Si una validación falla, debemos pasar al siguiente registro. Para resolver esta lógica, debemos crear una estructura anidada de IFs, ya que debo evitar que se ejecute el resto del loop si una de las validaciones falla.<pre style="color: rgb(0, 153, 0);">LOOP<br /> EXIT WHEN <span style="font-style: italic;">condicion</span>;<br /> i:=i+1;<br /><br /> a := valida_1(T(i));<br /> IF (a) THEN<br /> b := valida_2(a);<br /> IF (b) THEN<br /> ....<br /> IF (c) THEN<br /><br /> .....<br /> procesoRegistro(T(i));<br /> .....<br /> END IF;<br /> ELSE<br /> ....<br /> END IF;<br /> END IF;<br /><br />END LOOP;</pre>Notemos como los múltiples IF anidados complican el seguimiento del flujo. Muchas veces nos hemos visto complicados al tener que agregar una nueva validación, ya que hay que agregar un nuevo IF al loop, y debo mantener consistentes los correspondientes END IF que deshacen el nivel de anidación.<br /><br />Ahora veamos como puede verse mejorado con CONTINUE-WHEN:<pre><span style="color: rgb(0, 153, 0);">LOOP</span><br /><span style="color: rgb(0, 153, 0);"> EXIT WHEN <span style="font-style: italic;">condicion</span>;</span><br /><span style="color: rgb(0, 153, 0);"> i:=i+1;</span><br /><span style="color: rgb(0, 153, 0);"> </span><br /><span style="color: rgb(0, 153, 0);"> a := valida_1(T(i));</span><br /><span style="color: rgb(0, 153, 0);"> CONTINUE WHEN NOT a;</span><br /><br /><span style="color: rgb(0, 153, 0);"> b := valida_2(a);</span><br /><span style="color: rgb(0, 153, 0);"> CONTINUE WHEN NOT b;</span><br /><br /><span style="color: rgb(0, 153, 0);"> ....</span><br /><br /><span style="color: rgb(0, 153, 0);"> procesoRegistro(T(i));</span><br /><span style="color: rgb(0, 153, 0);"> </span><br /><span style="color: rgb(0, 153, 0);">END LOOP;</span></pre>La mejoría es evidente, conseguimos disminuir la anidación (a 1) y evitar el uso repetitivo de IF/END-IF, reduciendo la posibilidad de cometer errores de lógica al momento de modificar.<br /><br />CONTINUE es un recurso que evidentemente solo puede utilizarse en Oracle 11g, sin embargo, siendo conscientes que nuestro código no va a compilar en versiones anteriores, es una práctica que contribuye a la legibilidad del código, con todos los beneficios que eso trae aparejado.<br /><br /><span style="font-weight: bold;">Ver también sobre 11g</span><br /><a href="http://oraclenotepad.blogspot.com/2008/03/11g-y-sus-ndices-invisibles.html">11g y sus índices invisibles</a>lferhttp://www.blogger.com/profile/00618392085702183279noreply@blogger.com