4D v15

Support of joins

Home

 
4D v15
Support of joins

Support of joins  


 

 

The SQL engine of 4D extends the support of joins.

Join operations may be inner or outer, implicit or explicit. Implicit inner joins are support via the SELECT command. You can also generate explicit inner and outer joins using the SQL JOIN keyword.

Note: The current implementation of joins in the 4D SQL engine does not include:

  • natural joins.
  • the USING construct on inner joins.
  • cross inner joins.

Join operations are used to make connections between the records of two or more tables and combine the result in a new table, called a join. 

You generate joins via SELECT statements that specify the join conditions. With explicit joins, these conditions can be complex but they must always be based on an equality comparison between the columns included in the join. For example, it is not possible to use the >= operator in an explicit join condition. Any type of comparison can be used in an implicit join.
Internally, equality comparisons are carried out directly by the 4D engine, which ensures rapid execution. 

Note: Usually, in the database engine, the table order is determined by the order specified during the search. However, when you use joins, the order of the tables is determined by the list of tables. In the following example:
SELECT * FROM T1 RIGHT OUTER JOIN T2 ON T2.depID = T1.depID;
... the order of the tables is T1 then T2 (as they appear in the list of tables) and not T2 then T1 (as they appear in the join condition).

To illustrate how joins work, we are going to use the following database throughout this section:

  • Employees
    namedepIDcityID
    Alan1030
    Anne1139
    Bernard1033
    Fabrice1235
    Martin1530
    PhilipNULL33
    Thomas10NULL
  • Departments
    depIDdepName
    10Program
    11Engineering
    NULLMarketing
    12Development
    13Quality
  • Cities
    cityIDcityName
    30Paris
    33New York
    NULLBerlin

If you want, you can generate this database automatically by executing the following code:

 Begin SQL
         DROP TABLE IF EXISTS Employees;
         CREATE TABLE Employees ( depID INT32, name VARCHAR, cityID INT32);
         INSERT INTO Employees (name, depID, cityID) VALUES ('Alan', 10, 30);
         INSERT INTO Employees (name, depID, cityID) VALUES ('Anne', 11, 39);
         INSERT INTO Employees (name, depID, cityID) VALUES ('Bernard', 10, 33);
         INSERT INTO Employees (name, depID, cityID) VALUES ('Fabrice', 12, 35);
         INSERT INTO Employees (name, depID, cityID) VALUES ('Martin', 15, 30);
         INSERT INTO Employees (name, depID, cityID) VALUES ('Philip', NULL, 33);
         INSERT INTO Employees (name, depID, cityID) VALUES ('Thomas', 10, NULL);
 
         DROP TABLE IF EXISTS Departments;
         CREATE TABLE Departments ( depID INT32, depName VARCHAR );
         INSERT INTO Departments (depID, depName) VALUES (10, 'Program');
         INSERT INTO Departments (depID, depName) VALUES (11, 'Engineering');
         INSERT INTO Departments (depID, depName) VALUES (NULL, 'Marketing');
         INSERT INTO Departments (depID, depName) VALUES (12, 'Development');
         INSERT INTO Departments (depID, depName) VALUES (13, 'Quality');
 
         DROP TABLE IF EXISTS Cities;
         CREATE TABLE Cities ( cityID INT32, cityName VARCHAR );
         INSERT INTO Cities (cityID, cityName) VALUES (30, 'Paris');
         INSERT INTO Cities (cityID, cityName) VALUES (33, 'New York');
         INSERT INTO Cities (cityID, cityName) VALUES (NULL, 'Berlin');
 End SQL

An inner join is based on a comparison to find matches between two columns.

Here is an example of an implicit inner join:

SELECT *  
        FROM employees, departments
        WHERE employees.DepID = departments.DepID;

In 4D, you can also use the JOIN keyword to specify an explicit inner join:

SELECT *
        FROM employees
        INNER JOIN departments
            ON employees.DepID = departments.DepID;

You can insert this query into 4D code as follows:

 ARRAY TEXT(aName;0)
 ARRAY TEXT(aDepName;0)
 ARRAY INTEGER(aEmpDepID;0)
 ARRAY INTEGER(aDepID;0)
 Begin SQL
        SELECT Employees.name, Employees.depID, Departments.depID, Departments.depName
        FROM Employees
                INNER JOIN Departments
                    ON Employees.depID = Departments.depID
                INTO :aName, :aEmpDepID, :aDepID, :aDepName;
 End SQL

Here are the results of this join:

