Linking and Joining Data Items to Define the Query Dataset

Business Central queries enable you to retrieve records from one or more tables and combine the specific records into rows in a single dataset. In AL, each table is specified as a data item. The data included in the dataset is a result of how the data items are linked and joined together.

Tip

The concept of linking and joining data items in AL is similar to Join clauses in SQL Select statements on tables in SQL Server. For those familiar with SQL Joins, when describing links and joins in AL, this article provides the equivalent SQL SELECT statement in most cases.

Sample Tables and Query

To demonstrate data item links and joins, this article uses the following sample tables and query.

Salesperson/Purchaser Table

The Salesperson/Purchaser table contains a list of salespersons. Each salesperson is identified by a unique code. The following is a simplified version of the Salesperson/Purchaser table for demonstration purposes.

Code Name
AA Annette
BB Bart
DD Debra
JJ John

Sales Header Table

The Sales Header table contains a list of sales orders. Each sales order has a unique number, includes the name of the customer to sell to, and is assigned to a salesperson by the Salesperson_Code column. The following is a simplified version of the Sales Header table for demonstration purposes.

No. Sell-to Customer Name Salesperson Code
1000 Autohaus AA
2000 Blanemark DD
3000 Candoxy JJ
4000 New Concepts

Sample Query

The following query object links the Sale Header table with the Salesperson/Purchaser table on the Salesperson_Code and Code fields, as specified by the DataItemLink Property. In the example, the SQLJoinType Property is set to InnerJoin.

query 50100 "Sample Query"
{
    QueryType = Normal;
    Caption = 'Sales Overview';

    elements
    {
        dataitem(Salesperson_Purchaser; "Salesperson/Purchaser")
        {
            column(Salesperson; Name)
            {

            }
            dataitem(Sales_Header; "Sales Header")
            {
                DataItemLink = "Salesperson Code" = Salesperson_Purchaser.Code;
                // Change the SqlJoinType value to suit the desired results: LeftOuterJoin, InnerJoin, RighOuterJoin, FullJoin, CrossJoin.
                SqlJoinType = InnerJoin;

                column(Order_Number; "No.")
                {

                }
                column(Sell_to_Customer; "Sell-to Customer Name")
                {

                }
            }
        }
    }
}

When you add data items to a query object in AL, you define them in a specific hierarchy, one after another. Each lower data item is embedded within the definition of the upper data item. The order of the data items determines the sequence in which data items are linked and joined to produce the results in the dataset.

In short, to join two data items, you set the DataItemLink and SqlJoinType properties on the lower data item in the query object.

Note

In the sections that follow, some examples illustrate the use of either the WHERE clause and FROM clause to get the same results. However, for better performance, we recommend using a FROM clause wherever possible.

The DataItemLink Property sets up a reference or association between one or more fields in the source table of a lower data item tables with a field in the source table of the upper data item. In a query, two data item tables typically will have columns that have values that are common to both tables. For example, the Salesperson table and Sales Header table have the Code column and Salesperson_Code column in common. To create a link between these two tables, you could set the DataItemLink property of the Sales Header data item as follows:

DataItemLink = "Salesperson Code" = Salesperson_Purchaser.Code;

The DataItemLink Property sets up an "equal to" (=) comparison condition between two columns of the data items. When the query is run, the query compares each row of the two data items to find records that having matching values for the columns. Records that have matching column values are combined into a row in the resulting dataset. In some cases, there will be records that don't have matching values. You use the SqlJoinType Property to include records that don't have matching column values.

Set the SqlJoinType Property

The SqlJoinType Property determines which records to combine into the results, based on the values of the fields linked by the DataItemLink property. You use this property to limit the records that are included in the resulting dataset based on the specified conditions. By default, the SqlJoinType property is LeftOuterJoin, so if you omit this property, a LeftOuterJoin is performed.

Tip

In SQL join statements, tables are designated as either left or right. In AL query objects, because data items are arranged vertically, when joining data items, the left corresponds to the upper data item (table) and right corresponds to the lower data item (table).

Linking More Than Two Data Items

A query links data items in the order that they appear in AL, starting from the top and then working downward. When you have more than two data items, lower data items are linked to the resulting dataset of the linked data items above it. For example, when you link the first two data items, the query generates a dataset. When you add another data item, it's linked to the dataset of the first linked pair of data items, where it applies the conditions that are specified by its DataItemLink Property and SqlJoinType Property. The following code adds another data item to the sample query:

