Aggregate

Projection – Abstract

Purpose: Enables simple calculations for individual property values and aggregations for lists of property The values, which can optionally be formed by grouping as subsets from a basic set defined by the search.

images/download/attachments/157877408/image-2023-11-20_18-42-3-version-1-modificationdate-1700502129816-api-v2.png

The Aggregate projection type enables various simple calculations (for individual property values) and aggregations for lists of property values, which can optionally be formed by grouping as subsets from a basic set defined by the search.

The following table divides the options for the Type of calculation/aggregation into categories and specifies for each Type which data type is supported per Projection.

  • Only the types summarized here as aggregation functions can process several return values from the Projection and, if necessary, take into account subsets from a grouping in the context of the search.

  • The other calculation functions enable simple calculations or 'conversions' of individual values of a specific data type from the Projection.

Type

Function name

Data type for the projection

Description

Aggregation functions

Count

COUNT

any

Number of individual values to be aggregated that are not 'No value' ($null).

Count (distinct)

COUNT_DISTINCT

Number of different individual values that are not 'No value' ($null).

Min

MIN

Minimum value (according to the sorting logic of the database used for the data type)

Max

MAX

Maximum value (according to the sorting logic of the database used for the data type)

Least

LEAST

Minimum value (according to the sorting logic of the database used for the data type)

Sum

SUM

numerical

Sum of the individual values to be aggregated

Average

AVG

Arithmetic mean of the individual values to be aggregated that are not 'No value' ($null).
(=Sum/Count)

Arithmetic (for single numerical value)

Absolute

ABS

numerical

Returns the absolute value of a numerical value
('removes' a negative sign, if present)

Negate

NEG

Changes the sign of a numerical value (+|-)

Square root

SQRT

Square root of a numerical value

Logic (for single Boolean value)

Not

NOT

Boolean

Reverses a truth value (true|false)

Text processing (for single text value)

Length

LENGTH

String

Length of a character string (Long value) or $null

Lower

LOWER

Returns a character string in lower case letters

Upper

UPPER

Returns a character string in capital letters

Trim

TRIM

'Trims' (=removes) marginal space characters from a character string

Configuration

Parameter

Type

Description

Name

String

The optional Name parameter can be used to assign an (alias) name to the projection.

  • If no Name is specified, the column name (if relevant) is the name applicable in the context of the Projection according to the scheme '<function> of <projection>'. The placeholder <function> is replaced by the English 'function name' from the table above for the selected Type.

Type

AggregateType

images/download/attachments/157877408/image-2023-11-20_18-43-21-version-1-modificationdate-1700502208075-api-v2.png

The Type determines the type of aggregation, calculation and conversion to be performed on the basis of the Projection.

  • The Combobox element with search function refers to the static enumeration 'Search aggregate type' (AggregateType).

NOTE◄ The breakdown of the above table by category ('Aggregation functions', 'Arithmetic', ...) is not reflected in the dropdown.

Projection

Projection

In principle, any Projections can be configured for the Projection parameter as long as they return a data type permitted for the Type and the database system used supports their use in the given context.

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg CAUTIONimages/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg For 'real aggregations', i.e. those with a Type from the aggregation function category, the following restrictions may be relevant:

  • An aggregation function cannot generally be used within another Aggregate that is also an aggregation function. Aggregation functions cannot be nested.

  • Certain database systems (e.g. MSSQL) also do not support the use of a Subsearch projection in the context of an aggregation function.

Examples of the conversion of individual values

Arithmetic – Absolute (ABS): Absolute value of a numerical field as a restriction projection

The default property 'Last modifier ID' (lastModifierId) for entities usually contains a positive Long value that corresponds to the 'ID' (id) of a user account (see Users).

However, if the last change to an entity was made in the context of a guest user account (see Guest users), its 'ID' (id) is entered as a negative value in the lastModifierId property to ensure differentiation from users with the same ID.

In the data grid of an overview, the 'Last modifier ID' column appears empty by default if this property references a guest user account, because looking up the user name (see Subsearch projection), which is implemented as a column projection by default, is 'unproductive' for negative references.

Regardless of the display, the filter function for this column should be adapted so that the filter criteria for the positive Long value of an account ID can be entered, regardless of whether it is a Users or Guest users.

Configuration:

images/download/attachments/157877408/image-2023-11-20_18-45-12-version-1-modificationdate-1700502318636-api-v2.png

