Skip to content
2 changes: 2 additions & 0 deletions content/en/docs/refguide/modeling/domain-model/oql/_index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: "OQL"
url: /refguide/oql/
description: "An introduction to the Mendix Object Query Language with links to further information."
weight: 90
---

Expand Down Expand Up @@ -37,6 +38,7 @@ OQL is under constant development so some expressions and features are not avail
| Feature | Mendix Version |
| --- | --- |
| Comments | 11.7.0 |
| Parentheses around individual `UNION` subqueries | 11.15.0 |

### [OQL Expressions](/refguide/oql-expression-syntax/)

Expand Down
58 changes: 51 additions & 7 deletions content/en/docs/refguide/modeling/domain-model/oql/oql-clauses.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: "OQL Clauses"
url: /refguide/oql-clauses/
description: "A reference guide to OQL clauses"
weight: 10
aliases:
- /refguide/oql-from-clause/
Expand Down Expand Up @@ -36,7 +37,7 @@ Clauses must be presented in the following order, but can be left out if they ar
7. [`LIMIT`](#limit-offset)
8. [`OFFSET`](#limit-offset)

The `UNION` clause defies the usual order presented above. It will be presented in a [Union Clause](#oql-union) section at the end.
The `UNION` clause combines multiple SELECT queries and each of these SELECT queries must maintain the order presented above. See [`UNION` Clause](#oql-union), below.

The domain model used in the various examples is shown below:

Expand Down Expand Up @@ -853,7 +854,7 @@ This clause can include items that do not appear in the `SELECT` clause, except
{{% alert color="info" %}}
The `ORDER BY` clause cannot be used in view entities without a `LIMIT` or an `OFFSET` clause. See [Sorting of View Entity Results](/refguide/use-view-entities/#sorting) in *How To Use View Entities* for more details.

If OQL v2 is enabled, an `ORDER BY` clause cannot be used in subqueries without a `LIMIT` or an `OFFSET` clause because the order of the subquery results may not be retained in the outer query. See the [`ORDER BY` in Subquery](/refguide/oql-v2/#order-by-in-subquery) section of *OQL Version 2 Features* for more details.
If OQL v2 is enabled, an `ORDER BY` clause cannot be used in subqueries without a `LIMIT` or an `OFFSET` clause because the order of the subquery results may not be retained in the outer query. See the [`ORDER BY` in Subqueries](/refguide/oql-v2/#order-by-in-subqueries) section of *OQL Version 2 Features* for more details.
{{% /alert %}}

### Syntax
Expand Down Expand Up @@ -1076,16 +1077,22 @@ All select queries must define the same number of columns in the same order and
The syntax is as follows:

```sql
select_query
select_query | ( select_query )
{
UNION [ALL] select_query
UNION [ALL] { select_query | ( select_query ) }
} [ ,...n ]
[ order_by_clause ]
[ LIMIT number ]
[ OFFSET number ]
```

### Result data type {#oql-union-type}
By default, any `order_by_clause`, `LIMIT`, or `OFFSET` in a `UNION` clause will apply to the whole query. Wrapping a select_query in parentheses enables two things. First, it scopes any order_by_clause, LIMIT, or OFFSET inside the parentheses to only that subquery's results. Second, it allows a UNION to be nested inside another UNION, for example, `SELECT query_a UNION (SELECT query_b UNION ALL SELECT query_c)`. The outer UNION can still have its own order_by_clause, LIMIT, and OFFSET applying to the final combined result. See [Parenthesized `UNION` Subqueries](#oql-union-parentheses), below, for an example.

{{% alert color="info" %}}
Adding parentheses in `UNION` clauses was introduced in Mendix version 11.15.0. It is supported only in Java actions.
{{% /alert %}}

### Result Data Type {#oql-union-type}

The data types used in `select_query` statements are considered when determining the final return type of the `UNION` clause. All data types used in `select_query` statements must be compatible. All data types are compatible with themselves. Differing types are only compatible in these cases:

Expand Down Expand Up @@ -1196,7 +1203,40 @@ SELECT LastName AS Name FROM Sales.Customer
| Doe |
| Moose |

#### Union of different types
#### Parenthesized `UNION` Subqueries {#oql-union-parentheses}

{{% alert color="info" %}}
This feature was introduced in Mendix version 11.15.0. It is supported only in Java actions.
{{% /alert %}}

You can wrap an individual subquery in parentheses to sort and limit only the results from that subquery rather than the sorting and limiting applying to the result of the `UNION`. This is done by giving each subquery its own `ORDER BY`, `LIMIT` and `OFFSET` clauses.

For example, the following query uses `UNION` to return the brand and location with the highest and second-lowest stock levels, sorted in ascending order of the amount of stock.

```sql
(
SELECT Brand, City, Stock
FROM Sales.Location
ORDER BY Stock DESC
LIMIT 1
)
UNION
(
SELECT Brand, City, Stock
FROM Sales.Location
ORDER BY Stock ASC
LIMIT 1
OFFSET 1
)
ORDER BY Stock ASC
```

| Brand | City | Stock |
| ------ | ---------- | ----- |
| Veidt | Utrecht | 2 |
| Veidt | Rotterdam | 23 |

#### Union of Different Types

Presume two entities that have columns of types `INTEGER` and `DECIMAL`:

Expand Down Expand Up @@ -1235,7 +1275,7 @@ SELECT Sale FROM Sales.Sales
| 42.25 |
| 15.5 |

#### Union of associations
#### Union of Associations

Performing a `UNION` with columns that are associations is possible, given the columns refer to the same entity for all select clauses.

Expand Down Expand Up @@ -1274,6 +1314,10 @@ SELECT Cust.LastName as CustomerName FROM (

A subquery is an OQL query nested inside another query. A subquery can contain the same clauses as a regular OQL query. The entities from the outer query can be referred to in a subquery. A subquery can be used in different parts of the query.

{{% alert color="info" %}}
For the use of subqueries in `UNION` clauses, see [Parenthesized `UNION` Subqueries](#oql-union-parentheses), above.
{{% /alert %}}

### Subquery in `SELECT` {#subquery-in-select}

A subquery can be used as a column in the `SELECT` clause. It can refer to other tables and expressions in `FROM`.
Expand Down
19 changes: 18 additions & 1 deletion content/en/docs/refguide/modeling/domain-model/oql/oql-v2.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
---
title: "OQL Version 2 Features"
linktitle: "Switching to OQL Version 2"
description: "A guide to the differences between Mendix OQL versions 1 and 2, plus a guide to switching to version 2"
url: /refguide/oql-v2/
weight: 100
---
Expand Down Expand Up @@ -183,7 +184,7 @@ JOIN (SELECT Name AS N FROM Module.City) C
ON P/Residence = C/Name
```

### `ORDER BY` in Subquery {#order-by-in-subquery}
### `ORDER BY` in Subqueries {#order-by-in-subqueries}

You must now have a `LIMIT` and/or `OFFSET` in subquery containing `ORDER BY`. Using `ORDER BY` in subquery makes sense only when it is combined with `LIMIT` and/or `OFFSET`. Without the limitations, database engines do not guarantee that the row order in the subquery will be preserved in the outer query.

Expand Down Expand Up @@ -212,6 +213,22 @@ FROM (
)
```

The same restriction applies to a subquery which is a `select_query`, or a nested `UNION` as part of a [`UNION`](/refguide/oql-clauses/#oql-union). Consequently, you can only use `ORDER BY` in a parenthesized `UNION` clause if it is combined with `LIMIT` and/or `OFFSET`:

```sql
(
SELECT Name
FROM Module.Person
ORDER BY Name
LIMIT 20
)
UNION
(
SELECT Name
FROM Module.City
)
```

### `ORDER BY` in View Entities

For [view entities](/refguide/view-entities/), you must now have a `LIMIT` and `OFFSET` in all `ORDER BY` clauses, even for the top level query.
Expand Down