Joins

The following types are available for the explicit configuration of Joins:

NOTE

  • Joins are typically created in the configuration of a search (or a Sub search or Subsearch projection) at a parent level in order to use the alias name defined in the further configuration of the search.

  • If required, Joins can also be used to create a Chained projection (see there for examples). The alias names used are not valid outside the projection.

  • Joins can also be used in the context of data grid settings to include additional data in the Tuple search for an overview. A 'Joins' tab is available for this in the context of the column configuration. Although the Joins configured in this way are formally related to a specific column of the data grid, they can be addressed in the context of the entire data grid definition via the assigned alias name. On the other hand, it is important to ensure that there are no different definitions in different columns for the same alias name.


Background

All Search types in Produktnam require the selection of an entity type (in the 'Entity' property), which defines the primary data source for the 'Search'.

The selection of the entity determines which database table the database query generated for the search in the FROM section of the SELECT statement directly refers to.

The FROM section of a SELECT statement can also contain several JOIN sections in order to include the results of other table accesses in the search.

Within each JOIN section, the complex ON condition determines which criteria must be met for data records from the JOIN table to be considered 'related' to a specific data record from the FROM table.

Example diagram

A CANDIDATES table evaluates in the LEVEL column the knowledge of candidates identified in the NAME column in relation to the language named in the LANGUAGE column:

'CANDIDATES' table

NAME

LANGUAGE

LEVEL

Agneta

en

4

Agneta

sv

5

Bruno

en

1

Bruno

it

5

Charles

en

5

Charles

fr

2

Diego

en

3

Diego

es

5

Emilia

de

3

Emilia

en

2

Emilia

it

5

Florence

fr

5

A further TASKS table defines the required 'English language skills' (EN_LEVEL) for the tasks named in the TASK column:

'TASKS' table

TASK

EN_LEVEL

Service Desk

4

Pool supervisor

3

Housekeeping

2

Security

2

The following slightly simplified SELECT statement aims to form an intersection between TASKS and suitable CANDIDATES :

SELECT TASK, NAME FROM TASKS INNER JOIN CANDIDATES ON ((LANGUAGE = 'en') AND (LEVEL >= EN_LEVEL))

Result:

TASK

NAME

Service Desk

Agneta

Service Desk

Charles

Pool supervisor

Agneta

Pool supervisor

Charles

Pool supervisor

Diego

Housekeeping

Agneta

Housekeeping

Charles

Housekeeping

Diego

Housekeeping

Emilia

Security

Agneta

...

...

The SELECT statement creates a 'cross product' TASKS x CANDIDATES and returns only those combinations of TASK (from TASKS) and NAME (from CANDIDATES) as 'matches' (=result lines) for which sufficient knowledge of English is available (ON condition).

An INNER JOIN is explicitly used here because the result should be exactly the intersection of CANDIDATES and TASKS defined by the ON condition.

  • In contrast to this, a LEFT JOIN would also list TASKS in the result for which none of the CANDIDATES is sufficiently qualified. The NAME column would then remain empty.

  • CANDIDATES unsuitable for all TASKS (here: 'Bruno' and 'Florence') cannot be found in either the INNER JOIN or the LEFT JOIN. These would only be listed via RIGHT JOIN with an empty TASK column.

    IMPORTANT◄ In the context of a search in Lobster Data Platform / Orchestration, in many cases a RIGHT JOIN cannot 'work' in the same way as it would directly on a database. By default, explicitly configured Joins (as well as any implicitly generated ones; see below for details) are executed as a LEFT JOIN.

Implicitly generated joins

When executing a 'search', at least one SELECT statement is generated based on the configuration of the search and – if this succeeds without error – transferred to the database.

Data storage for an entity type often extends across several database tables, the relationship between which is then also more or less strictly 'regulated' on the database side, depending on the data model for the entity.

If the relationship between an entity and the data managed in a 'detail table' is sufficiently binding, the relevant relations are automatically 'resolved' when accessing detail properties in Projections, without the need to explicitly configure Joins.


NOTE◄ If different Projections imply exactly the same join, this is generally not executed redundantly on the database side, but is used jointly within the generated SELECT statement.



Example: Users ←(1 : 1)→ Addresses

images/download/attachments/167858318/image-2024-1-22_8-36-9-version-1-modificationdate-1705908970109-api-v2.png