The settings for the 'Last modifier ID' column (lastModifierId) must be displayed in the data grid settings for the relevant overview.

For this column, there is no configuration for a projection in the tab for defining the Restriction projection by default. This means that by default the Projection is also a Restriction projection.

If you configure a Restriction projection as shown on the right, it overrides the default behaviour as follows:

  • Instead of the text value tailored to Users (scheme: {id} - {username}), an Aggregate with the Type 'Absolute' (ABS) is used as a compare value for the filter, which is used here to remove any minus sign (for Guest users) from the Long value read from the Property projection for the lastModifierId property.

  • The positive ID values for Users return the Aggregate with the Type 'Absolute' (ABS) unchanged.

  • The characteristic of the filter adapts to the numerical data type.

NOTE◄ Of course, it is not ideal that this Restriction projection cannot distinguish between a user account and a guest user account with the same ID. However, if overlaps between the IDs used are relevant in practice, it is still possible to adapt the Projection so that Users and Guest users can still be clearly distinguished from each other.

Runtime example:

images/download/attachments/157877408/image-2023-11-20_18-46-18-version-1-modificationdate-1700502385122-api-v2.png

The screenshot on the left shows an excerpt from the 'Last modifier' column, for which not only the Restriction projection (as above) has been adjusted, but also the Projection, so that for Guest users the (positive) ID of the account appears with the prefix 'G#'.

As the filter expression (7251|2701) makes clear, the filter still refers exclusively to the positive ID values of the relevant accounts as desired.

NOTE◄ The Projection uses a Case projection (see screenshot below), which compiles the display text for references to the Guest users in the right branch of the case differentiation using a simple Concatenated projection. Again, an Aggregate with the Type 'Absolute' (ABS) is used to eliminate the minus sign of the negative lastModifierId value. The default Subsearch projection, which looks up the user name in the account, was placed in the left branch of the case differentiation.


images/download/attachments/157877408/image-2023-11-20_18-47-23-version-1-modificationdate-1700502450373-api-v2.png

Arithmetic – Negation (NEG): Negating numerical values (sign reversal)

The line items of a user-defined entity type 'Account' (see Custom type definition) are used to record incoming and outgoing payments, which are always maintained as positive numerical values in a 'payment value' property (payment.value), regardless of their type. An associated text property 'payment type' (paymentType) is used to further classify the transaction.

By convention, payouts should be identified by key values for the 'payment type' (paymentType) that begin with the letter 'R'.

Using a tuple search that directly addresses the item level (AccountLineItem), the balances for each 'account' instance are to be calculated in such a way that the total of all payments out is deducted from the total of all payments in.

Configuration:

The tuple search uses the two Projections shown on the right:

  • The first, a Property projection, identifies the parent entity (the relevant 'account') using the parentId reference property.
    IMPORTANT◄ This property must also be projected in the context of the Group by so that all items are aggregated per 'account'.

  • As a second projection, an Aggregate with the Type 'Sum' (SUM) is used, which calculates the aggregated balance per 'Account' using the Name TOTAL.

  • To ensure that the positive payment amounts stored for each line item are correctly offset against each other in the context of the Aggregate depending on the specified 'payment type', a sign reversal must be carried out for the amount in the payment.value property within the Projection if the 'payment type' (paymentType) begins with the code letter 'R':

    • A Case projection checks the paymentType via a Field restriction and uses an aggregate with the Type 'Negate' (NEG) in the THEN branch to reverse the sign for the numerical value from the Property projection payment.value.

    • In the OTHER branch (for deposits), the payment.value is 'passed through' unchanged.

NOTE◄ The example uses the NEG calculation function here more by chance in the context of a 'real' aggregation function (SUM). Calculation functions can also be used at any time without an aggregation function and grouping, for example to 'adjust' values in conditions.

images/download/attachments/157877408/image-2023-11-20_18-51-45-version-1-modificationdate-1700502712035-api-v2.png

Arithmetic – Square root (SQRT): Square root

A tuple search for Shipments should provide an indication of the complexity of a shipment in a COMPLEXITY column, the square root of the number of different values for the 'parent line item', in addition to other key figures.

Configuration:

