Table Queries
Table queries are used to select entire records out of a table. The easiest way to create table queries is to use the code wizard. This wizard can be called when the implementation screen for your object is opened.
A table query can be defined with the following syntax:
<Table query> : Tablequery ( [<Application>.]<Table> )
With one of the two following syntaxes the values from the query specified on the right are assigned to the query on the left of the assign function (:=). The difference is in the copying of the lionrecno.
1. <Table query>.* := <Table query>.*
All fields are copied except lionrecno
2. <Table query> := <Table query>
In this case all fields are copied, including lionrecno.
Table query functions can be used as follows:
<Table query>.<Function> ( <Function parameters> )
Field assignments can be written as follows:
<Table query>.<Fieldname> := <Expression>
The resultset of a query can be filtered by using the WHERE function.
There are two possibilities to read the result set of a query:
- Using GETFIRST in combination with LOOP...ENDLOOP. The GETFIRST function is used to perform a reading action on the first record from the table. The result set of the query (which consists of one or more records) is read within a loop, using LOOP...ENDLOOP.
- Using FIND (FIRST | NEXT) in combination with FINDNEXT.
These two possibilities must not be intermixed!!
Note: While the mixing of both possibilities used inside the same object (a form, report, etc) will result in an error when validating, this is not the case when using insertables or global routines. When using a query across multiple objects, the programmer must take care that only one of the two read methods is being used.
Table query instructions can be simplified by using the WITH command, which is useful if multiple actions are performed on a single object.
When reading a field with a null value (meaning that the field is empty), spaces or zero will be returned (depending on the field type). To test if a field is really null, a condition can be written with either "=" or "<>". Other operators with null are not allowed, and the null may only be written on the right side.
Besides defining table queries in the Local Definition, it is also possible to define table queries as a Global Definition. |
Syntax description
Item | Description | ||||||||||||||||||||||||||
<Application> |
Name of the external application that contains the requested table. In the Control Center, this application name has to be specified and linked to the required ODBC-settings (see also the Administration Manual). Omit this option if you do not need to refer to an external table in your query. To use this option, it is needed that the external application uses the same repository as the calling application. The generation options for both applications are expected to be set equally. If for the external application (object) a generation set is available with the same name as
for the calling application, then the revision for that generation set will be used. In all
other cases, always the newest revision that is available will be used (disregarding the
generation sets).
At runtime there are two different procedures for the handling of "external table queries".
The external connection for a report is established in its start up procedure. For forms and
global routines, the connection is made only after the first performance of the query.
|
||||||||||||||||||||||||||
<Fieldname> |
Fieldname within the table query. | ||||||||||||||||||||||||||
<Expression> |
Expression, returning the value for the indicated table field. This expression may also be
a reference to another fieldname. Examples:
(A)
qtb1A.field1 := null qtb1A.insert () (B) qtb1A.field1 := null qtb1A.update (field1) (C) qtb1A.field1 := null + 'abc' // This is not allowed |
||||||||||||||||||||||||||
<Function> |
Function (listed below) that applies to the table query. | ||||||||||||||||||||||||||
<Function parameters> |
Specification of the parameter values to be used by the Table query function. In the description of the concerned function, you can read if a specification is required and what kind of values are then expected. | ||||||||||||||||||||||||||
<Table> |
Name to identify the table on which the selection applies. | ||||||||||||||||||||||||||
<Table query> |
Name to identify the table query. |
Functions
Name | Description | ||||||||
CLEAR |
Deletes all values from the query except Lionrecno, Lionmodifieddate, Lionmodifiedtime, Lioncreateddate and Lioncreatedtime. Clear is always followed by parentheses. No information is specified between those parentheses. |
||||||||
DELETE |
Deletes the data record that is most recently read within the query. |
||||||||
EQUAL |
Assigns the index key to the record that is specified between parentheses. |
||||||||
FETCHROWS |
By default, AMT will fetch increasingly more rows when doing a select query on the database to optimize performance. For database queries where the result set size is already known, this default behaviour can be changed with this function by setting the number of rows which should be fetched per run. The FETCHROWS function should be coded before the INDEX function. Setting the FETCHROWS function to 0
(zero) will reset it, re-enabling the default behavior. Please note that this function will not limit the number of rows in a result set, it is only related to performance between AMT and the database. The default behaviour gives a good general performance, this function should therefore only be used in cases where there are specific performance issues.
Syntax: <tablequery>.FETCHROWS (<numrows>) Example:
qtest.fetchrows (250)
qtest.index (index-abc) loop qtest .. endloop |
||||||||
FIND |
A FIND with the suboption FIRST, always returns a new result set (which is not influenced by any previous retrievals). If there is already a query started through the same index that uses the same variable(s) as is/ are requested in the FIND (FIRST) command, that query will be closed automatically. When using the suboption NEXT, you have to specify also the .INDEX, .EQUAL, .START and .WHERE. Unless the values for inquiry through the index have changed, the behavior for the FIND(NEXT) is the same as for the FINDNEXT. If the values for the inquiry through the index have changed, the FIND(NEXT) option will be considered as a FIND(FIRST). The suboption has to be specified between (), so the syntax
becomes: <Tablequery>.FIND ( FIRST|NEXT ). Example:
loop
qtest.index (index-abc) qtest.equal (sa-key) qtest.start (0, 0) qtest.find (next) { The returning of any next value and the comparing of the keys is based on the actual value for the result set for the indec INDEX-ABC.} if not resok then break .. if sa-restart = 'Y' sa-key := 'NEXT KEY' // Next loop iteration starts a new query endif endloop |
||||||||
FINDNEXT |
Fetches the next value, based on the previous inquiry on the same index. This option can only be used in combination with FIND (FIRST | NEXT). The actual value for the specified inquiry on the index is always maintained. This means that also if the same index is read again, the starting value will be set according to the previous inquiry on the index and the found value will added to the same result set. In difference with the option FIND(NEXT), a FINDNEXT will not be executed as a FIND(FIRST) in case of a change in one of the inquiry values that are specified for the index. If there is a change in one of these values, the FINDNEXT will continue based on these new specifications. |
||||||||
FINDRESTART |
Makes sure that the next FIND (NEXT) is always regarded to be a FIND (FIRST). |
||||||||
GETFIRST |
Fetches the first record from the result set and closes the result set. |
||||||||
INDEX |
Selects the index used to retrieve records from the database. The key values are set using both
the EQUAL and the START function. To scan on the table,
you have to specify the INDEX with empty parentheses (e.g. qPARAM.INDEX () ). In that case, the
EQUAL and START properties do not apply. If you use the suboption "LOCKED", the record will be locked at the moment that it is read by the Table query. In difference with the LOCKED function, the next commands that refer to the same table query will not automatically) lock the requested records. Permitted syntaxes: <Table query>.INDEX () <Table query>.INDEX (<Indexname>, KEYONLY)
<Table query>.INDEX (LOCKED) <Table query>.INDEX
(<Indexname>,
LOCKED, KEYONLY) <Table query>.INDEX (NONE) <Table query>.INDEX (NONE, LOCKED)
qtest.index (index-abc, locked)
|
||||||||
INSERT |
Inserts the given values into the table.
(A)
icust.insert () qcust := icust icust.clear () (B) icust.insert (qcust, clear) (C) icust.insert () icust.clear () (D) icust.insert (clear) |
||||||||
ISOLATION |
Specifies under which isolation level the following queries (using this table query) will be read. |
||||||||
Syntax:
|
|||||||||
KEYONLY |
Reads only the keys of the <Index> and Lionrecno, which results in a faster execution. In contrast to Cursor Queries the remaining fields retain are blank/zero |
||||||||
LOCKED |
Locks the records at the time that another request for those records is done by using the same Table query variable. So, these records will also be locked if these table queries are not executed directly after the LOCKED function is set for these table queries. If the LOCKED function is used inside a report, every table query that uses the same variable causes a lock of the records throughout the program. If this function is used inside a form, these next table queries will lock the records only until the screenresults have been sent to the user. So, in that case this function only influences the table queries that are encountered before the end of the sections Display_main or Process_main or before the end of the event routine. Concurrent transactions only have rights to read the locked records. To avoid loss of performance or eventual occurrences of deadlock situations that may be caused when the same records are also requested through other transactions, you might want to release the lock with a COMMIT or SAVERECOVERYNAME. For the same reason, you might also consider using the .INDEX suboption "LOCK" where this is possible. In difference with the .LOCKED, this suboption will not place a lock for next requests that use the same Table query variable. |
||||||||
Directs result status of a command to the specified boolean or alphanumeric (length 5) variable (instead of using the system item RESOK). |
|||||||||
RETAINPTR |
If set to "TRUE", the pointer position for the opened table will be retained. So, if this would be done in a loop and that loop has been executed before, AMT will continue reading the next record when that loop is executed again. If set to false, the pointer will be reset to its previous position. Example: loop
for ldg-occurence := 1 to 10
if ldg-occurrrence = 1 qvweur.retainptr (false) // Reset previous result endif qvweur.index (fvweur) qvweur.start ('') qvweur.retainptr (true) // Keep result set open loop qvweur break endloop if resok then <record found action> else <no records found anymore action> endloop |
||||||||
SETPARAMALPHA |
Sets a WhereFreeSQL parameter of type Alpha defined in <ParamName> to the given <AlphaValue> or NULL. Syntax: <tablequery>.SETPARAMALPHA ( <ParamName>,
<AlphaValue> ) |
||||||||
SETPARAMBOOLEAN |
Sets a WhereFreeSQL parameter of type Boolean defined in <ParamName> to the given <BooleanValue> or NULL. Syntax: <tablequery>.SETPARAMBOOLEAN ( <ParamName>, <BooleanValue> ) |
||||||||
SETPARAMDATE |
Sets a WhereFreeSQL parameter of type Date defined in <ParamName> to the given <DbsDateValue> or NULL. Syntax: <tablequery>.SETPARAMDATE ( <ParamName>, <DbsDateValue> ) |
||||||||
SETPARAMDATETIME |
Sets a WhereFreeSQL parameter of type DateTime defined in <ParamName> to the given <DbsDateTimeValue> or NULL. Syntax: <tablequery>.SETPARAMDATETIME ( <ParamName>, <DbsDateTimeValue> ) |
||||||||
SETPARAMINTEGER |
Sets a WhereFreeSQL parameter of type Integer(64) defined in <ParamName> to the given <IntegerValue> or NULL. Syntax: <tablequery>.SETPARAMINTEGER ( <ParamName>, <IntegerValue> ) |
||||||||
SETPARAMNUMERIC |
Sets a WhereFreeSQL parameter of type Numeric defined in <ParamName> to the given <NumericValue> or NULL. Syntax: <tablequery>.SETPARAMNUMERIC ( <ParamName>, <NumericValue> ) |
||||||||
SETPARAMSTRING |
Sets a WhereFreeSQL parameter of type String defined in <ParamName> to the given <StringValue> or NULL. Syntax: <tablequery>.SETPARAMSTRING ( <ParamName>, <StringValue> ) |
||||||||
SETPARAMTIME |
Sets a WhereFreeSQL parameter of type Time defined in <ParamName> to the given <DbsTimeValue> or NULL. Syntax: <tablequery>.SETPARAMTIME ( <ParamName>, <DbsTimeValue> ) |
||||||||
START |
Defines the starting point from which the records are read. This function is always preceded by the EQUAL function. To read backwards, you type "START DESC". | ||||||||
UPDATE |
Updates the specified fields to the assigned values. To update all fields, use the * operand. E.g. qPARAM.UPDATE (*). To increase performance, AMT will only update a field when the value in the memory buffer of the
query has been changed.
|
||||||||
WHERE |
Sends an extra condition to the database server. By using this option, the table data will be filtered by the database server. Since the AMT application receives only the results for the condition and therefore does not have to filter the data itself, the performance of the application will increase. The WHERE instruction supports the
operators
=, <>, <, >, <=, >=, NOT, AND, OR, IN and LIKE. The
supported functions for this clause are LEFT, LOWER, RIGHT, SUBSTRING and UPPER. Syntax: <Table query>.WHERE ( <Condition> ) See also example H. |
||||||||
WHEREFREESQL |
WhereFreeSql is an advanced function is for writing complex subselections which are not possible with the Tablequery Where function. To write and validate correct SQL is the responsibility of the developer. The statement string needs to be correct SQL that can be added to an existing WHERE statement which is already created for the equal/start/where functions. When using WhereFreeSql, records are not retrieved in block mode anymore. Meaning that when you do
not process all the records, or when you have commits inside the loop, the performance might be
impacted in a negative way due to the plans generated for the query by the SQL engine. Syntax: <tablequery>.WHEREFREESQL(<SqlWhereString>) Parameters: Parameters can be defined as @paramname or :paramname depending on the target database. Unlike a 'Free Join Query' the SQL statement does not support ? for parameters.
Example:
tq.index(index02)
tq.equal('K1', 'K2') tq.start(3,4) tq.where (tq.maint <> 'D') tq.wherefreesql('value2 in (select val from tablex where field2 = @val1 or field3 = @val2)') tq.setparamalpha('@val1', 'NL') tq.setparaminteger('@val2', 12) loop tq ... endloop
|
Examples:
qdeair.index (fdeair)
qdeair.equal (qautec.dealer)
qdeair.resultokto (ga-status)
qdeair.getfirst ()
itrptd.clear ()
itrptd.adres := qdeair.adres
itrptd.icode := qdeair.postcode
itrptd.insert ()
tr-sa-rayon := ''
tr-sn-nklsw := 0
(B)
qallwd.index (proallwdm)
qallwd.equal (gw-userco)
qallwd.start (gw-menu, '')
(C)
sn-total := 0
qaevrd.index (proaevrdo)
qaevrd.equal (qaondl.ondcode)
loop qaevrd
sn-total := sn-total + qaevrd.vrrdamount
endloop
(D)
qtrptt.index (protrptt)
qtrptt.equal (code)
loop qtrptt
qtrptt.meent := gac-d
qtrptt.veldb := velda
qtrptt.update (meent, veldb)
break
endloop
(E)
qwakeup.clear ()
qwakeup.date := today.ccyymmdd
qwakeup.time := today.hhmmssnn
qwakeup.report := 'PRIBONN'
qwakeup.insert ()
(F)
qparam.index (fparam)
qparam.equal (gac-marap)
qparam.locked ()
qparam.getfirst ()
(H)
qtest.index (i_sub1)
qtest.where (gtest.lionrecno >= currecno)
qtest.find (first)
display_2 := qtest.sub1
(I)
loop for j := 1 to 2
{ The loops below will be entered twice.
Both loops us a different index on the same table.
The table contains all alfabet values (A..Z). The index
I_SUB_ASC uses an ascending key. The index I_SUB_DSC uses
a descending key. Ther is no retrieval through
these indexes outside the main loop. }
loop for i := 1 to 3
qtest.index (i_sub_asc)
qtest.start ('B')
qtest.find (next)
endloop
{ The first time this loop is entered (for j = 1)
the result set will contain the values: B, C, D.
The second time this loop is entered (for j = 2)
the NEXT will continue with the same result set.
This means that the result set will continue
with the values: E, F, G. }
loop for i := 1 to 3
qtest.index (i_sub_dsc)
qtest.start ('Z')
qtest.find (next)
endloop
{ Because the result sets are maintained per index, the
previous loop (which performed a retrieval through index
I_SUB_ASC), does not have any influence on this loop
(which does a retrievel through the index I_SUB_DSC).
Because the key for I_SUB_DSC is set desecnding,
the retrieval starts with the value Z. At the first
execution (j = 1), the result set for this loop will
contain the values: Z, Y, X.
At the second execution of this loop (j = 2), the
values W, V, U will be added to this result set. }
endloop