Skip to main content

Queries

A Query in the Application Object Tree (AOT) is a reusable, declarative definition of a data retrieval operation. It specifies which tables to read, how to join them, what ranges to apply, and in what order to return results — all without writing X++ code. At design time the query appears as a tree of data sources, ranges, and relations; at runtime it is compiled into SQL and executed against the database.

Queries serve three distinct purposes in D365 F&O:

  1. Standalone AOT objects — a named query that can be referenced by views (via the Query property), forms, reports, and data entities.
  2. Form data sources — every form data source is backed by a query that controls which records the form displays. Forms can reference a standalone AOT query or build one inline.
  3. X++ runtime objects — the Query and QueryRun classes let developers build and execute queries dynamically in code.

This section covers the AOT query object and its child elements. Form data sources are covered in the Forms section.


Query Types

The QueryType property determines how the query combines its root data sources:

Query TypeSQL BehaviourUse Case
Join (0)Root data sources are treated as separate FROM clauses joined together. Embedded data sources under each root are joined with the specified JoinMode.Standard multi-table queries.
Union (1)Root data sources are combined with UNION or UNION ALL. Each root data source contributes rows to a single result set.Combining rows from structurally similar tables into one list.

Join Queries

In a Join query (the default), the first root data source is the primary table. Additional tables are added as embedded data sources nested underneath the root, each with a JoinMode that controls how records from the child table relate to the parent:

Join ModeSQL EquivalentBehaviour
InnerJoin (0)INNER JOINReturns only rows where a match exists in both tables.
OuterJoin (1)LEFT OUTER JOINReturns all rows from the parent; unmatched child rows have null values.
ExistsJoin (2)EXISTS (SELECT ...)Returns parent rows where at least one child match exists. No child columns are returned.
NoExistsJoin (3)NOT EXISTS (SELECT ...)Returns parent rows where no child match exists.

Embedded data sources can be nested to any depth, enabling multi-table join chains.

Union Queries

In a Union query, each root data source contributes rows independently. The UnionType property on each data source controls whether duplicates are eliminated:

Union TypeSQL Behaviour
None (0)Data source does not participate in the union (default for non-union queries).
Union (1)UNION — combines rows and removes duplicates.
UnionAll (2)UNION ALL — combines rows and keeps all duplicates.

All root data sources in a union query must expose the same set of fields (same names and compatible types) so the result sets can be merged.


Data Source Hierarchy

Queries organise their data sources in a tree:

Query (AxQuerySimple)
└── Root Data Source (AxQuerySimpleRootDataSource)
├── Fields (AxQuerySimpleDataSourceField)
├── Ranges (AxQuerySimpleDataSourceRange)
├── Relations (AxQuerySimpleDataSourceRelation) ← only on embedded
├── GroupBy (AxQuerySimpleGroupByField) ← only on root
├── Having (AxQuerySimpleHavingPredicate) ← only on root
├── OrderBy (AxQuerySimpleOrderByField) ← only on root
└── Embedded Data Source (AxQuerySimpleEmbeddedDataSource)
├── Fields
├── Ranges
├── Relations
└── Embedded Data Source ← further nesting

Query Data Source Tree — hierarchical structure with join modes

The root data source (AxQuerySimpleRootDataSource) inherits all properties from the shared AxQuerySimpleDataSource base and adds GroupBy, Having, and OrderBy collections. Embedded data sources (AxQuerySimpleEmbeddedDataSource) inherit the same shared base but add JoinMode, FetchMode, UseRelations, and a Relations collection for defining custom join conditions.


Fields

The Fields collection on a data source controls which columns appear in the query result. Each field entry (AxQuerySimpleDataSourceField) references a column from the data source's table.

When DynamicFields is set to Yes on the data source, all fields from the table are included automatically and the Fields collection is ignored. When set to No, only the explicitly listed fields are returned.


Ranges

Ranges define filter conditions on a data source — they become WHERE clauses in the generated SQL. Each range (AxQuerySimpleDataSourceRange) targets a specific field and specifies a filter value.

The Value property supports operators and expressions:

ExpressionExampleSQL Equivalent
Exact value10= 10
Range1..100BETWEEN 1 AND 100
Not equal!10<> 10
WildcardCust*LIKE 'Cust%'
Or list10,20,30IN (10, 20, 30)

