How to be sure that only one record is taken into account at a given stage of the query? - openedge

I wonder how exactly the "queries" for each and first work.
lets say I have some tables A, B, C and D.
How many records will I find if I use sth like:
first B,
each C,
first D:
<block>
end.
1*|C|*1? [assuming there will be C that has some relation with B, etc]
And then I have sth like this:
for each A,
first B,
/*-----------------------*/
each C,
first D:
<block>
end.
How can I make sure to have the same complexity after this change? (B has now relation with A and there will be some where statements) Will it be |A|*1*|C|*1? And If I want to have the same complexity as before is there anything I can add there?
Example of the problem
define temp-table ttA no-undo
field mainID as character format "x(20)"
field foreignKey as character format "x(20)"
index idx_mainID is unique primary mainID
.
define temp-table ttB no-undo
field mainID as character format "x(20)"
field foreignKey as character format "x(20)"
index idx_mainID is unique primary mainID
.
define temp-table ttC no-undo
field mainID as character format "x(20)"
field foreignKey as character format "x(20)"
index idx_mainID is unique primary mainID
.
define temp-table ttD no-undo
field mainID as character format "x(20)"
field foreignKey as character format "x(20)"
index idx_mainID is unique primary mainID
.
DEFINE VARIABLE viCounterA as integer no-undo.
DEFINE VARIABLE viCounterB as integer no-undo.
DEFINE VARIABLE viCounterC as integer no-undo.
DEFINE VARIABLE viCounterD as integer no-undo.
DEFINE VARIABLE viTotal as integer no-undo.
DEFINE VARIABLE viTotal2 as integer no-undo.
assign
viCounterA = 0
viCounterB = 0
viCounterC = 0
viCounterD = 0
viTotal = 0
viTotal2 = 0
.
DEFINE VARIABLE vcAID as character no-undo.
DO viCounterA = 1 TO 9:
vcAID = "A0" + STRING(viCounterA).
create ttA.
ttA.mainID = vcAID.
ttA.foreignKey = "".
DEFINE VARIABLE vcBID as character no-undo.
DO viCounterB = 1 TO 9:
vcBID = vcAID + "B0" + STRING(viCounterB).
create ttB.
ttB.mainID = vcBID.
ttB.foreignKey = vcAID.
DEFINE VARIABLE vcCID as character no-undo.
DO viCounterC = 1 TO 9:
vcCID = vcBID + "C0" + STRING(viCounterC).
create ttC.
ttC.mainID = vcCID.
ttC.foreignKey = vcBID.
DEFINE VARIABLE vcDID as character no-undo.
DO viCounterD = 1 TO 9:
vcDID = vcCID + "D0" + STRING(viCounterD).
create ttD.
ttD.mainID = vcDID.
ttD.foreignKey = vcCID.
END.
END.
END.
END.
/* DISPLAY V1 */
for first ttB,
each ttC where ttC.foreignKey = ttB.mainID,
first ttD where ttD.foreignKey = ttC.mainID:
viTotal = viTotal + 1.
display
viTotal
ttD.mainID
.
end.
/* DISPLAY V2 */
for each ttA where ttA.mainID = "A01" or ttA.mainID = "A03",
first ttB where ttB.foreignKey = ttA.mainID,
each ttC where ttC.foreignKey = ttB.mainID,
first ttD where ttD.foreignKey = ttC.mainID:
viTotal2 = viTotal2 + 1.
display
viTotal2
ttD.mainID
.
end.
display
viTotal
viTotal2
.

It will be the same as:
define variable i as integer no-undo.
define variable j as integer no-undo.
define variable k as integer no-undo.
for each A no-lock:
i = i + 1.
for first B no-lock:
j = j + 1.
for each C no-lock where C.something = B.something:
k = k + 1.
display i j k.
end.
end.
end.

Related

Using num-entries() with more than one possible delimitor