The Projection shown on the right, in conjunction with a Group by of the search by the 'ID' (id) property of the shipment – not shown here – provides the desired key figure for the 'complexity':

  • The inner Aggregate with the Type 'Count (distinct)' determines the Group by 'variety' of values for the 'Parent line item no.' (parentLineItemId) property, taking into account the 'line items' (lineItems) per shipment.

  • The outer Aggregate with the Type 'Square root' (SQRT) calculates the square root value from the aggregated numerical value from the inner Aggregate.

images/download/attachments/157877408/image-2023-11-20_18-54-10-version-1-modificationdate-1700502856817-api-v2.png

Runtime example:

ID,VOLUME,COMPLEXITY
8455,1,2.0
7955,10,1.7320508075688772
7951,,1.7320508075688772
4006,2,1.7320508075688772
9251,4,1.4142135623730951
9252,4,1.0

The example data on the left shows the calculated Doublevalues for 'complexity values' of √4, √3, √2 and √1 for the COMPLEXITY column.

The square root is used here because doubling the number of 'parent line items' in the hierarchy should not mean twice the complexity. However, quadrupling does.

Logic – Not (NOT): Logical negation

In a tuple search for Users, the Boolean property 'Active' should be logically reversed so that with the column labeling such as DEACTIVATED, the value $true appears for the Users for which the 'Active' property contains the value $false and vice versa.

Configuration:

The Aggregate shown on the right defines the output column DEACTIVATED by Name:

  • The Type 'Not' (NOT) expects a Boolean value for the Projection, which is logically negated.

  • The Projection uses a Property projection that accesses the 'Active' (active) Property.

images/download/attachments/157877408/image-2023-11-20_18-55-31-version-1-modificationdate-1700502937791-api-v2.png

NOTE

  • The 'Active' property for users is 'not nullable' by definition, so the return value of the Aggregate will be $true or $false in all cases.

  • If the return value of the Projection can also be $null in addition to $true and $false, the Aggregate with the Type 'Not' (NOT) returns the return value $null if the original value is $null.

String processing – Length (LENGTH): Text length as filter condition

In the address property 'Account number' (address.accNumber) for Company accounts, a nine-digit character string is expected by convention.

A search should return a list of all Company accounts for which this convention for the address property 'Account number' is not fulfilled.

Configuration:

images/download/attachments/157877408/image-2023-11-20_18-57-32-version-1-modificationdate-1700503058620-api-v2.png

Within an OR conjunction, two instances of the Field restriction must be used to identify Company accounts for which the address property 'Account number' (address.accNumber) is either unassigned or not filled in at all:

  • The left Field restriction evaluates the text property 'Account number' as a check value using Aggregate with the Type 'Length' to check whether the length of an existing character string deviates from the default value 9 (!=).

  • The right Field restriction is required to cover the case that there is no information at all for the 'Account number'.

IMPORTANT◄ The right Field restriction formally checks whether the 'Account number' contains an empty string (''). This condition is actually implemented in the database in such a way that it checks whether there is an empty string or 'No value' ($null).

  • The Aggregate with the Type 'Length' only returns the value 0 in the special case that the address property 'Account number' actually contains an empty string ('') and not 'No value' ($null).

String processing – Upper (UPPER): Grouping users according to the first letter in the user name

A CSV search should return the number of Users who share the same initial letter for the 'username' (username).

No distinction should be made between upper and lower case letters (e.g. {admin,AEINSTEIN}A).

Configuration:

Group by's are required as the basis for the use of an Aggregate with the Type 'Count' (see below) for the actual aggregation of user accounts, which can be configured as shown on the right:

  • Within an Aggregate, the Type 'Upper' (UPPER) defines that the return value of the Projection should be converted to upper case.

  • The Projection is a Sub string projection that returns the first character from the 'username' (username) property.


images/download/attachments/157877408/image-2023-11-20_19-0-43-version-1-modificationdate-1700503249573-api-v2.png


The following two columns are to be output as Projections for the CSV search:

  • The first column to be output is the capital letter according to which the Users are grouped for counting purposes:

    • For formal reasons, the projection used in the Group by's (see above) must be used in the context of a real aggregation function. The Type 'Min' was selected here for the outer Aggregate. The corresponding Projection can be taken directly from the Group by's with this setting.

  • The second column defines the numerical value for the number of Users who share the initial letter specified in the first column in the 'username' property by a further Aggregate:

    • The Type selected here is 'Count' (COUNT).

    • The Projection refers to the 'ID' (id) property, i.e. the unique identifier of the user account, which reliably contains a value for each Users.