Range Status

The Status property controls whether end users can modify the range at runtime (in form query dialogs):

StatusBehaviour
Open (0)The user can see and modify the range value.
Locked (1)The user can see the range but cannot change it.
Hidden (2)The range is invisible to the user and cannot be changed.

Relations (Embedded Data Sources)

When an embedded data source has UseRelations set to No, the join condition must be defined manually in the Relations collection. Each relation entry (AxQuerySimpleDataSourceRelation) links a field on the child data source to a field on the parent (or another named data source).

When UseRelations is Yes, the runtime uses the relations defined between the tables in the AOT Data Dictionary and the Relations collection is ignored.


Group By, Having, and Order By

These collections are available only on the root data source.

Group By

The GroupBy collection (AxQuerySimpleGroupByField) specifies the fields used to group rows, producing an SQL GROUP BY clause. When grouping is active, non-grouped fields in the query must use an aggregation function (Sum, Count, Min, Max, Avg).

Having

The Having collection (AxQuerySimpleHavingPredicate) filters grouped results — equivalent to a SQL HAVING clause. Having predicates are applied after aggregation, allowing you to filter on aggregate values (e.g., "only groups where SUM(Amount) > 1000").

Order By

The OrderBy collection (AxQuerySimpleOrderByField) defines the sort order of results. Each entry specifies a field and a direction:

DirectionBehaviour
Ascending (0)Sort A→Z / smallest→largest.
Descending (1)Sort Z→A / largest→smallest.

Fetch Mode

The FetchMode property on embedded data sources controls how the runtime retrieves records from joined tables:

Fetch ModeBehaviour
OneToOne (0)A single record from the child table is fetched alongside each parent record. This is the default and is appropriate for lookup joins.
OneToN (1)Multiple child records are fetched per parent. The data source acts as a nested loop and must be iterated separately in X++ when used on forms.

In AOT queries consumed by views, FetchMode has no runtime effect because the view is flattened into SQL. It is primarily relevant when the query backs a form data source.


Using a Query in X++

The Query and QueryRun classes provide a programmatic interface to build and execute queries at runtime. You can start from an AOT query or build one entirely in code — adding data sources, ranges, joins, and sort orders dynamically.

When AllowCrossCompany is Yes on the AOT query (or set programmatically), the query retrieves data across all legal entities the user has access to.

See Code Examples for full implementation patterns.


Properties