In a Tuple search for Users, a Property projection accesses the 'Name' address property (address.name1).

This search returns the desired result without any further precautions, although only the 'username' (username) can be found directly in the database table for Users ( base_user ).

Access to the 'address' requires a LEFT JOIN to the database table base_address , which contains all addresses known in the system.

This LEFT JOIN, including the ON condition relevant to the context, is generated automatically when the database query is executed.

The following SELECT statement is generated for this simple Tuple search:


SELECT username, name1 FROM base_user LEFT JOIN base_address ON (id = address_id)


  • The base_user table for Users refers to the field id of the table base_address for Addresses defined as the primary key via the foreign key address_id property.

  • The ON condition requires the foreign key and primary key to match so that each user is assigned 'their' address.

  • The LEFT JOIN ensures that Users without an assigned address can also appear in the result.

Example: Users ←(1 : n) → IDs of assigned Roles

images/download/attachments/167858318/image-2024-1-22_8-36-44-version-1-modificationdate-1705909004281-api-v2.png

In a Tuple search for Users, a Property projection accesses the 'Roles' (roles) list field, which can contain several ID values of Roles as a value.

This search returns the desired result without any further precautions, although only the 'username' (username) can be found directly in the database table for Users ( base_user ).

So that several role IDs can be assigned to the same user, a specific detail table ( base_user_roles ) is required in which different role IDs ( role_id ) can be combined with the same foreign key ( user_id ) on the Users table.

Access to the 'roles' of a user again requires a LEFT JOIN.

The following SELECT statement is generated for this simple Tuple search:


SELECT username, role_id FROM base_user LEFT JOIN base_user_roles ON (id = user_id)


NOTE◄ Each role ID could in turn be interpreted as a foreign key for a data record in the table for Roles (base_role), so that there is actually an (m : n) relation (Users ←(m : n) → Roles). However, this cannot be enforced here by a Property projection such as roles.roleName, because Roles are only referenced in the data model for Users and are not embedded or contained in the data model..

Example: User ←1 : 1→ Addresses ~ Typed attribute projection

images/download/attachments/167858318/image-2024-1-22_8-37-40-version-1-modificationdate-1705909060685-api-v2.png

In a Tuple search for Users, a Typed attribute projection accesses the flag attribute for the address with the (sub)type VIP to return its 'flag value' (flagValue).

This search returns the desired result without any further precautions, although only the 'username' (username) can be found directly in the database table for Users ( base_user ).

As explained in the first example above, accessing a field of the address already implies a LEFT JOIN to the base_address table.

As can be seen in the screenshot on the left, our Typed attribute projection explicitly refers to the Attribute owner path address. By default, flag attributes for Users are not supported at all.

On the database side, the implementation of an attribute type for an owner requires a separate database table in which the attribute properties for this owner-attribute type combination are stored. Access to attribute values therefore always requires at least one implicit join.

The Projections for attributes only simplify access on the surface. However, this does not eliminate the need to look up the specific detail tables in the database.

NOTE◄ In special cases, it may be necessary to dispense with the convenience of Projections for attributes and instead set up explicit Joins for accessing attribute values.

The following SELECT statement is generated for this simple Tuple search:


SELECT username, flag_value FROM base_user
LEFT JOIN base_address ON ( id = address_id)
LEFT JOIN base_address_flag_attribute ON ((id = address_id) AND (flag_type = VIP))

NOTE◄ In the ON condition for the second LEFT JOIN, the id from the green address table (base_address) is used as the compare value for the address_id column in the red marked attribute table ( base_address_flag_attribute ). However, as can be seen in the ON condition for the first LEFT JOIN, this must match the foreign key address_id in the Users table (base_user) marked in blue. Therefore, it is possible to completely dispense with the first LEFT JOIN to the address if the foreign key address_id is compared directly with the address_id column of the attribute. This abbreviation can only be enforced in an explicit join. The implicit join will always follow the internally predefined schema (Entity → Attribute owner path → Attribute) if an Attribute owner path is specified that differs from the entity in the FROM section.

Explicitly defined joins

