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

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.

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.

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.

Related

change value in dict from datasets Hugging face

I want to train model on the Wikitext-2-v1 training corpus(https://huggingface.co/datasets/wikitext).
I tried to remove punctuation in each line, which from what I find is a dictionary, i.e., each line is a dictionary, so I tried to update the value, but after the loop, I checked the value, there is nothing changed.
%pip install datasets
from datasets import list_datasets, load_dataset, list_metrics, load_metric
dataset = load_dataset('wikitext', 'wikitext-2-v1', split =['train','validation','test'])
for i in range(len(dataset[0])):
for k,v in dataset[0][i].items():
v = v.translate(str.maketrans('', '', string.punctuation))
dataset[0][i]['text'] = v
Here is a one line example {'text': ' = Valkyria Chronicles III = \n'}
after the loop it keeps same, but I want it to be {'text': ' Valkyria Chronicles III'}
Your translate code is good and doing what it's supposed to.
I believe the Dataset type does not support item assignment. (You can't change it.) Normally this raises a TypeError but you managed to code it in a way to avoid that. You may need to build up a new a new datastructure with your translated data as you go.
Note also that it is rather strange they way you iterate through items() but only use the text one. Seems to me either explicitly use only text or explicitly handle every one.

is it the same to use MATCHES (* + "" + *) and no parameters in a FOR EACH in Progress 4GL?

So I made the following FOR EACH
FOR EACH insp_cd
WHERE insp_cd.status_ = 1
AND insp_cd.item MATCHES('*' + pc-itemPost + '*')
AND insp_cd.update_at < NOW:
So, when the pc-itemPost is "", should I avoid using the MATCHES? Like:
IF pc-itemPost = "" THEN DO:
FOR EACH insp_cd
WHERE insp_cd.status_ = 1
AND insp_cd.update_at < NOW:
...
END.
ELSE DO:
FOR EACH insp_cd
WHERE insp_cd.status_ = 1
AND insp_cd.item MATCHES('*' + pc-itemPost + '*')
AND insp_cd.update_at < NOW:
I know it's very slow because of the table scan, but I'd like to know if there is any difference. Thanks.
Any time that you can avoid MATCHES you should do so.
Using an IF statement to choose branches that execute different static FOR EACH statements is one way to do it. Building dynamic queries based on similar logic would be another approach.
Whether or not your two queries are "different"? Sure, they are different. They have different WHERE clauses so their specific behavior (and performance) will depend on the index structure (which we don't know).
insp_cd.item matches “*” + pc-itempost + “*”
Can be very different from:
insp_cd.item = “”.
And logically it is not the same as omitting a check of insp_cd.item altogether. Logically maybe you’re attempting to exclude empty values? I’m not sure what the requirement is here.
If insp_cd.item is the first component of an index, or the second component after insp_cd.Status then a variation of this query using ‘ = “” ‘ will be much more efficient than one using MATCHES.
Back to avoiding MATCHES, at a high level:
If there is no need for wild cards use "=". Equality matches are always preferred.
If the wild card is at the end of the string use BEGINS.
If the wild card is being used to signify a known list use a series of OR clauses or a LOOKUP() or build a temp-table to join in the query.
There are probably more ways to avoid MATCHES but these are the ones that spring to mind.

How to print unique numbers dynamically with PLSQL

I would like to display Unique numbers dynamically. I have tried below code for the same but same number is displaying all the times.
DECLARE
a NUMBER;
BEGIN
FOR i IN 1 .. 3 LOOP
DBMS_OUTPUT.PUT_LINE(&a);
END LOOP;
END;
the above code will ask me for "a" value three times, if i pass 1,2,3 as parameters then it should display 1,2,3 but this code is displaying first(1) value three time as 1,1,1.
Could you please help me to get the required output like 1,2,3
You can't really create an interactive program in just PL/SQL. When you put &a in the PL/SQL and run it in a tool like SQL Developer, it prompts you once for a value for a before it runs the code, using the value you typed instead of the substitution variable a.
You want to print i and not a. Also the ampersand in front of the a means you will be prompted to enter a value for a.

How to have a SQLite query with a variable part?

Hi I am trying to create a query for SQLite which has a variable part in it. By variable I mean that a certain part within the string can possibly contain a variable but also an empy value
I tried this but I am not sure whether this works.
SELECT * FROM table WHERE attr LIKE 'ABC% %DEF'
Adding onto my comment, check the below code to test your values.
SELECT CASE WHEN 'ABC G DEF' LIKE 'ABC%DEF'
THEN 1
ELSE 0 END as test_space,
CASE WHEN 'ABCGGGDEF' LIKE 'ABC%DEF'
THEN 1
ELSE 0 END AS test_all

Can someone please explain what the following code does?

I'm currently working on a project that was written in classic asp. I've used this language some before but I'm rusty with it.
In that code I see the following function call:
Result = SwapOEMPart(sItem)
When I look at SwapOEMPart I see this:
function SwapOEMPart(oemPart)
// Do a bunch of stuff
oemPart = objRS("CCIPartNo") <-- this is the result of the stuff
end function
What does that do? Does it fill Result with the value of oemPart? Does it change the value of sItem (similar to a pass by reference)? Or perhaps it is something entirely different.
I'm familiar with returning data from asp functions by setting the function name equal to the value you want to return, but in this instance they are changing the value of the parameter they pass in and then just ending the function.
Based on the code you have provided, I'm going to assume objRS is an adodb.recordset, if that is the case, CCIPartNo is a column in the recorset, all your code is doing is writing the value of that column into the eomPart variable - eomPart isnt referenced as byref in the function declaration but this is assumed as default if you're in vbscript (not .net) so **it's almost as if the value of the column is being passed back into eomPart & because eomPart is a REFERENCE to the sItem value in your example, the actual value of sItem would change.
http://msdn.microsoft.com/en-us/library/ee478101%28VS.84%29.aspx

Resources