query 50100 "Sample Query"
{
    QueryType = Normal;
    Caption = 'Sales Overview';

    elements
    {
        dataitem(Salesperson_Purchaser; "Salesperson/Purchaser")
        {
            column(Salesperson; Name)
            {

            }
            dataitem(Sales_Header; "Sales Header")
            {
                DataItemLink = "Salesperson Code" = Salesperson_Purchaser.Code;
                SqlJoinType = InnerJoin;

                column(Order_Number; "No.")
                {

                }
                column(Sell_to_Customer; "Sell-to Customer Name")
                {

                }
                dataitem(Sales_Line; "Sales Line")
                {
                    DataItemLink = "Sell-to Customer No." = Sales_Header."Sell-to Customer No.";
                }
            }
        }
    }
}

This pattern continues for each extra data item.

InnerJoin

InnerJoin creates a dataset by combining records from data item tables where a match is found between the columns that are linked by the DataItemLink Property of the lower data item. Inner Join uses an "equal to" comparison operator to match rows from the lower data item table with rows from the upper data item table that is based on the values of the linked columns.

  • Each pair of matching records is combined into a row in the dataset.

  • Records from the upper and lower data item tables that don't have a matching column in the lower data item table are excluded from the resulting dataset.

The following illustration shows an InnerJoin type between tables A and B. The shaded area indicates the records that are included in the resulting dataset.

Visualization of SQL inner join between two tables.

Dataset Example

The following table shows the resulting dataset for an InnerJoin between the Sales Header table and Salesperson/Purchaser table in sample query.

Salesperson Order_Number Sell_to_Customer
Annette 1000 Autohaus
Debra 2000 Blanemark
John 3000 Candoxy

The records for Bart in the Salesperson table and New Concepts in the Sales Header table don't have matching records in the opposing table, so they are excluded from the resulting dataset.

SQL SELECT Statement for Inner Join

To specify an inner join with an SQL statement, you can do either of the following:

  • Use a WHERE clause.
  • Use the INNER JOIN condition with an ON clause.

The following two examples show how to create an inner join on the Salesperson/Purchaser and Sales Header tables with SQL statements. These two statements result in the same dataset.

SELECT "Salesperson/Purchaser".Name, "Sales Header"."No.", "Sales Header"."Sell-to Customer Name"  
FROM "Salesperson/Purchaser" INNER JOIN "Sales Header"  
  ON "Salesperson/Purchaser".Code = "Sales Header"."Salesperson Code"  
SELECT "Salesperson/Purchaser".Name, "Sales Header"."No.", "Sales Header"."Sell-to Customer Name"  
FROM "Salesperson/Purchaser", "Sales Header"  
WHERE "Salesperson/Purchaser".Code = "Sales Header"."Salesperson Code"  

LeftOuterJoin

A LeftOuterJoin resembles the InnerJoin except that the resulting dataset set contains every record from the upper data item table, even if a record does not have a matching value in the lower data item for columns that are linked by the DataItemLink Property.

  • For each record in the upper data item, a row is added in the dataset that combines columns from the upper and lower data item.

  • When a record in the upper data item table has no matching record in the lower data item table, columns coming from the lower data item table have null values.

The following illustration shows a LeftOuterJoin type between tables A and B. The shaded area indicates the records that are included in the resulting dataset. In the sample query, the Salesperson/Purchaser table is considered the left table.

Visualization of SQL left outer join.

Dataset Example

The following table shows the resulting dataset for a LeftOuterJoin between the Sales Header table and Salesperson/Purchaser table in sample query.

Salesperson Order_Number Sell_to_Customer
Annette 1000 Autohaus
Bart null null
Debra 2000 Blanemark
John 3000 Candoxy

The record for Bart in the Salesperson/Purchaser table does not have a matching record in the Sales Header table, so a row is included but the columns from the Sale Header table are given null values. The record for New Concepts in the Sale Header table is not included in the resulting dataset because it does not have a matching column in the Salesperson/Purchaser table.

SQL SELECT Statement for Left Outer Join

To specify a left outer join with an SQL statement, you use the LEFT OUTER JOIN condition.

The following example shows how to create a left outer join on the Salesperson/Purchaser and Sales Header tables by using a SQL statement.

SELECT "Salesperson/Purchaser".Name, "Sales Header"."No.", "Sales Header"."Sell-to Customer Name"  
FROM "Salesperson/Purchaser" LEFT OUTER JOIN "Sales Header"  
  ON "Salesperson/Purchaser".Code = "Sales Header"."Salesperson Code"  

RightOuterJoin

A RightOuterJoin resembles the inner join except that the resulting dataset set contains every record from the lower data item table, even if a record does not have a matching value in the upper data item for columns that are linked by the DataItemLink Property.

  • For each record in the lower data item, a row is added in the dataset that combines columns from the lower and upper data item tables.

  • When a record in the lower data item table has no matching record in the upper data item table, columns coming from the upper data item table have null values.