I have a list of email addresses that I am reading in from a csv file, that are sometimes separated by commas and sometimes by semicolons when the person has more than 1 email address.
Examples:
Pin email_address
11 heidi#gmail.com,hh#yahoo.com
12 tom#osu.edu;TQ#gmail.com
13 lisa#yahoo.com
14 linda#me.com;llewis#gmail.com,lvlv#yahoo.com
Let's say I am reading these into a variable and counting them per person with another variable:
DEFINE VARIABLE emailString AS CHARACTER NO-UNDO.
DEFINE VARIABLE iEmailCount AS INTEGER.
I want to count the number of emails for the person. I know that I can use this syntax to count the entries between semi-colons, and between commas respectively.
iEmailCount = NUM-ENTRIES (emailString, ";").
iEmailCount = NUM-ENTRIES (emailString).
But how can I best say...
iEmailCount = Num_ENTRIES(emailString,";" OR ",").
You have to break the line down by each delimiter. Loop through one delimiter, then the second:
DEFINE VARIABLE emailString AS CHARACTER NO-UNDO.
DEFINE VARIABLE iEmailCount AS INTEGER NO-UNDO.
DEFINE VARIABLE iLoop AS INTEGER NO-UNDO.
iEmailCount = NUM-ENTRIES(emailString).
DO iLoop = 1 TO NUM-ENTRIES(emailString): /* Loop through comma delimiters */
iEmailCount = iEmailCount + NUM-ENTRIES(ENTRY(iLoop, emailString), ";") - 1. /* Sum by semicolon delimiter */
END.
If you're sure that a semicolon will only appear as a delimiter in the data, you can replace them with commas. Then it's a simple count of the number of comma entries:
DEFINE VARIABLE emailString AS CHARACTER NO-UNDO INITIAL "linda#me.com;llewis#gmail.com,lvlv#yahoo.com".
DEFINE VARIABLE iEmailCount AS INTEGER NO-UNDO.
emailString = REPLACE(emailString, ";", ",").
iEmailCount = NUM-ENTRIES(emailString).
MESSAGE "Email string: " emailString SKIP
"Count: " iEmailCount VIEW-AS ALERT-BOX.
You can't in a single statement.
DEFINE VARIABLE emailString AS CHARACTER NO-UNDO.
DEFINE VARIABLE iEmailCount AS INTEGER.
iEmailCount = NUM-ENTRIES (emailString, ";") + NUM-ENTRIES (emailString).
For your pin 14 you will need to loop through the string, and count the entries manually.
define variable pin as character.
define variable pos as integer.
define variable pos2 as integer.
define variable cnt as integer.
define variable addr as character.
define variable startAt as integer.
pin = 'linda#me.com;llewis#gmail.com,lvlv#yahoo.com'.
startAt = 1.
pos = index(pin, ',', startAt).
do while pos gt 0:
addr = substring(pin, startAt, pos - 1).
pos2 = index(addr, ';').
if pos2 gt pos then
cnt = cnt + 1.
else
cnt = cnt + num-entries(addr, ';').
startAt = pos + 1.
pos = index(pin, ',', startAt).
end.
// after the last ,
if not trim(substring(pin, StartAt)) eq '' then
cnt = cnt + 1.
message
pin skip
cnt
view-as alert-box.
Just a gotcha, a string with a space will return 1 . An empty string will return 0.
message
'empty: ' num-entries('') skip // 0
'space: ' num-entries(' ') // 1
view-as alert-box.

How to export XML in progress?