images/download/attachments/157877408/image-2023-11-20_19-1-54-version-1-modificationdate-1700503320646-api-v2.png

String processing – Lower (LOWER): Upper/lower case non-specific comparison

A search should list all Users for which there is a match between the address property 'Country' (address.countryCode) and the first two characters of the internal identifier for the 'Locale' (locale).

Configuration:

The Field restriction shown on the right produces the desired adjustment:

  • The check value (left) is a Sub string projection that returns the first two characters of the internal identifier for the user's 'locale' (locale). By convention (see Locale), these should be lowercase letters..

  • As a compare value (right), an Aggregate with the Type 'Lower' (LOWER) converts the return value from the address property 'Country' (address.countryCode)into lower case letters. By convention (see Country), this is a combination of two capital letters in accordance with the ISO 3166 standard.

images/download/attachments/157877408/image-2023-11-20_19-3-37-version-1-modificationdate-1700503423658-api-v2.png

IMPORTANT◄ An Aggregate with the Type 'Lower' cannot generally be used to process the internal name of enumeration values (here: Country, Locale). This only works here in exceptional cases, as the relevant properties for the user account (locale) or the address (countryCode) are treated as text properties in the database, in contrast to the general standard. In general, properties that refer to Dynamic enumerations contain the 'ordinal' value of the Long type in the database. A Projection on such a property – e.g. the address property 'Salutation' (address.salutation) for a user that refers to the dynamic enumeration Salutation – is then not suitable as an input value for a calculation function for text processing in an Aggregate. When executing the query, an error message usually appears, which refers to the conflict of types.

String processing – Trim (TRIM): Search for 'untrimmed' texts

A search is to determine Addresses for which 'untrimmed' text – i.e. a character string with at least one bordered space – was entered as the 'Name' (name1).

Configuration:

The Where condition shown on the right uses a Field restriction to check whether the text specified as 'Name' (name1) is different from the return value of the trim function for the same property (!=):

NOTE◄ A search with this Where condition returns all Addresses that can be accessed in the execution context because Address book entries refer to them. Addresses that were created in the context of other entities (e.g. Company accounts or Users) are not included in the search result, as long as they are not accessed via Joins, a Sub search or similar.

images/download/attachments/157877408/image-2023-11-20_19-6-4-version-1-modificationdate-1700503571526-api-v2.png

Examples of aggregation functions

Typical example: Aggregation of key figures in a search with grouping

A tuple search determines three 'static key figures' for the use of Guest users accounts by different Company accounts (column: COMPANY):

  • Number of Guest users per company (column: GUEST_ACCOUNTS)

  • Sum of logins executed by Guest users per company (column: GUEST_LOGINS)

  • Average login count executed per account per company (column: LOGIN_AVG)

Runtime example:

The example on the right shows the result of a tuple search with the following characteristics:

  • There are 3 result rows (row), each of which shows the data for a specific company.

  • The value (item) for the first column (COMPANY) identifies the company via its 'ID' (id).

  • The second column (GUEST_ACCOUNTS) shows the number of all Guest users created for each company as an integer (long).

  • The third column (GUEST_LOGINS) shows the total number of logins carried out for each company as an integer (int).

  • The fourth column (LOGIN_AVG) shows the average number of logins per account as a decimal number (double).
    NOTE◄ The aggregated average value can be 'recalculated' in the given scenario by dividing the aggregation results in columns 3 and 2 (GUEST_LOGINS/GUEST_ACCOUNTS) for verification purposes.

   <core:TupleSearchResult maxResults="100" count="3">
<columns>
<name>COMPANY</name>
<name>GUEST_ACCOUNTS</name>
<name>GUEST_LOGINS</name>
<name>LOGIN_AVG</name>
</columns>
<result>
<row>
<item xsi:type="xsd:long">101</item>
<item xsi:type="xsd:long">2</item>
<item xsi:type="xsd:int">0</item>
<item xsi:type="xsd:double">0.0</item>
</row>
<row>
<item xsi:type="xsd:long">1902</item>
<item xsi:type="xsd:long">12</item>
<item xsi:type="xsd:int">179</item>
<item xsi:type="xsd:double">14.916666666666666</item>
</row>
<row>
<item xsi:type="xsd:long">2202</item>
<item xsi:type="xsd:long">2</item>
<item xsi:type="xsd:int">9</item>
<item xsi:type="xsd:double">4.5</item>
</row>
</result>

Configuration:

