DEFINE QUERY statement

Defines a query that is created at compile time for use in one or more procedures, or within a single class or class hierarchy. A query can be opened with an OPEN QUERY statement, and records can be retrieved using a GET statement, BROWSE widget, or the FILL( ) method on a ProDataSet object handle.

Syntax

DEFINE {[[ NEW ] SHARED ]|[ PRIVATE | PROTECTED ][ STATIC ]}
  QUERY query
  FOR buffer-name[field-list][ , buffer-name[field-list]]...
  [ CACHE n]
  [ SCROLLING ]
  [ RCODE-INFORMATION ]
NEW SHARED QUERY query
Defines and identifies a query to be shared with one or more procedures called directly or indirectly by the current procedure. The called procedures must define the same query name as SHARED. For shared queries, each buffer-name must be the name of a shared buffer. The shared buffers must be specified in the same order both across shared queries and in the OPEN QUERY.
SHARED QUERY query
Defines and identifies a query that was initially defined by another procedure as NEW SHARED. For shared queries, each buffer-name must be the name of a shared buffer. The shared buffers must be specified in the same order across shared queries and in the OPEN QUERY.
[ PRIVATE | PROTECTED ][ STATIC ] QUERY query
Defines and identifies a query as a data member of a class, and optionally specifies an access mode (PRIVATE or PROTECTED) and scope (instance or STATIC) for that data member. You cannot specify these options when defining a query as a data element of a method (including constructors, destructors, and property accessors) or a procedure. For a data member query, each buffer-name must be the name of a compatible data member buffer (see the FOR option).
Note: The specified options are applicable only when defining a data member for a class in a class definition (.cls) file. Note also that you cannot shadow (override) the definition of a given query data member in a class hierarchy.

PRIVATE query data members can be accessed by the defining class. An instance can access a private data member of another instance if both instances are from the same class. PROTECTED query data members can be accessed by the defining class and any of its derived classes. An instance can access a protected data member of a second instance that is at the same level or higher in the class hierarchy. The default access mode is PRIVATE. When you reference a query from another data member definition (such as a data-source) defined in the same class or class hierarchy, the access mode of the query cannot be more restrictive than the access mode of the referencing data member.

A query defined with the STATIC option is a static data member of the class type for which it is defined and is scoped to the ABL session where it is referenced. ABL creates one copy of the specified class static query on first reference to the class type, and ABL creates only one such copy for any number of instances of the class that you create. You can directly reference an accessible static query data member from any other static or instance class member defined in the same class or class hierarchy.

Without the STATIC option, ABL creates an instance query data member that is scoped to a single instance of the class where it is defined. ABL creates one copy of the specified instance query for each such class instance that you create. You cannot directly reference an instance query data member from a STATIC class member definition defined within the same class or class hierarchy.

For more information on accessing queries of different access modes and scopes, see the reference entry for Class-based data member access.

Note: Members of a class are grouped into six namespaces, including buffers/temp-tables, methods, variables/properties/events, ProDataSets, queries, and data-sources. Queries defined as members of a class share the same namespace. There can be only one class member in this namespace with a given name.

For more information on where and how to define data members in a class, see the CLASS statement reference entry.

QUERY query
Defines and identifies a query whose records you can access only within the current procedure, method of a class (including constructors, destructors, and property accessors), or as a PRIVATE data member of a class.
FOR buffer-name[field-list][ , buffer-name[field-list]]...
Specifies the buffers to be used by the query, where buffer-name is a table or alternate buffer name. For a shared query, each buffer-name must be a shared buffer. If the query is a data member of a class, you must specify the name of a compatible buffer. Thus, if the query is a static data member, the buffer must also be a static data member; if the query is PROTECTED, the buffer must also be defined as PROTECTED or inherited from a super class; and if the data-source is PRIVATE, the buffer can be defined as either PRIVATE or PROTECTED. If the query is a PRIVATE instance data member, you can also specify a default database table buffer; you cannot specify a default database buffer for a query data member defined with any other combination of access mode and scope.
Note: ABL defines the default buffer for every database table that you access in a class as a PRIVATE instance buffer data member.

If the query definition references more than one buffer, it defines a join.

Once the query has been defined, you cannot change the buffers that it references, even if the query is closed and re-opened. For example, a buffer, buff1, is created for the Customer table in a DEFINE QUERY or OPEN QUERY for the query, qry1. The query is run and closed. You cannot now DEFINE or OPEN qry1 with buff1 for the item table. You can reuse buffers with CREATE QUERY, but you must re-run QUERY-PREPARE.

The field-list is an optional list of fields to include or exclude when you open the query. This is the syntax for field-list:

{
     FIELDS [ ( [field...] ) ]
   | EXCEPT [ ( [field...] ) ]
}

The FIELDS option specifies the fields you want to include in the query, and the EXCEPT option specifies the fields that you want to exclude from the query. The field parameter is the name of a single field in the table specified by buffer-name. If field is an array reference, the whole array is retrieved even if only one element is specified.

Note:

Field lists should be used with caution because they can cause unexpected run-time errors. It is possible, for example, that you may have eliminated a field that is required by a new or revised subroutine or trigger. The result can be a run-time error that may be difficult to debug.