I am new to OpenEdge and I am trying to export initially two tables to XML file. My ultimate goal is to export the XML file as:
<?xml version="1.0" encoding="utf-8"?>
<LAS xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<LASRow>
<temp_wonbr>wo01</temp_wonbr>
<temp_id>01</temp_id>
<Allocations>
<AllocDetail>
<Emplacement>SUP.TR</Emplacement>
<Reference/>
<NumLot>22045</NumLot>
<Expire/>
<Qalloc>1</Qalloc>
<Message/>
</AllocDetail>
<AllocDetail>
<Emplacement>SUP.TR</Emplacement>
<Reference/>
<NumLot>22046</NumLot>
<Expire/>
<Qalloc>1</Qalloc>
<Message/>
</AllocDetail>
<Allocations>
</LASRow>
[enter image description here][1]
Thanks for your help!
[1]: https://i.stack.imgur.com/0yWOP.png
With a dataset you can export pretty much any XML (with some limitations, like not being able to create xml-comments).
You might have to fiddle around with replacing certain datatypes with characters to properly create empty tags (an empty or really ?-containing date will create another structure that you might not want).
This will get you started
DEFINE TEMP-TABLE ttLASRow NO-UNDO SERIALIZE-NAME "LASRow"
FIELD temp_wonbr AS CHARACTER
FIELD temp_id AS CHARACTER.
DEFINE TEMP-TABLE ttAllocations NO-UNDO SERIALIZE-NAME "Allocations"
FIELD parentid AS RECID SERIALIZE-HIDDEN.
DEFINE TEMP-TABLE ttAllocDetails NO-UNDO SERIALIZE-NAME "AllocDetails"
FIELD parentId AS RECID SERIALIZE-HIDDEN
FIELD Emplacement AS CHARACTER
FIELD Reference AS CHARACTER
FIELD NumLot AS INTEGER
FIELD ExpDat AS CHARACTER SERIALIZE-NAME "Expire"
FIELD Qalloc AS INTEGER
FIELD msg AS CHARACTER SERIALIZE-NAME "Message".
DEFINE DATASET dsLAS SERIALIZE-NAME "LAS" FOR ttLasRow, ttAllocations, ttAllocDetails
PARENT-ID-RELATION FOR ttLasRow, ttAllocations PARENT-ID-FIELD parentId
PARENT-ID-RELATION FOR ttAllocations, ttAllocDetails PARENT-ID-FIELD parentId
.
CREATE ttLasRow.
ASSIGN ttLasRow.temp_wonbr = "wo01"
ttLasRow.temp_id = "01".
CREATE ttALlocations.
ASSIGN ttAllocations.parentId = RECID(ttLasRow).
CREATE ttAllocDetails.
ASSIGN ttAllocDetails.parentid = RECID(ttAllocations)
ttAllocDetails.Emplacement = "SUP.TR"
ttAllocDetails.NumLot = 22045
ttAllocDetails.Qalloc = 1.
CREATE ttAllocDetails.
ASSIGN ttAllocDetails.parentid = RECID(ttAllocations)
ttAllocDetails.Emplacement = "SUP.TR"
ttAllocDetails.NumLot = 22046
ttAllocDetails.Qalloc = 1.
DATASET dsLAS:WRITE-XML("file", "c:\temp\xml.xml").
You can achieve what you want by combining your temp-tables with relations in a dataset and using the write-xml method on your dataset:
define temp-table ttlas no-undo
field temp_wonbr as char
field temp_id as char
.
define temp-table ttallocations no-undo
field parent_id as recid serialize-hidden
.
define temp-table ttallocdetails no-undo
field parent_id as recid serialize-hidden
field Emplacement as char
field Reference as char
field NumLot as int
field lexpire as char serialize-name 'Expire'
field Qalloc as int
field cmessage as char serialize-name 'Message'
.
define buffer bulas for ttlas serialize-name 'LASRow'.
define buffer buallocation for ttallocations serialize-name 'Allocations'.
define buffer budetail for ttallocdetails serialize-name 'AllocDetail'.
define dataset dslas serialize-name 'LAS'
for bulas, buallocation, budetail
parent-id-relation for bulas, buallocation parent-id-field parent_id
parent-id-relation for buallocation, budetail parent-id-field parent_id
.
create bulas.
assign
bulas.temp_wonbr = 'wo01'
bulas.temp_id = '01'
.
create buallocation.
assign
buallocation.parent_id = recid( bulas )
.
create budetail.
assign
budetail.parent_id = recid( buallocation )
budetail.emplacement = 'SUP.TR'
budetail.numlot = 22045
budetail.qalloc = 1
.
create budetail.
assign
budetail.parent_id = recid( buallocation )
budetail.emplacement = 'SUP.TR'
budetail.numlot = 22046
budetail.qalloc = 1
.
def var lcxml as longchar no-undo.
dataset dslas:write-xml( 'longchar', lcxml, true, ?, ?, ?, true ).
message string( lcxml ).
See https://abldojo.services.progress.com/?shareId=603f5bda9585066c2197989a
TEMP-TABLE ttTempTableName:WRITE-XML ("FILE", "c:\temp\filename.xml", TRUE, ?, ?).

