Returning to a text field block again from the query - progress-4gl

I have a form that prompt for customer name and pass that value to a query,
FORM compname
customer.cusname
WITH FRAME f1.
UPDATE compname WITH FRAME f1.
This form wil pass the compname value to the following query,
FOR EACH customer WHERE customer.name = compname NO-LOCK :
if available(company) then
do:
CREATE temptt.
assign temptt.num = customer.kco
temptt.no = string(customer.kco)
temptt.name = customer.name
temptt.status = false.
END.
else
message "not matched " view-as alert-box.
end.
What i want to do is, if search does not receive any rows, it should again prompt for customer name. what should i do for this ??
how do i call that form again in the "else block" and also, currently I am giving the complete name in the field, but i want to give part of the name, for eg., customer name is "John Smith Doe" and if i input "Smith" it should retrieve the related rows. How should i alter the "Where" clause for this ?? Please help me.

Repeating the search
This can be done in several ways. Here's one example:
DEFINE TEMP-TABLE customer NO-UNDO
FIELD cusname AS CHARACTER
FIELD num AS INTEGER.
DEFINE VARIABLE compnum AS INTEGER NO-UNDO.
DEFINE VARIABLE compname AS CHARACTER NO-UNDO.
DEFINE QUERY qSearch FOR customer.
FORM compname compnum WITH FRAME f1.
/* Create some bogus data */
CREATE customer.
ASSIGN customer.cusname = "john doe"
customer.num = 1.
CREATE customer.
ASSIGN customer.cusname = "jane doe"
customer.num = 2.
CREATE customer.
ASSIGN customer.cusname = "name name"
customer.num = 3.
loop:
REPEAT:
CLEAR FRAME f2 ALL.
UPDATE compname compnum WITH FRAME f1.
/* Quit if neither name or number is entered */
IF compname = "" AND compnum = 0 THEN
LEAVE loop.
/* If num is entered - search by it, otherwise by name */
IF compnum <> 0 THEN DO:
OPEN QUERY qSearch FOR EACH customer NO-LOCK WHERE customer.num = compnum.
END.
ELSE DO:
OPEN QUERY qSearch FOR EACH customer NO-LOCK WHERE customer.cusname MATCHES "*" + compname + "*".
END.
GET NEXT qSearch.
DO WHILE AVAILABLE customer:
IF AVAILABLE customer THEN DO:
DISPLAY customer WITH FRAME f2 10 DOWN.
DOWN WITH FRAME f2.
END.
GET NEXT qSearch.
END.
/* If we have results - leave the loop otherwise try again */
IF QUERY qSearch:NUM-RESULTS = 0 THEN
LEAVE loop.
END.
MESSAGE "Quitting" VIEW-AS ALERT-BOX.
Searching for part of the name
There are a couple of operators for matching strings:
BEGINS
Tests a character expression to see if that expression begins with a second character expression.
Syntax:
expression1 BEGINS expression2
Example:
FOR EACH customer WHERE NO-LOCK customer.cusname BEGINS "john":
MATCHES
Compares a character expression to a pattern and evaluates to a TRUE value if the expression satisfies the pattern criteria.
The pattern can contain wildcard characters: a period (.) in a particular position indicates that any single character is acceptable in that position; an asterisk (*) indicates that any group of characters is acceptable, including a null group of characters.
Syntax:
expression1 MATCHES expression2
Example:
FOR EACH customer NO-LOCK WHERE customer.cusname MATCHES "*doe*":
MATCHES sounds like what you're after but be adviced: MATCHES will not utilize indices in the database so whole tables will be scanned. This can/will effect performance and possibly make your queries take long time.
The WHERE clause above replaced with MATCHES would look something like this:
FOR EACH customer NO-LOCK WHERE customer.cusname MATCHES "*" + compname + "*":
CONTAINS
There's also a third operator called CONTAINS that uses something called a WORD index. That will require you or your DBA to create these kind of indices in the database first. Read more about word indices and CONTAINS in the online help or in the PDF found here: Progress ABL Reference (page 1004).
CONTAINS is probably a better idea than MATCHES but will require you to make changes to your database as well.

Related

how to List the top ten customers form the given start date with greater cost/price of orders using progress 4gl