You can use the -rereadfields startup option if you have unexpected run-time errors resulting from field lists. When an error occurs, the -rereadfields startup option causes the AVM to ignore the field list and to fetch the entire record.

Also note that he AVM ignores the FIELDS option for temp-tables.

This statement defines a query to retrieve only the name and balance fields from the Customer table:

DEFINE QUERY custq FOR Customer FIELDS (name balance).

This statement defines a query to retrieve all fields of the Customer table except the name and balance fields:

DEFINE QUERY custq FOR Customer EXCEPT (name balance).

When you specify a field list for a query, the AVM:

  • Retrieves complete records when you open the query with EXCLUSIVE-LOCK or update any row (such as with a browse). This ensures proper operation of updates and the local before-image (BI) file. For information on the local BI file, see OpenEdge Data Management: Database Administration.
  • Retrieves complete records for DataServers that do not support SHARE-LOCK. For more information, see the OpenEdge DataServer Guides (OpenEdge Data Management: DataServer for Microsoft SQL Server and OpenEdge Data Management: DataServer for Oracle).
CACHE n
Specifies the number of records of the query to hold in memory for a NO-LOCK query. Generally, caching more records produces better browse performance when accessing a database across a network. However, caching consumes both memory and CPU time for buffer management.

If you specify the CACHE option, the SCROLLING option is assumed. If a query is referenced in a DEFINE BROWSE statement, caching occurs by default. The default for a query involving only one table is 50 records. The default for a multi-table query is 30 records. If you specify CACHE 0 in the DEFINE QUERY statement, no caching occurs.

SCROLLING
Specifies that you can jump to a location within the list of records that satisfy the query by using the REPOSITION statement. If you do not use this option, you can use only the FIRST, NEXT, LAST, and PREV options of the GET statement to navigate within the list.

The SCROLLING option can improve NETWORK performance because query NO-LOCK records can be prefetched with multiple records per network message. (Note that in a join only the lowest level records for a given set of upper level records, can be prefetched). The -defaultscrolling startup parameter has the same effect. See OpenEdge Deployment: Startup Command and Parameter Reference for more information.

Non-network queries are faster if you do not use this option, but you must specify it to use the REPOSITION statement. If you do not specify SCROLLING for non-OpenEdge databases, you can only move forward through the list of records using the FIRST and NEXT options of the GET statement.

RCODE-INFORMATION
Note: This option is the default behavior (thus, it has no effect). It is supported only for backward compatibility.

Examples

The following example defines two queries, q-salesrep and q-cust. The first is opened in the main procedure block and is used to find all SalesRep records. The q-cust query is used to find all Customers associated with a SalesRep. The results of the q-cust query are displayed in a browse widget. The q-cust query is reopened each time you find a new SalesRep.

r-defqry.p

DEFINE QUERY q-salesrep FOR SalesRep 
DEFINE QUERY q-cust FOR Customer

DEFINE BROWSE cust-brws QUERY q-cust
  DISPLAY Customer.CustNum Customer.Name Customer.Phone
    WITH 5 DOWN TITLE "Customer Information".

DEFINE BUTTON b_next LABEL "Next".
DEFINE BUTTON b_quit LABEL "Quit" AUTO-ENDKEY.

FORM
  SalesRep.SalesRep SalesRep.RepName SalesRep.Region SaleRep.MonthQuota
  WITH FRAME rep-info SIDE-LABELS TITLE "Sales Rep. Info".

FORM b_next space(5) b_quit 
  WITH FRAME butt-frame COLUMN 60.

ON CHOOSE OF b_next DO:
  GET NEXT q-salesrep.
  IF NOT AVAILABLE SalesRep THEN GET FIRST q-salesrep.
  RUN disp-rep.
END.

OPEN QUERY q-salesrep FOR EACH SalesRep NO-LOCK.

GET FIRST q-salesrep.
RUN disp-rep.

ENABLE cust-brws WITH FRAME cust-info.
ENABLE ALL WITH FRAME butt-frame.
  
WAIT-FOR WINDOW-CLOSE OF CURRENT-WINDOW.

PROCEDURE disp-rep:
  DISPLAY SalesRep.SalesRep Salesrep.RepName SalesRep.Region
    SalesRep.MonthQuota
    WITH FRAME rep-info CENTERED SIDE-LABELS TITLE "Sales Rep. Info".
  OPEN QUERY q-cust FOR EACH Customer OF SalesRep NO-LOCK.
END PROCEDURE.

The following example uses the RCODE-INFORMATION option of the DEFINE QUERY statement to extract index information from a compile-time defined query. If you run the example with the RCODE-INFORMATION option commented out, the AVM reports a run-time error.

r-rcdinf.p

/* r-rcdinf.p */
/* Extracts index information from a compile-time defined query.*/
DEFINE VARIABLE h AS HANDLE NO-UNDO.

DEFINE QUERY q FOR Customer RCODE-INFORMATION.

h = QUERY q:HANDLE.
OPEN QUERY q FOR EACH Customer BY Customer.Name.

MESSAGE h:INDEX-INFORMATION.

Notes

See also

Class-based data member access, CLOSE QUERY statement, CREATE QUERY statement, CURRENT-RESULT-ROW function, DEFINE BROWSE statement, DEFINE DATASET statement, GET statement, NUM-RESULTS function, OPEN QUERY statement, REPOSITION statement, RUN statement