The data structure for Guest users provides the following characteristics for our statistics:

  • The 'Company' (companyId) property is a required field for the guest user account, which must be filled with a reference to the 'ID' (id) of exactly one company account (see Company accounts).

  • The 'Number of logins' (loginCount) property provides the number of logins carried out with a guest user account as an integer.

As our search is intended to aggregate key figures for Guest users per company, Group by's must be defined for the search:

  • The screenshot shows (top right) a Property projection on the 'Company' (companyId) property, which is set up for this purpose.

  • As the screenshot (bottom right) shows, the same Property projection should also be used as a Projection in the context of Order by.

    NOTE◄ It is not necessary to define Order by. This sorting criteria should only be defined if the Order by represents added value for the intended use. Instead of Projections from the Group by, aggregation results could also be accessed within the Order by and in the given example, for example, the companies could be sorted in descending order by the number of guest users.

images/download/attachments/157877408/image-2023-11-20_19-8-2-version-1-modificationdate-1700503689104-api-v2.png

The screenshot on the right shows an overview of the Projections set up for the tuple search, which define the output columns:

  • The first column (COMPANY) uses the Property projection on the 'Company' (companyId) property, which is also specified as a Group by.

  • The configuration for the following 'statistics columns' is explained step by step below.

images/download/attachments/157877408/image-2023-11-20_19-10-52-version-1-modificationdate-1700503859220-api-v2.png

The GUEST_ACCOUNTS column uses an Aggregate with the Type 'Count' (COUNT) with a Property projection for the 'ID' (id) property of the Guest users to be aggregated.

For the 'Count' aggregation type, the property selection is irrelevant as long as it is ensured that it cannot contain 'No value' ($null). Otherwise, Guest users for which the field does not contain a value in the Projection are not counted.

Without an entry for the Name parameter, the title of the output column would be 'COUNT of id'.

images/download/attachments/157877408/image-2023-11-20_19-11-24-version-1-modificationdate-1700503891322-api-v2.png

The GUEST_LOGINS column uses an Aggregate with the Type 'Sum' (SUM) with a Property projection for the 'Number of logins' (loginCount) property of the Guest users to be aggregated.

The 'Sum' aggregation type adds up all the numerical values found. Whether the property in the Projection is filled for all aggregated Guest users is irrelevant for the value returned as 'Sum'.

Without an input for the Name parameter, the title of the output column would be 'SUM of loginCount'.

images/download/attachments/157877408/image-2023-11-20_19-11-50-version-1-modificationdate-1700503916566-api-v2.png

The LOGIN_AVG column uses an Aggregate with the Type 'Average' (AVG) with a Property projection for the 'Number of logins' (loginCount) property of the Gastbenutze to be aggregated.

The 'Average' aggregation type relates the sum of all values from the Projection to the number of aggregated individual values that are not 'No value' ($null). Since the loginCount property is initialized with the value 0 and cannot contain a $null value on the database side, the interpretation of the mean value in the context is not critical.

Without an entry for the Name parameter, the title of the output column would be 'AVG of loginCount'.

images/download/attachments/157877408/image-2023-11-20_19-12-12-version-1-modificationdate-1700503938534-api-v2.png

Unusual example: Determining key figures for company accounts

A tuple search should determine three 'statistical key figures' for the addresses of Company accounts maintained in the system:

  • Count of all Company accounts (column: COMPANIES)

  • Count of all Company accounts in whose address (address) a Country is selected in the 'Country' (countryCode) property (column: WITH_COUNTRY)

  • Number of different Country values in the 'Country' (countryCode) property in the addresses of companies (column: COUNTRIES)

Runtime example:

The key figures for the evaluation should 'aggregate' all companies for which read access exists in the execution context.

This means:

  • The search works without grouping.

  • Only exactly one result line is expected (see example data), if a company (with read access) exists at all.

   <core:TupleSearchResult maxResults="100" count="1">
<columns>
<name>COMPANIES</name>
<name>WITH_COUNTRY</name>
<name>COUNTRIES</name>
</columns>
<result>
<row>
<item xsi:type="xsd:long">40</item>
<item xsi:type="xsd:long">28</item>
<item xsi:type="xsd:long">10</item>
</row>
</result>
</core:TupleSearchResult>

Configuration:

Three Projections of the Aggregate type are required for the output columns of the tuple search:

The COMPANIES column should show the number of all evaluated Company accounts.