How to add html tables in progress 4gl?

I created a temp table in Progress4gl and I need to email the data from temp table using html syntax. Which means I need to link all the fields in temp table to html table and email.
The fields in temp table are:
Part_ID, CustomerPartID, customer
Please help me with this.
Well you could just output the HTML. Something like this:
define temp-table tt_test
field f1 as integer
field f2 as character
field f3 as date
.
create tt_test.
assign
f1 = 1
f2 = "abc"
f3 = today
.
create tt_test.
assign
f1 = 2
f2 = "xyz"
f3 = today + 30
.
output to value( "mytable.html" ).
put unformatted "<table>" skip.
for each tt_test:
put unformatted substitute( " <tr><td>&1</td><td>&2</td><td>&3</td></tr>", f1, f2, f3 ) skip.
end.
put unformatted "</table>" skip.
output close.
For creating an html table you can (ab)use the power of datasets combined with serialize-name:
/* Write some awesome ABL code here, or load an existing snippet! */
define temp-table ttparts serialize-name "tr"
field part_id as char serialize-name "td"
field customerPartID as char serialize-name "td"
field customer as char serialize-name "td"
.
define dataset ds serialize-name "table" for ttparts .
define buffer bupart for ttparts.
create bupart.
assign
bupart.part_id = "one"
bupart.customer = "A"
.
create bupart.
assign
bupart.part_id = "two"
bupart.customer = "B"
.
def var lcc as longchar no-undo.
dataset ds:write-xml( "longchar", lcc, true ).
message string( lcc ).
https://abldojo.services.progress.com:443/#/?shareId=5d1618c14b1a0f40c34b8bc8
An updated version which accepts any temp-table handle and will return a longchar containing the HTML table:
function createHtmlTable returns longchar (
i_ht as handle
):
def var lcc as longchar.
def var hds as handle.
def var hb as handle.
def var ic as int.
create dataset hds.
hds:serialize-name = "table". // not needed if stripped below
create buffer hb for table i_ht.
hb:serialize-name = "tr".
hds:add-buffer( hb ).
do ic = 1 to hb:num-fields:
hb:buffer-field( ic ):serialize-name = "td".
end.
hds:write-xml( "longchar", lcc, true ).
// remove xml declaration
lcc = substring( lcc, index( lcc, "<", 2 ) ).
entry( 1, lcc, ">" ) = "<table". // see comment above
return lcc.
finally:
delete object hds.
end finally.
end function.
define temp-table ttparts
field part_id as char
field customerPartID as char
field customer as char
.
define buffer bupart for ttparts.
create bupart.
assign
bupart.part_id = "one"
bupart.customer = "A"
.
create bupart.
assign
bupart.part_id = "two"
bupart.customer = "B"
.
message string( createHtmlTable( temp-table ttparts:handle ) ).
https://abldojo.services.progress.com/#/?shareId=5d1760d84b1a0f40c34b8bcd
There is no built-in method to do this. One way that I could think of is converting the temp table to json and then json to HTML. I believe there are several utilities to convert json to html table. You can convert temp table to json in ABL using WRITE-JSON method.
An example from Progress documentation:
DEFINE VARIABLE cTargetType AS CHARACTER NO-UNDO.
DEFINE VARIABLE cFile AS CHARACTER NO-UNDO.
DEFINE VARIABLE lFormatted AS LOGICAL NO-UNDO.
DEFINE VARIABLE lRetOK AS LOGICAL NO-UNDO.
DEFINE TEMP-TABLE ttCust NO-UNDO LIKE Customer.
/* Code to populate the temp-table */
ASSIGN
cTargetType = "file"
cFile = "ttCust.json"
lFormatted = TRUE.
lRetOK = TEMP-TABLE ttCust:WRITE-JSON(cTargetType, cFile, lFormatted).