a single customer could have multiple orders and corresponding cost.
now the cost/price has to be added and according to the max price the customer's should be displayed.
i have just written the skeleton of the prog , please help me.
define temp-table ttorder
field ocust-num like order.cust-num
field oorder-num like order.order-num.
define variable i as int.
define variable a as int.
define temp-table ttorderln
field oprice like order-line.price.
for each order where order-date > 01/08/93 /*by cust-num*/ .
create ttorder .
assign
ttorder.ocust-num =cust-num
ttorder.oorder-num = order-num.
for each order-line where order-line.order-num = ttorder.oorder-num break by ocust-num.
i = order-line.price.
a = i + a.
/* display cust-num order-num a. */
if last-of (ttorder.ocust-num) then
do:
create ttorderln.
ttorderln.oprice=a.
end.
display ttorderln.
end.
end.
If you're looking for the top customers, you should use a temp table based on customers, not orders. Go through the orders and order lines, accumulating the amounts by customer.
define temp-table ttcust
field cust-num like order.cust-num
field order-tot as decimal
index idx1 cust-num
index idx2 order-tot.
define variable i as integer.
for each order where order-date > 01/08/93:
/* Find or create a customer temp record. */
find first ttcust where ttcust.cust-num = order.cust-num no-error.
if not available(ttcust) then
do:
create ttcust.
ttcust.cust-num = order.cust-num.
end.
/* Add up the order lines. */
for each order-line where order-line.order-num = order.order-num no-lock:
ttcust.order-tot = ttcust.order-tot + order-line.extended-price.
end.
end.
/* Display the top 10. */
for each ttcust by order-tot descending:
i = i + 1.
message "Cust: " ttcust.cust-num skip
"Total: " ttcust.order-tot view-as alert-box.
if i >= 10 then leave.
end.

How to search and display the fields from a table in an editor widget using progress 4gl

Accept a customer number and then output the details of each order and items to an editor widget.
Here customer , order ,order-line and items are table names.
where as customer and order tables have cust-num as common field , order and order-line(table-name) and order have order-num as common field , order-line and item have item-num as common field.
now i have to use a fill-in (f1 is object name) to get the cust-num and use a search button (search1 as object name) to find the corresponding fields and display them in the editor widget ( editor-1 as object name).
define temp-table ttcustomer
field custnum like customer.cust-num
field cname like customer.name
field orders like order.order-num
field items like item.item-num
field itemname like item.item-name .
find first customer WHERE customer.cust-num = input f1 NO-LOCK .
create ttcustomer .
assign
ttcustomer.custnum = customer.cust-num
ttcustomer.cname = customer.name.
for each order WHERE Order.cust-num = input f1 NO-LOCK .
assign
ttcustomer.orders = order.order-num.
for each order-line where order-line.order-num = order.order-num no-lock.
for each item where item.item-num = order-line.item-num no-lock.
assign
ttcustomer.items = item.item-num
ttcustomer.itemname = item.item-name.
end.
end.
end.
i have written this code in search button .
how can i display the temp-table ttcustomer in editor widget please help me :)
You'd probably be better off using a browser instead of an editor. But if you are going to use an editor, this should give you what you need:
DEFINE VARIABLE edData AS CHARACTER NO-UNDO.
FOR EACH ttcustomer:
edData = edData + ttcustomer.items + ", " + ttcustomer.itemname + CHR(10).
END.
editor-1:SCREEN-VALUE = edData.
The editor is just text so you won't be able to do any record selection/manipulation like you can with a browser. And if you have many ttcustomer records, you run the risk of overflowing the 32k character string size limit.

Pulling variable length substring from middle of string

I am trying to grab variable length string from a primary string.
Example:
ABC*12*1*name name****XX*123456789~
ABC*12*1*diffname diffname****XX*234567890~
ABC*12*1*diffname2 diffname2***XX*345678901~
I need to pull out the 'name name', 'diffname diffname', 'diffname2 diffname2'
etc from the string. And then replace the ' ' between the names with an asterisk - but, I cant just insert in the first space in the string, there could be multiple names, and so I would want to insert the '*' into the second, or third space, depending on the length of the name string.
SELECT
CHARINDEX('*1*',data)+3 AS startpos,
CHARINDEX('***',data) AS Endpos,
data
from #t
where data like '%ABC*12*1*%'
This gives me a start point and end point for the variable length string. So I try:
SELECT SUBSTRING(data,CHARINDEX('*1*',data)+3,CHARINDEX('***',data) -CHARINDEX('*1*',data)+3)
FROM #t
WHERE data like '%ABC*12*1*name%'
But this gives me
name n name aa*****X
as a result set, basically starting at the start point and then running well past the end point.
What am I doing wrong?
This part is the problem :
SELECT .....-CHARINDEX('*1*',data)+3
FROM .....
WHERE .....
You want to substract with Endpos so it supposed to be written in brackets like so :
-(CHARINDEX('*1*',data)+3)
and if the brackets are removed the last part should become -3 :
-CHARINDEX('*1*',data)-3

Query a database table whose name is known only at runtime