By explicitly defining Joins, additional data sources can be included in a search so that they are available for the definition of Projections.

  • All Search types can use Projections on Joins to define Restrictions.
    NOTE◄ An INNER JOIN can also restrict the search if necessary, without there being any restrictions at the main level of the search.

  • In a Tuple search or CSV search, data assigned via Joins can serve as Projections for Output columns and Group by's.

  • In data grid settings, data from Joins can also be used in Restriction projections (for filtering) or Sorting projections (for sorting).

  • Explicit Joins may only be required as an intermediate step in order to enable projections for key values in the ON condition of further Joins.

All Joins have the parameters shown on the right:

  • The Join alias (with the default value a) defines the name by which the structure from the Join can be addressed in the associated search. This usually also applies to Projections for Restrictions in the On condition.

  • A Join type ('Inner', 'Left', 'Right') must be selected in the Combobox. By default, 'Left' is preset, as this Join type covers the typical use case – the inclusion of any existing data records in the context of the search. The other types ('Inner' and 'Right') are often only of limited use in the context of a search or can only be used in special cases.

  • The Optional option is selected by default. This means that the configured join is only effectively used in database queries at runtime if Projections are actually created in the search configuration that access the alias name.

images/download/attachments/167858318/image-2024-1-22_8-38-32-version-1-modificationdate-1705909113128-api-v2.png

The configuration of an On condition is always optional. For all Joins except the Entity join, the context already implies a condition for the join:

An explicitly configured On condition is always combined with any applicable implicit condition in an AND junction. In this case, the join only adds data records for which both the implicit and the explicit condition apply as passed.

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg CAUTIONimages/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg An important restriction for the definition of an explicit On condition is that it must not refer to a projection with a path to a property that would imply another join.

What sounds quite complicated can be clearly understood using the following example:

  • A search for Users uses a Entity join to include the data of all Company accounts in the search whose ID is specified in the 'Companies' (companies) list field of a user account.

  • A secondary condition is that only company accounts whose address field 'Country' (address.countryCode) refers to the Country 'Switzerland' (CH) should be taken into account.

NOTE◄ The configuration shown on the right is not completely nonsensical, but 'just off the mark'. It is intended to demonstrate a common mistake when configuring an On condition that contains a secondary condition.


  • The Entity join refers to the 'Company account' entity type as an Entity.

  • The text abbreviation cmp was arbitrarily selected as the Join alias.

  • 'Inner' is selected as the Join type. In conjunction with unchecking the Optional option, this should force the parent search to only list Users for whom at least one company account exists that fulfills the following On condition:

    • The first Field restriction requires the company ID (cmp.id) to match an entry in the 'Companies' (companies) list field of the user account.

    • The second Field restriction is intended to ensure that the location of an assigned company is in Switzerland:

      • The 'Country' address property of the company (cmp.address.countryCode) is addressed as the check value (left).

      • The static compare value (right) is provided via a Dynamic enumeration value resolver.


This configuration returns an error message when the search is executed:


A join within a on condition is not possible

The 'Join' to which the error message refers is not the explicitly created Entity join to the company account.

However, it is problematic that the 'Country' property is addressed in the address of the company account. The path selected in the Property parameter implies a join to the address so that its 'Country' property can be evaluated. What is not difficult in the projection for an output column, for example, is not possible in the context of an On condition.

In order for the restriction for the country of the company account to be implemented effectively, the company address must be explicitly included in the search by means of an additional join.

images/download/attachments/167858318/image-2024-1-22_8-43-24-version-1-modificationdate-1705909404600-api-v2.png

The secondary bindings for the address of a company included by a join can only be effectively implemented here by an additional join for the address:

The Entity join described above can be customized as follows:

  • The Join type has been changed to 'Left'.

  • The Optional option has been unchecked.

  • The second Field restriction has been removed from the On condition.

In the form shown on the right, the Entity join first binds all Company accounts that are assigned in the companies property of a user.

A Mapped join has been added below, which refers to the 'address' property of a company provided by the first join (cmp.address) as a Join property:

  • The name cmpAddress was arbitrarily assigned as the Join alias here.

  • The Join type 'Inner' in conjunction with the unchecked Optional option ensures that the parent search returns exactly those Users as matches for which the On condition is fulfilled, which checks whether the 'Country' property of the company address (cmpAddress.countryCode) refers to the Country 'Switzerland' (CH).


images/download/attachments/167858318/image-2024-1-22_9-48-27-version-1-modificationdate-1705913307834-api-v2.png