I've been browsing a while but I haven't found a successful answer for this.. shouldn't be much trouble for an experienced SQL coder:
I have the following FOR loop with an IF condition inside, and I want to exit the loop whenever the IF condition is met
<<OUTER_LOOP>>
FOR I IN T_TITLE.FIRST.. T_TABLE.LAST LOOP
IF T_TABLE(I).VAR_TITLE = PAR_TITLE THEN
V_TITLE_ID = I;
--insert exit here
END IF;
END LOOP;
I'm uncertain whether to use EXIT; EXIT OUTER_LOOP; or something like EXIT OUTER_LOOP WHEN V_TITLE_ID IS NOT NULL;
Thanks a lot for the help!
Just use EXIT:
FOR I IN T_TITLE.FIRST.. T_TABLE.LAST LOOP
IF T_TABLE(I).VAR_TITLE = PAR_TITLE THEN
V_TITLE_ID = I;
EXIT;
END IF;
END LOOP;
You shouldn't use EXIT WHEN in this situation, because you wouldn't be able to save the value of I.
You could use EXIT some_loop_label, but it is not necessary in your situation. It may come in handy when you have nested loops, though.
More information here: EXIT in Oracle
Related
A colleague and I were trying to figure out a way of doing the equivalent of a "continue" statement within a VBScript "For/Next" loop.
Everywhere we looked we found people had no way to do this in VBScript without having nasty nestings, which is not an option for us since it is a quite big loop.
We came out with this idea. Would it work just as a "continue(to next iteration)"? Does anyone have any better workaround or improvement suggestion?
For i=1 to N
For workaroundloop = 1 to 1
[Code]
If Condition1 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[...]
Next
Next
Thanks for your comments
Your suggestion would work, but using a Do loop might be a little more readable.
This is actually an idiom in C - instead of using a goto, you can have a do { } while (0) loop with a break statement if you want to bail out of the construct early.
Dim i
For i = 0 To 10
Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False
Next
As crush suggests, it looks a little better if you remove the extra indentation level.
Dim i
For i = 0 To 10: Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False: Next
A solution I decided on involved the use of a boolean variable to track if the for loop should process its instructions or skip to the next iteration:
Dim continue
For Each item In collection
continue = True
If condition1 Then continue = False End If
If continue Then
'Do work
End If
Next
I found the nested loop solutions to be somewhat confusing readability wise. This method also has its own pitfalls since the loop doesn't immediately skip to the next iteration after encountering continue. It would be possible for a later condition to reverse the state of continue. It also has a secondary construct within the initial loop, and requires the declaration of an extra var.
Oh, VBScript...sigh.
Also, if you want to use the accepted answer, which isn't too bad readability wise, you could couple that with the use of : to merge the two loops into what appears to be one:
Dim i
For i = 0 To 10 : Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False : Next
I found it useful to eliminate the extra level of indentation.
One option would be to put all the code in the loop inside a Sub and then just return from that Sub when you want to "continue".
Not perfect, but I think it would be less confusing that the extra loop.
I use to use the Do, Loop a lot but I have started using a Sub or a Function that I could exit out of instead. It just seemed cleaner to me. If any variables you need are not global you will need to pass them to the Sub also.
For i=1 to N
DoWork i
Next
Sub DoWork(i)
[Code]
If Condition1 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[...]
End Sub
We can use a separate function for performing a continue statement work. suppose you have following problem:
for i=1 to 10
if(condition) then 'for loop body'
contionue
End If
Next
Here we will use a function call for for loop body:
for i=1 to 10
Call loopbody()
next
function loopbody()
if(condition) then 'for loop body'
Exit Function
End If
End Function
loop will continue for function exit statement....
I've always used an Do While loop. This works with both For type loops.
For iIndex = 0 to 100
Do
If bCondition then Exit Do
...
Loop While False
Next
IMHO, this just looks clean.
I just saw Crush's answer, at the bottom. Sorry for the duplicate answer.
Implement the iteration as a recursive function.
Function Iterate( i , N )
If i == N Then
Exit Function
End If
[Code]
If Condition1 Then
Call Iterate( i+1, N );
Exit Function
End If
[Code]
If Condition2 Then
Call Iterate( i+1, N );
Exit Function
End If
Call Iterate( i+1, N );
End Function
Start with a call to Iterate( 1, N )
Try use While/Wend and Do While / Loop statements...
i = 1
While i < N + 1
Do While true
[Code]
If Condition1 Then
Exit Do
End If
[MoreCode]
If Condition2 Then
Exit Do
End If
[...]
Exit Do
Loop
Wend
I think you are intended to contain ALL YOUR LOGIC under your if statement. Basically:
' PRINTS EVERYTHING EXCEPT 4
For i = 0 To 10
' you want to say
' If i = 4 CONTINUE but VBScript has no continue
If i <> 4 Then ' just invert the logic
WSH.Echo( i )
End If
Next
This can make the code a bit longer, but some people don't like break or continue anyway.
It has been around 20 years since I last had to write in Pascal. I can't seem to use the structure elements of the language correctly where I am nesting if then blocks using begin and end. For example this gets me an Compiler Error "Identifier Expected".
procedure InitializeWizard;
begin
Log('Initialize Wizard');
if IsAdminLoggedOn then begin
SetupUserGroup();
SomeOtherProcedure();
else begin (*Identifier Expected*)
Log('User is not an administrator.');
msgbox('The current user is not administrator.', mbInformation, MB_OK);
end
end;
end;
Of course if I remove the if then block and the begin end blocks associated with them then everything is OK.
Sometimes I get it this kind of syntax right and it works out OK, but the problems become exasperated when nesting the if then else blocks.
Solving the problem is not enough here. I want to have a better understanding how to use these blocks. I am clearly missing a concept. Something from C++ or C# is probably creeping in from another part of my mind and messing up my understanding. I have read a few articles about it, and well I think I understand it and then I don't.
You have to match every begin with an end at the same level, like
if Condition then
begin
DoSomething;
end
else
begin
DoADifferentThing;
end;
You can shorten the number of lines used without affecting the placement, if you prefer. (The above might be easier when you're first getting used to the syntax, though.)
if Condition then begin
DoSomething
end else begin
DoADifferentThing;
end;
If you're executing a single statement, the begin..end are optional. Note that the first condition does not contain a terminating ;, as you're not yet ending the statement:
if Condition then
DoSomething
else
DoADifferentThing;
The semicolon is optional at the last statement in a block (although I typically include it even when it's optional, to avoid future issues when you add a line and forget to update the preceding line at the same time).
if Condition then
begin
DoSomething; // Semicolon required here
DoSomethingElse; // Semicolon optional here
end; // Semicolon required here unless the
// next line is another 'end'.
You can combine single and multiple statement blocks as well:
if Condition then
begin
DoSomething;
DoSomethingElse;
end
else
DoADifferentThing;
if Condition then
DoSomething
else
begin
DoADifferentThing;
DoAnotherDifferentThing;
end;
The correct use for your code would be:
procedure InitializeWizard;
begin
Log('Initialize Wizard');
if IsAdminLoggedOn then
begin
SetupUserGroup();
SomeOtherProcedure();
end
else
begin
Log('User is not an administrator.');
msgbox('The current user is not administrator.', mbInformation, MB_OK);
end;
end;
I ran across this piece of pascal code. I am curious as to how this does not repeat endlessly.
repeat
if xs>(torgx+xlim)
then begin
x:=xlim;
BREAK;
end;
if xs<(torgx-xlim)
then begin
x:=0-xlim;
BREAK;
end;
x:=xs-torgx;
BREAK;
until 0<>0;
I am confused as to how zero would ever be greater than or less than zero.
A loop that continues until 0 <> 0 is supposed to be endless.
But inside the loop there are some conditions that will break the loop, hence the use of the keyword break.
In fact, the repeat..until loop will only run once. The comparison is made that if a value is larger than a condition or less than another it will break out of the loop. If none of those conditions are met, it will break anyway.
A colleague and I were trying to figure out a way of doing the equivalent of a "continue" statement within a VBScript "For/Next" loop.
Everywhere we looked we found people had no way to do this in VBScript without having nasty nestings, which is not an option for us since it is a quite big loop.
We came out with this idea. Would it work just as a "continue(to next iteration)"? Does anyone have any better workaround or improvement suggestion?
For i=1 to N
For workaroundloop = 1 to 1
[Code]
If Condition1 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[MoreCode]
If Condition2 Then
Exit For
End If
[...]
Next
Next
Thanks for your comments
Your suggestion would work, but using a Do loop might be a little more readable.
This is actually an idiom in C - instead of using a goto, you can have a do { } while (0) loop with a break statement if you want to bail out of the construct early.
Dim i
For i = 0 To 10
Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False
Next
As crush suggests, it looks a little better if you remove the extra indentation level.
Dim i
For i = 0 To 10: Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False: Next
A solution I decided on involved the use of a boolean variable to track if the for loop should process its instructions or skip to the next iteration:
Dim continue
For Each item In collection
continue = True
If condition1 Then continue = False End If
If continue Then
'Do work
End If
Next
I found the nested loop solutions to be somewhat confusing readability wise. This method also has its own pitfalls since the loop doesn't immediately skip to the next iteration after encountering continue. It would be possible for a later condition to reverse the state of continue. It also has a secondary construct within the initial loop, and requires the declaration of an extra var.
Oh, VBScript...sigh.
Also, if you want to use the accepted answer, which isn't too bad readability wise, you could couple that with the use of : to merge the two loops into what appears to be one:
Dim i
For i = 0 To 10 : Do
If i = 4 Then Exit Do
WScript.Echo i
Loop While False : Next
I found it useful to eliminate the extra level of indentation.
One option would be to put all the code in the loop inside a Sub and then just return from that Sub when you want to "continue".
Not perfect, but I think it would be less confusing that the extra loop.
I use to use the Do, Loop a lot but I have started using a Sub or a Function that I could exit out of instead. It just seemed cleaner to me. If any variables you need are not global you will need to pass them to the Sub also.
For i=1 to N
DoWork i
Next
Sub DoWork(i)
[Code]
If Condition1 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[MoreCode]
If Condition2 Then
Exit Sub
End If
[...]
End Sub
We can use a separate function for performing a continue statement work. suppose you have following problem:
for i=1 to 10
if(condition) then 'for loop body'
contionue
End If
Next
Here we will use a function call for for loop body:
for i=1 to 10
Call loopbody()
next
function loopbody()
if(condition) then 'for loop body'
Exit Function
End If
End Function
loop will continue for function exit statement....
I've always used an Do While loop. This works with both For type loops.
For iIndex = 0 to 100
Do
If bCondition then Exit Do
...
Loop While False
Next
IMHO, this just looks clean.
I just saw Crush's answer, at the bottom. Sorry for the duplicate answer.
Implement the iteration as a recursive function.
Function Iterate( i , N )
If i == N Then
Exit Function
End If
[Code]
If Condition1 Then
Call Iterate( i+1, N );
Exit Function
End If
[Code]
If Condition2 Then
Call Iterate( i+1, N );
Exit Function
End If
Call Iterate( i+1, N );
End Function
Start with a call to Iterate( 1, N )
Try use While/Wend and Do While / Loop statements...
i = 1
While i < N + 1
Do While true
[Code]
If Condition1 Then
Exit Do
End If
[MoreCode]
If Condition2 Then
Exit Do
End If
[...]
Exit Do
Loop
Wend
I think you are intended to contain ALL YOUR LOGIC under your if statement. Basically:
' PRINTS EVERYTHING EXCEPT 4
For i = 0 To 10
' you want to say
' If i = 4 CONTINUE but VBScript has no continue
If i <> 4 Then ' just invert the logic
WSH.Echo( i )
End If
Next
This can make the code a bit longer, but some people don't like break or continue anyway.
I occasionally do something like....
IF very-likely-condition THEN
NULL;
ELSE
<<code to deal with the unlikely condition>>
END IF;
Which gives a PLW-06002 unreachable code warning from the PL/SQL compiler on the NULL line atfer the IF.
Now whilst I can clearly ignore the warning and/or refactor the IF statement to be a NOT, I think it reads better this way.
So does anybody know is there is another way of inserting an empty statement so that I don't get the compiler warning?
EDIT:
I'm not saying I do this often... in fact I'd do it very rarely. But occasionally I do think it reads better this way.
EDIT 2:
Plus there are other scenarios where it might be valid to do this (such as ignoring a specific error in an EXCEPTION block). I only used the IF as a simple example to illustrate the point.
To Recursive And Weblog :
the following statements are NOT equivalent:
IF :x = 0 THEN
NULL;
ELSE
do_something;
END IF;
and
IF NOT :x = 0 THEN
do_something;
END IF;
If :x IS NULL the do_something procedure will be called in the first case only. This is because the expression NULL = 0 is neither TRUE nor FALSE in Oracle, it is "unknown".
The correct way to re-write the first statement would be:
IF :x != 0 OR :x IS NULL THEN
do_something;
END IF;
I can see why in some cases we could write things as the OP.
Looks like this is by design. See http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14261/controlstructures.htm#i5421
Example 4-23 Using NULL as a Placeholder When Creating a Subprogram
CREATE PROCEDURE ... AS
BEGIN
NULL; -- use NULL as placeholder, raises "unreachable code" if warnings enabled
END;
/
Why do you have an empty statement? That's a code smell. It's generally accepted that is it not easier to read with an empty if block.
Change your if condition to the opposite of what it currently is:
IF NOT very-likely-condition THEN
<<code to deal with the unlikely condition>>
END IF;
If you need to do something when the condition is true, you can always add that block back in. Empty blocks separate the condition from the block that's executed when the condition is true. It also looks like you used to have code in the if section, then removed it but were too lazy to rewrite the if condition to remove the empty statement.
Subjectively, if I were reading your code and saw the empty if block, I'd think you didn't know what you were doing.