I get a database table name at run time(let us suppose from user). I need to query the table and return few fields(which I know). How to do this?
"FOR EACH" wont accept a variable name in it. So, I cant use it.
I have gone through dynamic queries, especially SET-BUFFERS() method. Even with this, I need to know the table name before.
I need something like:
DEF VAR tablename AS CHAR.
tablename = somename.
FOR EACH tablename WHERE ....:
...
...
END.
Can someone please point me to right direction?
You can do a dynamic query with a dynamic buffer. Simply replace the value of cTableName variable in this example:
/* Replace _file with whatever field you're after */
DEFINE VARIABLE cTableName AS CHARACTER NO-UNDO INIT "_file".
DEFINE VARIABLE hQuery AS HANDLE NO-UNDO.
DEFINE VARIABLE hBuffer AS HANDLE NO-UNDO.
CREATE BUFFER hBuffer FOR TABLE cTableName.
CREATE QUERY hQuery.
hQuery:SET-BUFFERS(hBuffer).
hQuery:QUERY-PREPARE("FOR EACH " + cTableName).
hQuery:QUERY-OPEN().
REPEAT:
hQuery:GET-NEXT().
IF hQuery:QUERY-OFF-END THEN LEAVE.
DISPLAY hBuffer:BUFFER-FIELD(1):BUFFER-VALUE.
/* If you know the name of the field you can do: */
/* DISPLAY hBuffer:BUFFER-FIELD("nameoffield"):BUFFER-VALUE. */
END.
/* Clean up */
hQuery:QUERY-CLOSE().
hBuffer:BUFFER-RELEASE().
DELETE OBJECT hBuffer.
DELETE OBJECT hQuery.

Centura Gupta Team Developer Automation Possibility

Is there a automation tool which can automate the software build on Team Developer (v6.0).
I have tried with multiple automation tools to spy the table object in the application, it identifies it as Gupta ChildTable. But I am not able to retrieve the values from the row.
For example:
1. I have 10 rows in the table(grid) with 12 columns. I need to find the value "AAAAA" contained in first column and select that particular row via Automation.
2. I have 10 rows in the table(grid) with 12 columns. I need to find the value "AAAAA" contained in first column and click on particular cell in that row to input the data via Automation.
Thanks in advance.
Use VisTblFindString . This function ( and many others ) are included into your TD code if include 'VT.apl' in your include libraries .
VisTblFindString will return the Row - so then you simply set context to that row using SalTblSetContext( hWndForm, nRow ) , and then you can refer to the contents of each cell by name to return the value.
Syntax
nRow = VisTblFindString(hWndTable, nStartRow, hWndColumn, sString)
Handle: hWndTable
Number: nStartRow
Number: hWndColumn
String: sString
Description
Locates a string value within a column.
The string must match exactly, but case is ignored. Searching ends when the last row in the table is checked. A SAM_FetchRow message is sent for all rows that have not yet been fetched into the cache.
You can use the pattern matching characters understood by the function SalStrScan. The percent character (%) matches any set of characters. The underscore character ( _ ) matches any single character.
Parameters
hWndTable Table window handle.
nStartRow Row number at which to start the search.
hWndColumn Handle of column to search. Use hWndNULL to search all string columns.
sString String for which to search.
Return Value
Number: The row number if sString is found, or -1 if not found.
Example:
Set nRow = VisTblFindString (twOrders, 0, colDesc, 'AAAAAA')
Call SalTblSetContext( twOrders , nRow )
( Now you can get the value of any cell in nRow by referring to the Column Name )
e.g. Set sCellValue = twOrders.colDesc or Set sCellValue = twOrders.colId etc.
Rows ( or anything what-so-ever in a TableWindow - even the cell borders , backgrounds , lines, row headers etc ) can be treat as an 'Item' or 'Object' by TeamDeveloper . Recommend you use MTbl - it is an invaluable set of add-on functions that make dealing with Tables a breeze. I know of no sites using TableWindows that don't use MTbl. In terms of rows , you can define any row as an Item or Object and manipulate it accordingly. See M!Tbl ( a TableWindows extention ) and specifically fcMTblItem.DefineAsRow( hWndTbl, nRow ).
BTW , you can also use MTbl to completely change the look and feel of your TableWindows , to give them a real modern look.
Very rough napkin code, don't have TD on this computer. Not that you can copy&paste this easily anyway due to the code structure, only line by line.
tbl1 is the name of the table, col1 is the name of the column, substitute to fit your program.
Set nRow = TBL_MinRow
While SalTblFindNextRow( tbl1, nRow, 0, 0 )
Call SalTblSetContext( tbl1, nRow )
If tbl1.col1 = "AAAAA"
Call SalTblSetFocusCell( tbl1, nRow, tbl1.col1, 0, -1 )
Break
This should run through each row, check whether col1 has the chosen value, and then activates edit mode for that cell - provided the column is editable.