The Type 'Count' enables this in conjunction with a Property projection that refers to the 'ID' (id) property of the company. The result provides the number of Company accounts for which read access exists, subject to two conditions:

  1. The Projection does not return 'No value' ($null) for any company, which is certainly the case for the 'ID' property.

  2. There is always exactly one result line per company. This applies as long as no Projections on multi-value properties are used (see the following variant).

images/download/attachments/157877408/image-2023-11-20_19-13-21-version-1-modificationdate-1700504007637-api-v2.png

The WITH_COUNTRY column shows the number of all evaluated Company accounts in whose address field 'Country' (countryCode) a Country is selected.

Since the Type 'Count' only takes into account the values from the Projection that are not $null, it uses the Property projection on the path to the property in question (address.countryCode) to return exactly the number searched for, as long as it is guaranteed that none of the other Projections affect a multi-value property (see the following variant).



images/download/attachments/157877408/image-2023-11-20_19-14-20-version-1-modificationdate-1700504067191-api-v2.png

The COUNTRIES column is intended to indicate the number of different 'Countries' found in the addresses of the evaluated companies.

The Type 'Count (distinct )' (COUNT_DISTINCT) enables a Property projection in connection with the address property 'Country' (countryCode), as in the previous column.

IMPORTANT◄ The condition that no country is specified in the address is not counted. If the 'Count (distinct)' results in the value 1, this does not mean that all Company accounts are located in the same country, but only that no company address refers to a different Country.

In contrast to the Type 'Count', the Type 'Count (distinct)' is fundamentally resistant to the scenario that a multi-value projection generates several result rows per company (see following variant). The variety of values in the Projection does not increase if the same values are mentioned repeatedly.

images/download/attachments/157877408/image-2023-11-20_19-14-57-version-1-modificationdate-1700504104537-api-v2.png

Variant:

Based on the existing configuration, an additional output column (HAS_PARENT) is added which specifies the number of Company accounts whose list field 'parent companies' (parentCompanies) contains at least one entry.

Based on the projection for the WITH_COUNTRY column, the number of companies with filled 'parent companies' (parentCompanies) could be determined as shown on the right.


images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg CAUTIONimages/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg This approach works formally in an 'error-free' way, but by no means delivers the expected results.


It is important to understand what happens when you add the projection shown on the right to the existing ones (see above).

With the same company data as in the runtime example above, the extended tuple search returns the following result:

images/download/attachments/157877408/image-2023-11-20_19-16-2-version-1-modificationdate-1700504168883-api-v2.png

   <core:TupleSearchResult maxResults="100" count="1">
<columns>
<name>COMPANIES</name>
<name>WITH_COUNTRY</name>
<name>COUNTRIES</name>
<name>HAS_PARENT</name>
</columns>
<result>
<row>
<item xsi:type="xsd:long">57</item>
<item xsi:type="xsd:long">45</item>
<item xsi:type="xsd:long">10</item>
<item xsi:type="xsd:long">46</item>
</row>
</result>
</core:TupleSearchResult>

Without a direct comparison to the previous result, the result data makes a thoroughly 'unsuspicious' impression.

However, the COMPANIES and WITH_COUNTRY columns now return higher values (57←40 and 45←28) than before the extension, without additional Company accounts having been created or their addresses having been edited.

Why? The added Aggregate refers to a multi-value property via Property projection (see also data type Long[] in the screenshot above), which causes a multiplication of the previous result rows for Company accounts with the associated list of Long references for parent companies.

The aggregation functions process the result of the 'cross product': {companies} x {parent companies}

The data linked directly or in a (1:1) relation with the company (here: the property values for id and address.countryCode) are repeated in as many result rows as 'parent companies' are referenced for the company in question.

  • For the COMPANIES column, a change to the Type 'Count (distinct)' would help, as the aggregation then only provides the number of different 'ID' values.

  • The incorrect displays for the WITH_COUNTRIES column and the new HAS_PARENT column cannot be 'corrected' so easily.

  • The COUNTRIES column shows an unchanged value because the Type 'Count (distinct)' is selected here anyway.

The following configuration for the HAS_PARENT column prevents the multiplication of the result rows before aggregation and ensures that the search returns correct data overall:


images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg CAUTIONimages/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg If the database system used does not support the use of the Subsearch projection within an aggregation function, an error message is displayed. This is the case for MSSQL, for example (see 'Alternative configuration' below).


