I have the following code which should do a simple if-else statement using Progress ABL.
I cannot get the program to reach the ELSE statement even when the substring "UK" cannot be found. Can anyone see what I am missing:
FIND FIRST ttShipHead WHERE ttShipHead.ShipToCustCustID = "1404".
IF ttShipHead.AddrList Matches "*UK*" THEN
assign ttShipHead.CheckBox01 = (false).
ELSE
assign ttShipHead.CheckBox01 = (true).
I suggest that you add some debugging:
FIND FIRST ttShipHead WHERE ttShipHead.ShipToCustCustID = "1404" no-error.
message available( ttShipHead ).
pause.
message ttShipHead.AddrList ( ttShipHead.AddrList Matches "*UK*" ).
pause.
IF ttShipHead.AddrList Matches "*UK*" THEN
assign ttShipHead.CheckBox01 = (false).
ELSE
assign ttShipHead.CheckBox01 = (true).
message ttShipHead.Checkbox01.
pause.
This should make it clear what is going wrong.
I don't know a whole lot about ABL. But I think the syntax is
IF expression THEN DO: work. So try adding a DO: after your THEN
If there's a message on the screen about record ttshiphead not found, then it's not running the IF statement at all.
Typically FINDs have a "NO-ERROR" followed by an "IF AVAILABLE ttshiphead THEN " where required.
Your code looks correct. Maybe some small changes to make sure you have record.
FIND FIRST ttShipHead WHERE ttShipHead.ShipToCustCustID = "1404" NO-ERROR.
IF AVAILABLE ttShipHead THEN
IF ttShipHead.AddrList MATCHES "*UK*":U THEN
assign ttShipHead.CheckBox01 = (false).
ELSE
assign ttShipHead.CheckBox01 = (true).
if you want to can add and else to show if record not available.
FIND FIRST ttShipHead WHERE ttShipHead.ShipToCustCustID = "1404" NO-ERROR.
IF AVAILABLE ttShipHead THEN
IF ttShipHead.AddrList MATCHES "*UK*":U THEN
assign ttShipHead.CheckBox01 = (false).
ELSE
assign ttShipHead.CheckBox01 = (true).
ELSE
MESSAGE "NO RECORD FOUND".
Related
REXX is completely new to me, I like it so far. I am using SixPack running on Hercules. VM/370 is a nice environment, but I am trying to make it user friendly; filling in scripts for everything that works-so as to not need to repeat my steps.
The file attached below was written to search in ISFP, instead I want it to access disks. It searches for a specified file.
I do not know enough to rewrite a REXX program. It stops at strange places saying "found" this or that. Please, give any suggestions.
/* REXX */
ARG PROGNAME
PROGNAME = STRIP(PROGNAME)
ACCESS_TEMPLATE='A2 Y U'
USE VAR ACCESS_TEMPLATE A2 Y U /* NOT PARSE */
VAR1 = A2
VAR2 = Y
VAR3 = U
IF PROGNAME == '' THEN DO
SAY 'ENTER MEMBER NAME'
FULL PROGNAME
PROGNAME = STRIP(PROGNAME)
IF PROGNAME == '' THEN DO
SAY NO MEMBER ENTERED. EXITING THE PROGRAM
EXIT
END
END
SEARCH.1 = PROD1.LIB
SEARCH.2 = PROD2.LIB
SEARCH.3 = PROD3.LIB
CNT = 3
FND = 'N'
DO I = 1 TO CNT
ACCESS 'VAR1' 'VAR2' 'VAR3'
LIB = LIST.I(PROGNAME)
IF SYSDSN('LIB') == OK THEN DO
FND = 'Y'
TYPE('LIB')
END
END
IF FND == 'N'THEN DO
SAY MEMBERS NOT FOUND IN ANY LIBRARIES
SAY PLEASE CHECK THE MEMBER ENTERED
EXIT
END
This is a bit late but it's good advice for novice REXX programmers...
Right near the top of your program put in this:
SIGNAL ON NOVALUE
and then near the every end...
NOVALUE: SAY 'NOVALUE error at line' SIGL
exit 4
Why? REXX has a "feature" in that every undefined variable resolves to its own name in UPPER case, like this:
myvar1='hi there'
mayvar2=', joe'
say myvar1||myvar2
What you probably intended to SAY was
'hi there, joe'
but instead got
'hi thereMYVAR2'
If you had SIGNAL ON NOVALUE it would have given you an error message which is a lot better. I ALWAYS put this into my code.
I have the following if else statement that created by myself in order to link to the if else statement given in second part:
m=4
if m==3
disp(true)
else
disp(false)
Second part ( this code is fix cannot be change):
if (true)
A=Hello World
else
A=Bye
If using the first part code, my output will be
A=Hello World
but my desire output is
A=Bye
Anyone one have idea to edit the first part, because now my return value in first part not able to link to my second part.
If you can't change the second part's code, I'm afraid your desire cannot be fulfilled. Or rather, I'm afraid your code won't run at all, because your perenthesis, quotes, end-statement (and arguably semicolons) are not in place.
if true
A = 'Hello World';
else
A = 'Bye';
end
This code will return A = 'Hello World', no matter what, since true is always true. If-else conditions work like this:
if (*what's in here evealuates to true*)
%do stuff
else (*if what's up there does not evaluate to true*)
%do other stuff
Clearly, true will always evaluate to true. So the above if-else condition will always return A = 'Hello World'.
You don't need two if statements in order to accomplish this task. One is more than enough to perform all what you need:
m = 4;
if (m == 3)
A = 'Hello World';
else
A = 'Bye';
end
disp(A);
A few comments concerning your code:
if statements need to be closed with an end
if (true) will always pass into the statement
the disp function doesn't assign a value, its only goal is to display it in the Command Window
in order to work with text, you have to enclose it within single quotes ' (char array) or double quotes " (string), more info here
If you posted only small excerpts of your code and you need to perform those two checks sequentially, in different parts of your script, then:
m = 4;
if (m == 3)
m_equals_3 = true;
disp('M == 3');
else
m_equals_3 = false;
disp('M ~= 3');
end
% then, somewhere else...
if (m_equals_3)
A = 'Hello World';
else
A = 'Bye';
end
% ...
I guess this is a homework exercise. You should disclose that if it’s the case.
The exercise requieres you to change the workspace such that the second bit of code evaluated the else case. This can be accomplished by changing the meaning of true. In your first bit of code, make it so that
true = flase;
Or equivalently,
true = 0;
Note that this is really bad form, if you ever do something like this outside of a homework exercise that explicitly asks you to do so, you’ll get fired or maybe even shot. You’ve been warned!
By the way, I assume that the missing quote characters around the strings and the missing ends are typos?
I have a small problem which I believed I could solve simply, it turns out I'm not able to figure out.
I have following query:
SELECT custom_field
INTO v_start_of_invoice
FROM BILL
WHERE BIMA_TRACKING_ID = v_previous_BIMAtrackingID
AND BSCO_CODE_ID = 'PRPAYMENT'
AND PREP_SEQ_NUM = 0
AND ITEM_CAT_CODE_ID = 1
AND PARTITION_KEY = v_prev_partition
AND SUBPARTITION_KEY = v_prev_subpartition;
What I would like to achieve here is to give to variable v_start_of_invoice the value "0" if one or all the where condition are not met.
In simple word I don't want the script to fail but I want the variable either to be set with some value if all the where conditions are matched, otherwise I want to assign the value 0.
I'm sure there are quite a few ways but I need to check what could be the best way to achieve that.
Many Thks in advance
M.
You seem to have a misunderstanding of what the exception block actually does. First off you cannot avoid the exception. If you use "select into" the query is successful only when exactly 1 row is returned. Otherwise PLSQL will internally raise the NO_DATA_FOUND when the query returns 0 rows, and TOO_MANY_ROWS when it returns more then 1 row. The exception block tells PLSQL what to do when an error is generated. Basically the exception block tells what action to take on specific errors and whether to continue error processing or discard the error. (Check the RAISE and RAISE_APPLICATION_ERROR statements.)
Keep in mind that blocks can be nested. With this in mind and in context of a outer block the solution offered by #are is exactly what you want. The structure becomes:
Begin
.
.
.
begin
place #are's code here.
end ;
-- Continue your code here: The Error has been handled and execution continues as though the exception never happened.
.
.
.
end;
As far as the "NVL(v_start_of_invoice, 0);" it's a function that will return 0 if v_start_of_invoice is NULL and v_start_of_invoice otherwise. Note the value of INTO variables is not it the select generates an error unless you set it in the exception block.
begin
SELECT custom_field
INTO v_start_of_invoice
FROM BILL
WHERE BIMA_TRACKING_ID = v_previous_BIMAtrackingID
AND BSCO_CODE_ID = 'PRPAYMENT'
AND PREP_SEQ_NUM = 0
AND ITEM_CAT_CODE_ID = 1
AND PARTITION_KEY = v_prev_partition
AND SUBPARTITION_KEY = v_prev_subpartition;
exception WHEN NO_DATA_FOUND THEN
v_start_of_invoice := 0;
end;
I'm a progress noob, actually having problem with basic blocks.
Below the issue is in my if else statement. It works fine when its just if, then, else then, but when I want to put in more than one statement into the if portion, I have to put it in a block, so I'm using if, then do: else, then do: but these aren't working for me. Any obvious errors you can see? My error message is **Colon followed by white space terminates a statement. (199)
INPUT FROM "r:\_content\stephen\4gl apps\dpl\output.csv".
REPEAT:
ASSIGN i_cntr = (i_cntr + 1).
myRow = "".
IMPORT DELIMITER ',' myRow.
IF myRow[5] <> "" THEN DO:
/*change this to assign 2 rows - 2 creates - 2 sets of four*/
c_fname = myRow[1].
MESSAGE
c_fname SKIP
myRow[2] SKIP
myRow[3] skip
myRow[4] skip
myRow[5] SKIP
i_cntr
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END./*end of if, then do:*/
ELSE IF myRow[5] = "" THEN DO:
MESSAGE
myRow[1] SKIP
myRow[2] skip
myRow[3] skip
myRow[4] skip
i_cntr
VIEW-AS ALERT-BOX INFO BUTTONS OK.
END./*end of else if, then do:*/
END./*end of repeat*/
A very simple syntax error: you need at least one space after the END-statement.
END. /*end of if, then do:*/
/* ^ Make sure there's space above here! */
And if you don't want to follow the excellent advice in Tims answer (use CASE). This is the "complete" syntax of the IF statement.
IF expression1 THEN DO:
/* Code goes here */
END.
ELSE IF expression2 THEN DO:
/* Code goes here */
END.
ELSE DO:
/* Code goes here */
END.
expressions:
A constant, field name, variable name, or expression whose value is logical (TRUE or FALSE). The expression can include comparisons, logical operators, and parentheses.
You can also leave out the DO: END. When the IF code to be executed only consists of a single statement:
IF TRUE THEN DISPLAY "TRUE".
ELSE DISPLAY "NOT TRUE".
You could also use other block-statements (such as FOR or REPEAT) but that will most likely only create code that is hard to read.
Rather than using nested IF/ELSE, you'd be better off using a CASE statement like so:
CASE varname:
WHEN "" THEN DO: /*something */ END.
WHEN "value" THEN DO: /*something */ END.
OTHERWISE DO: /*something */ END.
END CASE.
Check the docs on this statement for more details.
I figured out the issue. This wasn't caused by a coding error. Apparently Progress doesn't like comments too close to the code, which caused it to throw an error.
END. /*end of if, then do:*/ => This is ok.
END./*end of if, then do:*/ => This caused the issue comments too close to statement.
Thanks To Tim Kuehn for his response.
I apologies for this being a very simple question but as a first time user of ABL open edge and im stuck. I have enter values into a table like so
METHOD PRIVATE VOID POPULATETABLE ( ):
DEFINE VARIABLE I AS INTEGER.
DO I = 0 TO 100:
CREATE TEST.
ASSIGN TEST.CUSTOMER_NAME="SMITH"
TEST.ORDER_NUMBER=I
TEST.ORDER="BOOKS"
TEST.COST=45.00
TEST.CUSTOMER_NAME = "JACKSON"
TEST.ORDER_NUMBER=I
TEST.ORDER="PAPER CLIPS"
TEST.COST=1.7.
ASSIGN TEST.CUSTOMER_NAME="JONES"
TEST.ORDER_NUMBER =I
TEST.ORDER="PENCILS"
TEST.COST=2.50
TEST.CUSTOMER_NAME = "TURNER"
TEST.ORDER_NUMBER = I
TEST.ORDER="PENS"
TEST.COST=0.7.
END.
END METHOD.
and I'm trying to display them using this
FOR EACH TEST:
DISPLAY TEST.COST TEST.CUSTOMER_NAME TEST.ORDER TEST.ORDER_NUMBER.
RETURN.
END.
However the result only shows the last row of data entered. can anyone help, I'm even unsure on whether the display function is right or the assign is.
The "return" in your FOR EACH is causing the code to leave the loop after the first record. Delete that statement and you'll see all the records.
FOR EACH TEST:
DISPLAY TEST.COST
TEST.CUSTOMER_NAME
TEST.ORDER
TEST.ORDER_NUMBER.
RETURN. /* this is why you're only seeing one record - */
/* get rid of this and you'll see all the records */
END.
I would avoid assigning an order# of 0. It's just asking to confuse people.
define variable i as integer no-undo.
do i = 1 to 100:
create test.
assign
test.order_number = i
test.customer = "smith" /* you need some way to get */
test.order = "books" /* actual data for the rest */
test.cost = random( 10, 100) /* of the fields... */
.
end.
And then review the orders with:
for each test no-lock:
display test.
end.
Yeah, all I needed was a create statement per each assign for each record and that worked. Thanks everyone, the working coded looks like:
CREATE TEST.
ASSIGN TEST.CUSTOMER_NAME="SMITH"
TEST.ORDER_NUMBER=I
TEST.ORDER="BOOKS"
TEST.COST=45.00.
CREATE TEST.
ASSIGN TEST.CUSTOMER_NAME = "TAYLOR"
TEST.ORDER_NUMBER=I
TEST.ORDER="PAPER CLIPS"
TEST.COST=1.7.
CREATE TEST.
ASSIGN TEST.CUSTOMER_NAME="THOMPSON"
TEST.ORDER_NUMBER =I
TEST.ORDER="PENCILS"
TEST.COST=2.50.
CREATE TEST.
ASSIGN TEST.CUSTOMER_NAME = "TURNER"
TEST.ORDER_NUMBER = 2
TEST.ORDER="PENS"
TEST.COST=0.7.
FOR EACH TEST WHERE TEST.COST > 1.3 BY TEST.ORDER_NUMBER:
DISPLAY TEST.
END.