aNameaEmpDepIDaDepIDaDepName
Alan1010Program
Anne1111Engineering
Bernard1010Program
Mark1212Development
Thomas1010Program

Note that neither the employees named Philip or Martin nor the Marketing or Quality departments appear in the resulting join because:

  • Philip does not have a department associated with his name (NULL value),
  • The department ID associated with Martin’s name does not exist in the Departments table,
  • There is no employee associated with the Quality department (ID 13),
  • The Marketing department does not have an ID associated with it (NULL value).

You can now generate outer joins with 4D. With outer joins, it is not necessary for there to be a match between the rows of joined tables. The resulting table contains all the rows of the tables (or of at least one of the joined tables) even if there are no matching rows. This means that all the information of a table can be used, even if the rows are not completely filled in between the different joined tables. 

There are three types of outer joins, specified using the LEFT, RIGHT and FULL keywords. LEFT and RIGHT are used to indicate the table (located to the left or right of the JOIN keyword) where all the data must be processed. FULL indicates a bilateral outer join.

Note: Only explicit outer joins are supported by 4D.

The result of a left outer join (or left join) always contains all the records for the table located to the left of keyword even if the join condition does not find a matching record in the table located to the right. This means that for each row in the left table where the search does not find any matching row in the right table, the join will still contain this row but it will have NULL values in each column of the right table. In other words, a left outer join returns all the rows of the left table plus any of those of the right table that match the join condition (or NULL if none match). Note that if the right table contains more than one row that matches the join predicate for a single row of the left table, the values of the left table will be repeated for each distinct row of the right table. 

Here is an example of 4D code with a left outer join:

 ARRAY TEXT(aName;0)
 ARRAY TEXT(aDepName;0)
 ARRAY INTEGER(aEmpDepID;0)
 ARRAY INTEGER(aDepID;0)
 Begin SQL
        SELECT Employees.name, Employees.depID, Departments.depID, Departments.depName
            FROM Employees
            LEFT OUTER JOIN Departments
                ON Employees.DepID = Departments.DepID
                INTO :aName, :aEmpDepID, :aDepID, :aDepName;
 End SQL

Here is the result of this join with our example database (additional rows shown in red):

aNameaEmpDepIDaDepIDaDepName
Alan1010Program
Anne1111Engineering
Bernard1010Program
Mark1212Development
Thomas1010Program
Martin15NULLNULL
PhilipNULLNULLNULL

A right outer join is the exact opposite of a left outer join. Its result always contains all the records of the table located to the right of the JOIN keyword even if the join condition does not find any matching record in the left table. 

Here is an example of 4D code with a right outer join:

 ARRAY TEXT(aName;0)
 ARRAY TEXT(aDepName;0)
 ARRAY INTEGER(aEmpDepID;0)
 ARRAY INTEGER(aDepID;0)
 Begin SQL
        SELECT Employees.name, Employees.depID, Departments.depID, Departments.depName
            FROM Employees
            RIGHT OUTER JOIN Departments
                ON Employees.DepID = Departments.DepID;
                INTO :aName, :aEmpDepID, :aDepID, :aDepName;
 End SQL

Here is the result of this join with our example database (additional rows shown in red):

aNameaEmpDepIDaDepIDaDepName
Alan1010Program
Anne1111Engineering
Bernard1010Program
Mark1212Development
Thomas1010Program
NULLNULLNULLMarketing
NULLNULL13Quality

A full outer join simply combines together the results of a left outer join and a right outer join. The resulting join table contains all the records of the left and right tables and fills in the missing fields on each side with NULL values. 

Here is an example of 4D code with a full outer join:

 ARRAY TEXT(aName;0)
 ARRAY TEXT(aDepName;0)
 ARRAY INTEGER(aEmpDepID;0)
 ARRAY INTEGER(aDepID;0)
 Begin SQL
        SELECT Employees.name, Employees.depID, Departments.depID, Departments.depName
            FROM Employees
            FULL OUTER JOIN Departments
                ON Employees.DepID = Departments.DepID
                INTO :aName, :aEmpDepID, :aDepID, :aDepName;
 End SQL

Here is the result of this join with our example database (additional rows shown in red):

aNameaEmpDepIDaDepIDaDepName
Alan1010Program
Anne1111Engineering
Bernard1010Program
Mark1212Development
Thomas1010Program
Martin15NULLNULL
PhilipNULLNULLNULL
NULLNULLNULLMarketing
NULLNULL13Quality

 
PROPERTIES 

Product: 4D
Theme: Using SQL in 4D

 
HISTORY 

 
ARTICLE USAGE

4D SQL Reference ( 4D v15)