The following illustration shows a RightOuterJoin type between tables A and B. The shaded area indicates the records that are included in the resulting dataset.

Visualization of SQL right outer join.

Dataset Example

The following table shows the resulting dataset for a RightOuterJoin between the Salesperson/Purchaser table and Sales Header table in the sample query. The Sales Header table is considered the right table.

Salesperson Order_Number Sell_to_Customer
Annette 1000 Autohaus
Debra 2000 Blanemark
John 3000 Candoxy
null 4000 New Concept

The record for New Concepts in the Sales Header table does not have a matching record in the Salesperson/Purchaser table, so a row is included but the columns from the Salesperson/Purchaser table are given null values. The record for Bart in the Salesperson/Purchaser table is not included in the resulting dataset because it does not have a matching column in the Sales Header table.

SQL SELECT Statement for Right Outer Join

To specify a right outer join with an SQL statement, you use the RIGHT OUTER JOIN condition.

The following example shows how to create a right outer join on the Salesperson/Purchaser and Sales Header tables by using a SQL statement.

SELECT "Salesperson/Purchaser".Name, "Sales Header"."No.", "Sales Header"."Sell-to Customer Name"  
FROM "Salesperson/Purchaser" RIGHT OUTER JOIN "Sales Header"  
  ON "Salesperson/Purchaser".Code = "Sales Header"."Salesperson Code"  

FullOuterJoin

A FullOuterJoin contains all the records from the upper data item table, and all records from the lower data item, including records that don't have a matching value for columns that are linked by the DataItemLink Property.

  • Each pair of records from the data items that have matching column values are combined into a row in the dataset.

  • Records from the upper data item table that do have a matching column are included in a row, where the columns from lower data item table have null values.

  • Records from the lower data item table that do have a matching column are included in a row, where the columns from upper data item table have null values.

The following illustration shows a FullOuterJoin type between tables A and B. The shaded area indicates the records that are included in the resulting dataset.

Visualization of an SQL full outer join.

Dataset Example

The following table shows the resulting dataset for a full outer join between the Sales Header table and Salesperson/Purchaser table in sample query.

Salesperson Order_Number Sell_to_Customer
Annette 1000 Autohaus
Bart null null
Debra 2000 Blanemark
John 3000 Candoxy
null 4000 New Concept

The records for Bart in the Salesperson/Purchaser table and New Concepts in the Sales Header table are included in a row, even though they not have matching values for columns.

SQL SELECT Statement for Full Outer Join

To specify a full outer join with an SQL statement, you use the FULL OUTER JOIN condition.

The following example shows how to create a full outer join on the Salesperson/Purchaser and Sales Header tables by using a SQL statement.

SELECT "Salesperson/Purchaser".Name, "Sales Header"."No.", "Sales Header"."Sell-to Customer Name"  
FROM "Salesperson/Purchaser" FULL OUTER JOIN "Sales Header"  
  ON "Salesperson/Purchaser".Code = "Sales Header"."Salesperson Code"  

CrossJoin

A CrossJoin contains rows that combine each row from the upper data item table with each row from a lower data item table. Cross joins are also called Cartesian products. A cross join does not apply any comparisons between columns of data items, so the DataItemLink Property is left blank.

Dataset Example

The following table shows the resulting dataset for a CrossJoin between the Sales Header table and Salesperson/Purchaser table in sample query.

Salesperson Order_Number Sell_to_Customer
Annette 1000 Autohaus
Annette 2000 Blanemark
Annette 3000 Candoxy
Annette 4000 New Concept
Bart 1000 Autohaus
Bart 2000 Blanemark
Bart 3000 Candoxy
Bart 4000 New Concept
Debra 1000 Autohaus
Debra 2000 Blanemark
Debra 3000 Candoxy
Debra 4000 New Concept
John 1000 Autohaus
John 2000 Blanemark
John 3000 Candoxy
John 4000 New Concept

SQL SELECT Statement for Cross Join

To specify a cross join with a SQL statement, you can do either of the following:

  • Use the CROSS JOIN condition

  • Create an implicit join, which has no join condition, without using a WHERE clause

The following examples shows how to create a cross join of the Salesperson/Purchaser and Sales Header tables by using a SQL statement.

SELECT "Salesperson/Purchaser".Name, "Sales Header"."No.", "Sales Header"."Sell-to Customer Name"  
FROM "Salesperson/Purchaser" CROSS JOIN "Sales Header"  
SELECT "Salesperson/Purchaser".Name, "Sales Header"."No.", "Sales Header"."Sell-to Customer Name"  
FROM "Salesperson/Purchaser", "Sales Header"  

Query Object
Filtering Queries
Aggregating Data