67/67 properties
PropertyDisplay NameTypeDescription
QueryAxQuerySimple
QueryTypeQuery TypeQueryTypeType of query. Values: Join (0), Union (1).
TitleTitleStringTitle of the query.
DescriptionDescriptionStringDescriptive help text for the query.
FormFormStringForm associated with the query.
UserUpdateUser UpdateNoYesWhether the user may modify the query. Values: No (0), Yes (1).
LiteralsLiteralsSqlLiteralMode_ITxtHow literals are represented in SQL statements. Values: Default (0), ForceLiterals (1), ForcePlaceholders (2).
InteractiveInteractiveNoYesWhether the query may open dialogs. Values: No (0), Yes (1).
AllowCheckAllow CheckNoYesWhether security checking occurs before or after the form opens. Values: No (0), Yes (1).
SearchableSearchableNoYesWhether query results are searchable. Values: No (0), Yes (1).
AllowCrossCompanyAllow Cross CompanyNoYesWhether the query aggregates data across all companies. Values: No (0), Yes (1).
ImportableImportableNoYesWhether the query is importable. Values: No (0), Yes (1).
Data Source — sharedAxQuerySimpleDataSource
NameNameStringThe name of the data source.
TagsTagsStringTags for this element separated by semicolon.
TableTableStringThe table, view, or data entity that supplies data for this data source.
LabelLabelStringDescriptive label for the data source.
CompanyCompanyStringSpecific company context for this data source.
FirstOnlyFirst OnlyNoYesWhether only the first record should be selected. Values: No (0), Yes (1).
FirstFastFirst FastNoYesWhether to retrieve the first record faster than subsequent records. Values: No (0), Yes (1).
AllowAddAllow AddNoYesWhether the user may add fields for search. Values: No (0), Yes (1).
UpdateUpdateNoYesWhether the cursor can update records. Values: No (0), Yes (1).
EnabledEnabledNoYesWhether the data source is enabled. Values: No (0), Yes (1).
SelectWithRepeatableReadSelect With Repeatable ReadNoYesWhether the data source uses a repeatable read hint. Values: No (0), Yes (1).
ConcurrencyModelConcurrency ModelConcurrencyModelConcurrency model for the data source. Values: Auto (0), Optimistic (1), Pessimistic (2).
UnionTypeUnion TypeUnionTypeType of union for this data source. Values: None (0), Union (1), UnionAll (2).
DynamicFieldsDynamic FieldsQueryFieldListDynamicWhether fields are dynamically selected. Values: No (0), Yes (1), Unselected (99).
PolicyContextPolicy ContextStringPolicy context for the data source.
IsReadOnlyIs Read OnlyNoYesWhether the data source is read-only. Values: No (0), Yes (1).
ApplyDateFilterApply Date FilterNoYesWhether the data source is filtered for date effectivity. Values: No (0), Yes (1).
ValidTimeStateUpdateValid Time State UpdateValidTimeStateUpdateType of update for date-effective records. Values: CreateNewTimePeriod (1), Correction (2), EffectiveBased (3).
ChangeTrackingEnabledChange Tracking EnabledNoYesWhether the data source participates in change tracking. Values: No (0), Yes (1).
Root Data SourceAxQuerySimpleRootDataSource
GroupByGroup ByCollectionFields to group by. Contains AxQuerySimpleGroupByField entries.
HavingHavingCollectionHaving predicates applied after aggregation. Contains AxQuerySimpleHavingPredicate entries.
OrderByOrder ByCollectionSort order fields. Contains AxQuerySimpleOrderByField entries.
Embedded Data SourceAxQuerySimpleEmbeddedDataSource
JoinModeJoin ModeJoinMode_ITxtHow the data source joins to its parent. Values: InnerJoin (0), OuterJoin (1), ExistsJoin (2), NoExistsJoin (3).
FetchModeFetch ModeFetchMode_ITxtHow linked records are fetched. Values: OneToOne (0), OneToN (1).
UseRelationsUse RelationsNoYesWhether to use AOT-defined relations for the join condition. Values: No (0), Yes (1).
Field / Range / Relation / GroupBy / OrderBy
NameNameStringThe name of the field entry.
TagsTagsStringTags for this element separated by semicolon.
FieldFieldStringThe field from the data source table to include in the query result.
DerivedTableDerived TableStringTable used when referencing a field from a derived (table-inheritance) table.
NameNameStringThe name of the range.
TagsTagsStringTags for this element separated by semicolon.
FieldFieldStringThe field to filter on.
ValueValueStringThe filter value or expression.
LabelLabelStringDescriptive label for the range.
StatusStatusRangeStatusRuntime visibility and editability of the range. Values: Open (0), Locked (1), Hidden (2).
EnabledEnabledNoYesWhether the range is active. Values: No (0), Yes (1).
DerivedTableDerived TableStringTable used when filtering a field from a derived table.
NameNameStringThe name of the relation.
TagsTagsStringTags for this element separated by semicolon.
JoinDataSourceJoin Data SourceStringThe data source to join to (by name).
FieldFieldStringField on the current data source.
RelatedFieldRelated FieldStringField on the joined data source.
JoinRelationNameJoin Relation NameStringName of the AOT relation to use for the join.
JoinDerivedTableJoin Derived TableStringDerived table on the join target side.
DerivedTableDerived TableStringDerived table on the current data source side.
NameNameStringThe name of the group-by entry.
TagsTagsStringTags for this element separated by semicolon.
FieldFieldStringThe field to group by.
DataSourceData SourceStringThe data source containing the field (when grouping by a field on a joined data source).
DerivedTableDerived TableStringDerived table reference for table-inheritance scenarios.
NameNameStringThe name of the order-by entry.
TagsTagsStringTags for this element separated by semicolon.
FieldFieldStringThe field to sort by.
DirectionDirectionOrderByDirectionSort direction. Values: Ascending (0), Descending (1).
DataSourceData SourceStringThe data source containing the field.
DerivedTableDerived TableStringDerived table reference for table-inheritance scenarios.