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. This means that these objects cannot use the requested fields after the query transaction has been executed. So, if you would use these fields in your form or global routine before the table query is executed, you will receive an error message at runtime. |
||||||||||||||||||||||||||
|
<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. Depending on the NULL values property setting, a field may be given the value null, like in the examples below. The null can not be used inside an operation. Examples: |
||||||||||||||||||||||||||
|
<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. The <numrows> parameter must be a non-negative integer literal. 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: |
||||||||
| 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 ). The .FIND option cannot be used in combination with .GETFIRST or LOOP <Tabelequery>. Example: |
||||||||
|
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 be 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. When the index specifier is set to 'NONE', no index will be used and the database server has to find the optimal path for returning the results. 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>) <Table query>.INDEX (<Indexname>, KEYONLY) <Table query>.INDEX (LOCKED)<Table query>.INDEX (<Indexname>, LOCKED) <Table query>.INDEX (<Indexname>, LOCKED, KEYONLY) <Table query>.INDEX (NONE) <Table query>.INDEX (NONE, LOCKED)Example: |
||||||||
|
INSERT |
Inserts the given values into the table. This function together with the assignment of a buffer content to a table query and the deletion of the buffers content afterwards, can be written as a single instruction. See also the examples A & B below, which are similar as are examples C & D: |
||||||||
| 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: |
||||||||
| 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. This means that it is possible that after the database values have been read by the query, even though the database has been updated by a different query, the memory buffer values of the query have not changed and thus no update will be performed on the database. It is therefore recommended not to update the same record by multiple queries or alternatively reread the potentially changed record before updating.
|
||||||||
|
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. It is not allowed to use array items of tables in the where clausule. Syntax: 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. After a commit, the next record is retrieved by re-executing the query with the current record as start values. Find/Find(Next) options are not supported in combination with WhereFreeSql. 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: |
||||||||
Examples:
(A)
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