Configuration:

An Aggregate with the Type 'Count' should include all Company accounts that have at least one parent company.

For this purpose, the Projection must return any value other than 'No value' ($null) if the number of parent companies is >0.

  • The Case projection within the Projection formulates this condition via a Field restriction and arbitrarily assigns an empty string as the return value via a Literal projection if the condition is fulfilled. Otherwise, the return value is 'No value' ($null).

  • As a check value for the Field restriction, the number of parentCompanies of the company account to which the parent search refers must be determined. This number can only be determined in the context of an Aggregate via a Subsearch projection. Direct nesting of aggregation functions is not permitted.

    • The 'Company account' type is again selected as the Entity for the sub-select.

    • The Projection for column of subselect defines the Aggregate for determining the 'number' of parent companies (parentCompanies).

    • The Property to join and Property of entity to join with parameters require a match with regard to the 'ID' (id) property. The subselect is used here as an exception to map a (1:1) relation. The inner aggregation result ('Number of parent companies') should logically be assigned to the exact company for which it was collected.

images/download/attachments/157877408/image-2023-11-20_19-20-26-version-1-modificationdate-1700504433121-api-v2.png

Alternative Configuration:

Since not every database system accepts the use of a Subsearch projection within an aggregation function, the following configuration is intended to show how the desired results can be achieved without a Subsearch projection in a given application.

In the previous approach, the Subsearch projection was used to avoid multiplying input data ('cross product' {companies} x {parent companies}) for the aggregation function.

The following alternative approach deliberately accepts the multiplication of the input data and compensates for its effect by adjusting the Type and Projection for the aggregation function.

Column

Previous projection

Conversion

Customized projection

COMPANIES

images/download/attachments/157877408/image-2023-11-20_19-13-21-version-1-modificationdate-1700504007637-api-v2.png

Previously, the Company accounts could be counted using the Type 'Count' (COUNT) because exactly one line was output per company.

The Aggregate are now converted to the Type 'Count (distinct)' (COUNT_DISTINCT), so that each company 'found' by the search (identified by the unique 'ID') is only included once in the count.

images/download/attachments/157877408/image-2023-11-20_19-22-19-version-1-modificationdate-1700504546113-api-v2.png

WITH_COUNTRY

images/download/attachments/157877408/image-2023-11-20_19-14-20-version-1-modificationdate-1700504067191-api-v2.png

The previous Aggregate utilized the effect that an aggregation with the Type 'Count' (COUNT) only counts values from the Projection that are not 'No value' ($null).

Instead, we now use a Case projection within the Projection to explicitly check whether the address property 'Country' (countryCode) to be evaluated contains a value. Only then should the Case projection transfer the 'ID' (id) of the company return value to the Aggregate.

For the Aggregate, the Type is changed to 'Count (distinct)' (COUNT_DISTINCT). This compensates for multiple mentions of the same 'ID' value if the return value is 'multiplied' because the additional projection for the HAS_PARENT column (see below) finds several parent companies.

images/download/attachments/157877408/image-2023-11-20_19-23-45-version-1-modificationdate-1700504632488-api-v2.png

COUNTRIES


images/download/attachments/157877408/image-2023-11-20_19-14-57-version-1-modificationdate-1700504104537-api-v2.png

The projection for the COUNTRIES column can be retained unchanged, as the Type 'Count (distinct)' (COUNT_DISTINCT) is already used here.

Multiplying the input values for the aggregation does not change the variety of countries.

unchanged:
images/download/attachments/157877408/image-2023-11-20_19-14-57-version-1-modificationdate-1700504104537-api-v22.png

HAS_PARENT

not yet available
(or realized via Subsearch projection; see above)

The projection for the HAS_PARENT column reproduces the concept for the WITH_COUNTRY column:

  • In the Projection, the 'parent companies' list (parentCompanies) is checked for content using Case projection.

  • The Field restriction applies to each listed reference for a parent company. Only then should the Case projection transfer the 'ID' (id) of the child company return value to the Aggregate.

  • The Aggregate use the Type 'Count (distinct)' (COUNT_DISTINCT), so that each ID of a 'child' company is simply included in the count. The IDs of companies without a parent company do not appear in the count anyway because there is no ELSE branch with a projection in the Case projection.

images/download/attachments/157877408/image-2023-11-20_19-25-19-version-1-modificationdate-1700504725590-api-v2.png