Display dynamic number of fields

I'm new to progress and I'm trying to learn dynamic queries. As a Task I gave to myself I want to read a csv file and create a table based on the contents of said file. So far everything works but I can't really seem to find a way to display the contents properly.
I have a temp-table created based on a csv input with the first line being the columns or fields of the table and everything after being the records.
Field1,Field2,Field3,Field4,Fieldn...
Value1.1,Value2.1,Value3.1,Value4.1,Valuen.1...
Value1.2,Value2.2,Value3.2,Value4.2,Valuen.1...
Value1.3,Value2.3,Value3.3,Value4.3,Valuen.1...
Value1.4,Value2.4,Value3.4,Value4.4,Valuen.1...
etc...
How can I display a dynamic number of fields and their names properly?
The following things are unknown:
Number of fields
Name of fields
Values of records
The following works and shows the data in the desired format (but it's hard coded):
DO WHILE qMyTable:GET-NEXT():
DISPLAY
bMyTable:BUFFER-FIELD(1):BUFFER-VALUE LABEL 'PK'
bMyTable:BUFFER-FIELD(2):BUFFER-VALUE LABEL 'Field1'
bMyTable:BUFFER-FIELD(3):BUFFER-VALUE LABEL 'Field2'
bMyTable:BUFFER-FIELD(4):BUFFER-VALUE LABEL 'Field3'
bMyTable:BUFFER-FIELD(5):BUFFER-VALUE LABEL 'Field4'
WITH FRAME f DOWN.
DOWN WITH FRAME f.
END.
I'm trying to loop over the buffer fields but I can't find a way to do it without redefining the DISPLAY command every iteration. Also I don't know how to display the labels of the fields in as a header row.
I'm looking for something like this :
/*
This doesn't work
*/
DO WHILE qMyTable:GET-NEXT():
DO i = 1 to iNumFields:
DISPLAY bMyTable:BUFFER-FIELD(i):BUFFER-VALUE LABEL cTitlerow[i].
END.
END.
This would be the full code:
/*
Variables
*/
DEF VAR i AS INTEGER INITIAL 0 NO-UNDO. //Counter
DEF VAR iEntry AS INTEGER INITIAL 0 NO-UNDO. //Counter2
DEF VAR cTitleRow AS CHARACTER NO-UNDO. //Fields csv
DEF VAR cDataRow AS CHARACTER NO-UNDO. //Entries csv
DEF VAR cFieldName AS CHARACTER NO-UNDO. //Field
DEF VAR iNumFields AS INTEGER NO-UNDO. //Amount of Fields
DEF VAR iNumLines AS INTEGER NO-UNDO. //Amount of records
DEF VAR cTitleArray AS CHARACTER EXTENT NO-UNDO. //Fields Array
/*
Handles
*/
DEF VAR ttMyTable AS HANDLE NO-UNDO. //Temp table
DEF VAR bMyTable AS HANDLE NO-UNDO. //Buffer
DEF VAR qMyTable AS HANDLE NO-UNDO. //Query
INPUT FROM 'C:\Path\To\CSV\mycsv.csv'.
/*
Get first row for fields and field names
*/
IMPORT UNFORMATTED cTitleRow.
iNumFields = NUM-ENTRIES(cTitleRow) + 1. //Additional field for PK
EXTENT(cTitleArray) = iNumFields.
/*
Dynamic table creation
*/
CREATE TEMP-TABLE ttMyTable.
ttMyTable:ADD-NEW-FIELD('PK', 'integer').
cTitleArray[1] = 'PK'.
DO i = 2 to iNumFields:
iEntry = i - 1.
cFieldName = ENTRY(iEntry,cTitleRow).
ttMyTable:ADD-NEW-FIELD(cFieldName, 'character').
cTitleArray[i] = cFieldName.
END.
/*
Adding and defining indexes
*/
ttMyTable:ADD-NEW-INDEX('idx', TRUE, TRUE).
ttMyTable:ADD-INDEX-FIELD('idx', 'PK', 'asc').
ttMyTable:TEMP-TABLE-PREPARE('myTable').
/*
Creating buffer
*/
bMyTable = ttMyTable:DEFAULT-BUFFER-HANDLE.
/*
Populating data
*/
REPEAT:
IMPORT UNFORMATTED cDataRow.
bMyTable:BUFFER-CREATE.
bMyTable::pk = iNumLines.
DO i = 2 to iNumFields:
iEntry = i - 1.
bMyTable:BUFFER-FIELD(i):BUFFER-VALUE = ENTRY(iEntry,cDataRow).
bMyTable:BUFFER-FIELD(i):COLUMN-LABEL = cTitleArray[i].
bMyTable:BUFFER-FIELD(i):LABEL = cTitleArray[i].
END.
iNumLines = iNumLines + 1.
END.
/*
Creating query
*/
CREATE QUERY qMyTable.
qMyTable:SET-BUFFERS(bMyTable).
qMyTable:QUERY-PREPARE('for each myTable').
qMyTable:QUERY-OPEN().
/*
/*
This doesn't work
*/
DO WHILE qMyTable:GET-NEXT():
DO i = 1 to iNumFields:
DISPLAY bMyTable:BUFFER-FIELD(i):BUFFER-VALUE.
END.
END.
*/
DO WHILE qMyTable:GET-NEXT():
DISPLAY
bMyTable:BUFFER-FIELD(1):BUFFER-VALUE LABEL 'PK'
bMyTable:BUFFER-FIELD(2):BUFFER-VALUE LABEL 'Field1'
bMyTable:BUFFER-FIELD(3):BUFFER-VALUE LABEL 'Field2'
bMyTable:BUFFER-FIELD(4):BUFFER-VALUE LABEL 'Field3'
bMyTable:BUFFER-FIELD(5):BUFFER-VALUE LABEL 'Field4'
WITH FRAME f DOWN.
DOWN WITH FRAME f.
END.
qMyTable:QUERY-CLOSE().
DELETE OBJECT qMyTable.
I think you only might have some frame issues. Your code should basically work.
This minor change with display your data but for it will display them all in one column.
DO WHILE qMyTable:GET-NEXT():
DO i = 1 to iNumFields:
DISPLAY bMyTable:BUFFER-FIELD(i):BUFFER-VALUE WITH FRAME f2 DOWN TITLE "Dynamic" .
DOWN WITH FRAME f2 .
END.
END.
So output will basically be
row1column1
row1column2
row1column3
...
row1columnN
row2column1
row2column2
row2column3
...
row2columnN
etc
Instead of
row1column1 row1column2 row1column3 ... row1columnN
row2column1 row2column2 row2column3 ... row2columnN
One idea to get the same result is to create a frame widget dynamically as well...
I'd do it this way. It would show the field value next to its name, and one record at a time. I hope this helps:
DO WHILE qMyTable:GET-NEXT():
DO i = 1 to iNumFields:
DISPLAY bMyTable:BUFFER-FIELD(i):NAME
bMyTable:BUFFER-FIELD(i):BUFFER-VALUE LABEL cTitlerow[i] WITH FRAME f DOWN.
DOWN WITH FRAME f.
END.
CLEAR FRAME f ALL.
END.
This should get you started on creating a frame and a "text" widgets dynamically:
define variable f as handle no-undo.
define variable t as handle no-undo.
define variable r as integer no-undo initial 1.
define variable c as integer no-undo initial 1.
create frame f.
assign
f:row = 4
f:column = 1
f:width-chars = 132
f:box = no
f:top-only = false
f:overlay = true
f:name = "something"
no-error.
create text t.
assign
t:frame = f
t:name = "text1"
t:format = substitute( "x(&1)", max( 1, 20, length( t:name )))
t:row = r
t:col = c
t:screen-value = "value1"
f:height-chars = max( r, f:height-chars )
.
f:visible = yes.
In your case you would probably want to create the frame just once at the top and then create 2 text widgets for each field - one for the label and one for the data values.

Dynamic Query in OpenEdge

Good day:
Quick question: Can I perform a dynamic query in OpenEdge?
Example:
def temp-table tt-num1
field f1 as int
field f2 as int.
def temp-table tt-num2
field f1 as int
field f2 as int.
def temp-table tt-num3
field f1 as int
field f2 as int.
What I need is something that looks like this:
procedure repeat-query:
for each 'variable that contains table-name' no-lock.
disp f1 f2.
end.
end procedure.
or some other way that can solve my problem.
How do I proceed with this? I tried to check for dynamic query on the Internet but with no luck. Thanks in advance.
If you go directly to https://documentation.progress.com/#page/progdocindex%2Fopenedge.html you can find documentation around everything OpenEdge. For instance dynamic queries.
I don't understand exactly what you try to do but here's an example of a dynamic query.
DEFINE TEMP-TABLE tt-num1 NO-UNDO
FIELD f1 AS INTEGER
FIELD f2 AS INTEGER.
DEFINE TEMP-TABLE tt-num2 NO-UNDO
FIELD f1 AS INTEGER
FIELD f2 AS INTEGER.
DEFINE TEMP-TABLE tt-num3 NO-UNDO
FIELD f1 AS INTEGER
FIELD f2 AS INTEGER.
CREATE tt-num1.
ASSIGN
tt-num1.f1 = 1
tt-num1.f2 = 1.
CREATE tt-num1.
ASSIGN
tt-num1.f1 = 1
tt-num1.f2 = 2.
CREATE tt-num1.
ASSIGN
tt-num1.f1 = 2
tt-num1.f2 = 1.
CREATE tt-num1.
ASSIGN
tt-num1.f1 = 2
tt-num1.f2 = 2.
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE cBuffer AS CHARACTER NO-UNDO.
DEFINE VARIABLE cField AS CHARACTER NO-UNDO.
DEFINE VARIABLE iValue AS INTEGER NO-UNDO.
ASSIGN
cBuffer = "tt-num1"
cField = "f1"
iValue = 1.
CREATE QUERY hQuery.
hQuery:ADD-BUFFER(cBuffer).
hQuery:QUERY-PREPARE("for each " + cBuffer + " where " + cBuffer + "." + cField + " = " + STRING(iValue)).
hQuery:QUERY-OPEN().
queryLoop:
REPEAT:
hQuery:GET-NEXT().
IF hQuery:QUERY-OFF-END THEN LEAVE queryLoop.
DISPLAY hQuery:GET-BUFFER-HANDLE(1):BUFFER-FIELD(cField):BUFFER-VALUE.
END.
hQuery:QUERY-CLOSE().
DELETE OBJECT hQuery.
As Stefan Drissen mentions in a very valid comment: the loop can be more compact:
DO WHILE hQuery:GET-NEXT():
/* Code goes here */
END.

Resources