Roger Waterhouse
Roger Waterhouse

Reputation: 13

How can I dynamically change the where conditions of a for each loop?

I have a table of records that has two logical flags, holdn and holdl. I want to loop through this table with 3 different criteria.

Either flag is TRUE - We want to see everything that is on hold

Flag holdl is TRUE - We only want see items that are on hold for this one reason

Flag holdn is TRUE - We only want to see items that are on hold for this other reason.

I cannot figure out how to dynamically change the for each loop based on this. What I have tried so far is to set the value of a variable based on these conditions and then use the content of the variable as one of the where parameters. This does not work as Progress complains that there is a data mismatch. The variable is a string, the flags are logical, so that does make sense. See sample code below. This is a snippet of the actual code with the the table name changed. The which-hold, order-from, etc variables are defined and set in a different module which calls this one.

DEFINE VARIABLE which-hold# AS CHARACTER FORMAT "x(30)" NO-UNDO.

CASE which-hold:
   WHEN "B" THEN which-hold# = "(widget.holdn or widget.holdl)".
   WHEN "L" THEN which-hold# = "widget.holdl".
   WHEN "N" THEN which-hold# = "widget.holdn".
END CASE.


for each widget where which-hold# and
         widget.order-no >= order-from and widget.order-no <= order-thru and
         widget.line-no >= line-from and widget.line-no <= line-thru and
         widget.joint-no >= joint-from and widget.joint-no <= joint-thru
         no-lock:

         A bunch of code to make a nice report with the retrieved records...

end.

Self taught Progress programmer here, who has inherited a huge, poorly documented application. Please be gentle.

Upvotes: 1

Views: 430

Answers (2)

Tom Bascom
Tom Bascom

Reputation: 14020

If you would prefer not to deal with handles a semi-dynamic approach is also possible:

define variable i as integer no-undo.

define query q for customer.

do while true:

  update i.

  case i:
    when 0 then quit.
    when 1 then open query q for each customer no-lock where custNum >= 1000.
    when 2 then open query q for each customer no-lock where state = "nh".
    otherwise   open query q for each customer no-lock where name begins "u".
  end.

  do while true with frame a:

    get next q.

    if not available customer then leave.

    display custNum name state with frame a 10 down.
    down with frame a.

  end.

  close query q.

end.

Upvotes: 3

bupereira
bupereira

Reputation: 1498

What you want is actually a dynamic query. I'll get to it at the end, but first I'd like to explain why you won't be able to try and substitute the field name in the which-hold# variable: because the query is evaluated at compile time. And this is what it reads (supposing which-hold# has a value of widget.holdn FOR EACH widget where "widget-holdn" (...) And that does not evaluate to TRUE or FALSE. So what, you ask? Well, that is the key here. Every condition needs to evaluate to true or false, so you'd be more in luck if you try

for each widget where (if widget-hold# = 'widget.holdn' then widget.holdn = true else TRUE) (...)

Again, notice the condition will exist if widget-hold# has the value I want, otherwise it doesn't filter on this at all. So you can just code the way I showed (for each of the conditions you have) and it should work fine. BUT let me suggest a dynamic query instead. You need to have:

DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.

CREATE QUERY hQuery.
hQuery:SET-BUFFERS(BUFFER widget:HANDLE).
hQuery:QUERY-PREPARE('<THIS IS THE CORE>').
hQuery:QUERY-OPEN().
DO WHILE hQuery:GET-NEXT():
   A bunch of code to make a nice report with the retrieved records...  
END.

So in the core you have a string that corresponds to your for each the way you want it to look. So it should be for example (store this in a variable, or assemble it inside the query prepare, it doesn't matter):

'FOR EACH widget NO-LOCK WHERE ' + 
(if which-hold = 'B' then 'widget.holdn = true and widget.holdl = true'
 else if which-hold = 'L' then 'widget-holdl = true'
 else /* N */ 'widget-holdn = true').

Remember I said your query is evaluated at compile time? Well, just so you know, dynamic queries on the other end are evaluated at run time, so be prepared for errors to pop up only when you run. Another thing I should mention is dynamic queries are slower than static ones, so please evaluate and choose your poison :)

This should be what you need. Please let me know if it's helpful or any questions remain.

Upvotes: 2

Related Questions