Play with Mysql Series - Part 11: In-depth understanding of connection queries and principles

This is the 11th article in the Mysql series.

Environment: mysql5.7.25, demonstrated in cmd command.

When the data we query comes from multiple tables, we need to use connection query. The usage rate of connection query is very high. I hope everyone must master it.

Text content

  1. Cartesian Product

  2. inner join

  3. outer join

  4. left join

  5. right join

  6. The principle of table join

  7. Use java to implement connection queries and deepen understanding

Prepare data

2 tables:

t_team: group table.

t_employee: employee table, there is an internal team_id that refers to the id of the group table.

drop table if exists t_team;
create table t_team(
  id int not null AUTO_INCREMENT PRIMARY KEY comment '组id',
  team_name varchar(32) not null default '' comment '名称'
) comment '组表';

drop table if exists t_employee;
create table t_employee(
  id int not null AUTO_INCREMENT PRIMARY KEY comment '部门id',
  emp_name varchar(32) not null default '' comment '员工名称',
  team_id int not null default 0 comment '员工所在组id'
) comment '员工表表';

insert into t_team values (1,'架构组'),(2,'测试组'),(3,'java组'),(4,'前端组');
insert into t_employee values (1,'路人甲Java',1),(2,'张三',2),(3,'李四',3),(4,'王五',0),(5,'赵六',0);

t_teamTable 4 records are as follows:

mysql> select * from t_team;
+----+-----------+
| id | team_name |
+----+-----------+
|  1 | 架构组    |
|  2 | 测试组    |
|  3 | java组    |
|  4 | 前端组    |
+----+-----------+
4 rows in set (0.00 sec)

t_employeeTable 5 records are as follows:

mysql> select * from t_employee;
+----+---------------+---------+
| id | emp_name      | team_id |
+----+---------------+---------+
|  1 | 路人甲Java    |       1 |
|  2 | 张三          |       2 |
|  3 | 李四          |       3 |
|  4 | 王五          |       0 |
|  5 | 赵六          |       0 |
+----+---------------+---------+
5 rows in set (0.00 sec)

Cartesian Product

Before introducing join queries, we need to first understand the Cartesian product.

A simple understanding of the Cartesian product: There are two sets A and B. The Cartesian product represents all possible results produced by any correlation between the elements in the A set and the elements in the B set.

If there are m elements in A and n elements in B, the Cartesian product of A and B produces m*n results, which is equivalent to looping through the elements in the two sets in any combination.

The java pseudo code is expressed as follows:

for(Object eleA : A){
    for(Object eleB : B){
        System.out.print(eleA+","+eleB);
    }
}

Process: Take the first row in set A to match all the rows in set B, and then take the second row in set A to match all the rows in set B. The final number of results is m*n.

Cartesian product syntax in sql

select 字段 from 表1,表2[,表N];
或者
select 字段 from 表1 join 表2 [join 表N];

Example:

mysql> select * from t_team,t_employee;
+----+-----------+----+---------------+---------+
| id | team_name | id | emp_name      | team_id |
+----+-----------+----+---------------+---------+
|  1 | 架构组    |  1 | 路人甲Java    |       1 |
|  2 | 测试组    |  1 | 路人甲Java    |       1 |
|  3 | java组    |  1 | 路人甲Java    |       1 |
|  4 | 前端组    |  1 | 路人甲Java    |       1 |
|  1 | 架构组    |  2 | 张三          |       2 |
|  2 | 测试组    |  2 | 张三          |       2 |
|  3 | java组    |  2 | 张三          |       2 |
|  4 | 前端组    |  2 | 张三          |       2 |
|  1 | 架构组    |  3 | 李四          |       3 |
|  2 | 测试组    |  3 | 李四          |       3 |
|  3 | java组    |  3 | 李四          |       3 |
|  4 | 前端组    |  3 | 李四          |       3 |
|  1 | 架构组    |  4 | 王五          |       0 |
|  2 | 测试组    |  4 | 王五          |       0 |
|  3 | java组    |  4 | 王五          |       0 |
|  4 | 前端组    |  4 | 王五          |       0 |
|  1 | 架构组    |  5 | 赵六          |       0 |
|  2 | 测试组    |  5 | 赵六          |       0 |
|  3 | java组    |  5 | 赵六          |       0 |
|  4 | 前端组    |  5 | 赵六          |       0 |
+----+-----------+----+---------------+---------+
20 rows in set (0.00 sec)

The t_team table has 4 records, the t_employee table has 5 records, and the Cartesian product result outputs 20 rows of records.

inner join

grammar:

select 字段 from 表1 inner join 表2 on 连接条件;
或
select 字段 from 表1 join 表2 on 连接条件;
或
select 字段 from 表1, 表2 [where 关联条件];

Inner join is equivalent to adding connection conditions on the basis of Cartesian product.

When there are no join conditions, the inner join rises to a Cartesian product.

The process uses java pseudo code as follows:

for(Object eleA : A){
    for(Object eleB : B){
        if(连接条件是否为true){
            System.out.print(eleA+","+eleB);
        }
    }
}

Example 1: There are join conditions

Query employees and departments they belong to

mysql> select t1.emp_name,t2.team_name from t_employee t1 inner join t_team t2 on t1.team_id = t2.id;
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
| 张三          | 测试组    |
| 李四          | java组    |
+---------------+-----------+
3 rows in set (0.00 sec)

mysql> select t1.emp_name,t2.team_name from t_employee t1 join t_team t2 on t1.team_id = t2.id;
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
| 张三          | 测试组    |
| 李四          | java组    |
+---------------+-----------+
3 rows in set (0.00 sec)

mysql> select t1.emp_name,t2.team_name from t_employee t1, t_team t2 where t1.team_id = t2.id;
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
| 张三          | 测试组    |
| 李四          | java组    |
+---------------+-----------+
3 rows in set (0.00 sec)

The above is equivalent to obtaining the intersection of two tables and querying the data in both tables.

Example 2: No connection conditions

Unconditional inner join, rising to Cartesian product, as follows:

mysql> select t1.emp_name,t2.team_name from t_employee t1 inner join t_team t2;
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
| 路人甲Java    | 测试组    |
| 路人甲Java    | java组    |
| 路人甲Java    | 前端组    |
| 张三          | 架构组    |
| 张三          | 测试组    |
| 张三          | java组    |
| 张三          | 前端组    |
| 李四          | 架构组    |
| 李四          | 测试组    |
| 李四          | java组    |
| 李四          | 前端组    |
| 王五          | 架构组    |
| 王五          | 测试组    |
| 王五          | java组    |
| 王五          | 前端组    |
| 赵六          | 架构组    |
| 赵六          | 测试组    |
| 赵六          | java组    |
| 赵六          | 前端组    |
+---------------+-----------+
20 rows in set (0.00 sec)

Example 3: Query by combining conditions

Query the employees of the architecture group, 3 ways to write

mysql> select t1.emp_name,t2.team_name from t_employee t1 inner join t_team t2 on t1.team_id = t2.id and t2.team_name = '架构组';
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
+---------------+-----------+
1 row in set (0.00 sec)

mysql> select t1.emp_name,t2.team_name from t_employee t1 inner join t_team t2 on t1.team_id = t2.id where t2.team_name = '架构组';
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
+---------------+-----------+
1 row in set (0.00 sec)

mysql> select t1.emp_name,t2.team_name from t_employee t1, t_team t2 where t1.team_id = t2.id and t2.team_name = '架构组';
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
+---------------+-----------+
1 row in set (0.00 sec)

The above 3 methods are explained.

Method 1: Combination conditions are used in on.

Method 2: Filter after the connection result, which is equivalent to getting the connection result first, and then using the conditions in where to filter the connection result.

Method 3: Filter directly after where.

Summarize

It is recommended to use the third syntax for inner connections, which is concise:

select 字段 from 表1, 表2 [where 关联条件];

outer join

Outer joins involve two tables, divided into: master table and slave table. Which table the information to be queried mainly comes from is the master table.

The outer join query results are all records in the main table. If there is a match from the table, the matching value is displayed, which is equivalent to the result of the inner join query; if there is no match from the table, null is displayed.

Finally: the outer join query result = the inner join result + the records that are in the main table but not in the inner join result.

There are 2 types of outer joins:

Left outer link: Use the left join keyword, and the left side of the left join is the main table.

Right outer join: Use the right join keyword, and the right join is the main table.

left join

grammar

select 列 from 主表 left join 从表 on 连接条件;

Example 1:

Query all employee information and display the group to which the employee belongs, as follows:

mysql> SELECT
        t1.emp_name,
        t2.team_name
    FROM
        t_employee t1
    LEFT JOIN
        t_team t2
    ON
        t1.team_id = t2.id;
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
| 张三          | 测试组    |
| 李四          | java组    |
| 王五          | NULL      |
| 赵六          | NULL      |
+---------------+-----------+
5 rows in set (0.00 sec)

The above query shows all employees. For employees with team_id=0, team_name is NULL.

Example 2:

Query the employee name and group name, and return records whose group name is not empty, as follows:

mysql> SELECT
        t1.emp_name,
        t2.team_name
    FROM
        t_employee t1
    LEFT JOIN
        t_team t2
    ON
        t1.team_id = t2.id
    WHERE
        t2.team_name IS NOT NULL;
+---------------+-----------+
| emp_name      | team_name |
+---------------+-----------+
| 路人甲Java    | 架构组    |
| 张三          | 测试组    |
| 李四          | java组    |
+---------------+-----------+
3 rows in set (0.00 sec)

The above first uses inner join to obtain the connection result, and then uses where to filter the connection result.

right join

grammar

select 列 from 从表 right join 主表 on 连接条件;

Example

We use right joins to implement the functions implemented by left joins above, as follows:

mysql> SELECT
        t2.team_name,
        t1.emp_name
    FROM
        t_team t2
    RIGHT JOIN
        t_employee t1
    ON
        t1.team_id = t2.id;
+-----------+---------------+
| team_name | emp_name      |
+-----------+---------------+
| 架构组    | 路人甲Java    |
| 测试组    | 张三          |
| java组    | 李四          |
| NULL      | 王五          |
| NULL      | 赵六          |
+-----------+---------------+
5 rows in set (0.00 sec)

mysql> SELECT
        t2.team_name,
        t1.emp_name
    FROM
        t_team t2
    RIGHT JOIN
        t_employee t1
    ON
        t1.team_id = t2.id
    WHERE
        t2.team_name IS NOT NULL;
+-----------+---------------+
| team_name | emp_name      |
+-----------+---------------+
| 架构组    | 路人甲Java    |
| 测试组    | 张三          |
| java组    | 李四          |
+-----------+---------------+
3 rows in set (0.00 sec)

Understand the principle of table join

Prepare data

drop table if exists test1;
create table test1(
  a int
);
drop table if exists test2;
create table test2(
  b int
);
insert into test1 values (1),(2),(3);
insert into test2 values (3),(4),(5);
mysql> select * from test1;
+------+
| a    |
+------+
|    1 |
|    2 |
|    3 |
+------+
3 rows in set (0.00 sec)

mysql> select * from test2;
+------+
| b    |
+------+
|    3 |
|    4 |
|    5 |
+------+
3 rows in set (0.00 sec)

Let's write a few connections and see the effect.

Example 1: Inner join

mysql> select * from test1 t1,test2 t2;
+------+------+
| a    | b    |
+------+------+
|    1 |    3 |
|    2 |    3 |
|    3 |    3 |
|    1 |    4 |
|    2 |    4 |
|    3 |    4 |
|    1 |    5 |
|    2 |    5 |
|    3 |    5 |
+------+------+
9 rows in set (0.00 sec)

mysql> select * from test1 t1,test2 t2 where t1.a = t2.b;
+------+------+
| a    | b    |
+------+------+
|    3 |    3 |
+------+------+
1 row in set (0.00 sec)

9 pieces of data are normal.

Example 2: Left join

mysql> select * from test1 t1 left join test2 t2 on t1.a = t2.b;
+------+------+
| a    | b    |
+------+------+
|    3 |    3 |
|    1 | NULL |
|    2 | NULL |
+------+------+
3 rows in set (0.00 sec)

mysql> select * from test1 t1 left join test2 t2 on t1.a>10;
+------+------+
| a    | b    |
+------+------+
|    1 | NULL |
|    2 | NULL |
|    3 | NULL |
+------+------+
3 rows in set (0.00 sec)

mysql> select * from test1 t1 left join test2 t2 on 1=1;
+------+------+
| a    | b    |
+------+------+
|    1 |    3 |
|    2 |    3 |
|    3 |    3 |
|    1 |    4 |
|    2 |    4 |
|    3 |    4 |
|    1 |    5 |
|    2 |    5 |
|    3 |    5 |
+------+------+
9 rows in set (0.00 sec)

The first left join above is easy to understand.

The second sql connection condition t1.a>10is only associated with the test1 table. Let’s look at the results again. Is it understandable? If you don’t understand, continue reading. We use java code to implement connection queries.

The connection condition 1=1 in the third sql has a value of true, and the returned result is a Cartesian product.

Java code implements connection query

The following is a simplified version of the implementation

package com.itsoku.sql;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

public class Test1 {
    public static class Table1 {
        int a;

        public int getA() {
            return a;
        }

        public void setA(int a) {
            this.a = a;
        }

        public Table1(int a) {
            this.a = a;
        }

        @Override
        public String toString() {
            return "Table1{" +
                    "a=" + a +
                    '}';
        }

        public static Table1 build(int a) {
            return new Table1(a);
        }
    }

    public static class Table2 {
        int b;

        public int getB() {
            return b;
        }

        public void setB(int b) {
            this.b = b;
        }

        public Table2(int b) {
            this.b = b;
        }

        public static Table2 build(int b) {
            return new Table2(b);
        }

        @Override
        public String toString() {
            return "Table2{" +
                    "b=" + b +
                    '}';
        }
    }

    public static class Record<R1, R2> {
        R1 r1;
        R2 r2;

        public R1 getR1() {
            return r1;
        }

        public void setR1(R1 r1) {
            this.r1 = r1;
        }

        public R2 getR2() {
            return r2;
        }

        public void setR2(R2 r2) {
            this.r2 = r2;
        }

        public Record(R1 r1, R2 r2) {
            this.r1 = r1;
            this.r2 = r2;
        }

        @Override
        public String toString() {
            return "Record{" +
                    "r1=" + r1 +
                    ", r2=" + r2 +
                    '}';
        }

        public static <R1, R2> Record<R1, R2> build(R1 r1, R2 r2) {
            return new Record(r1, r2);
        }
    }

    public static enum JoinType {
        innerJoin, leftJoin
    }


    public static interface Filter<R1, R2> {
        boolean accept(R1 r1, R2 r2);
    }

    public static <R1, R2> List<Record<R1, R2>> join(List<R1> table1, List<R2> table2, JoinType joinType, Filter<R1, R2> onFilter, Filter<R1, R2> whereFilter) {
        if (Objects.isNull(table1) || Objects.isNull(table2) || joinType == null) {
            return new ArrayList<>();
        }

        List<Record<R1, R2>> result = new CopyOnWriteArrayList<>();

        for (R1 r1 : table1) {
            List<Record<R1, R2>> onceJoinResult = joinOn(r1, table2, onFilter);
            result.addAll(onceJoinResult);
        }

        if (joinType == JoinType.leftJoin) {
            List<R1> r1Record = result.stream().map(Record::getR1).collect(Collectors.toList());
            List<Record<R1, R2>> leftAppendList = new ArrayList<>();
            for (R1 r1 : table1) {
                if (!r1Record.contains(r1)) {
                    leftAppendList.add(Record.build(r1, null));
                }
            }
            result.addAll(leftAppendList);
        }
        if (Objects.nonNull(whereFilter)) {
            for (Record<R1, R2> record : result) {
                if (!whereFilter.accept(record.r1, record.r2)) {
                    result.remove(record);
                }
            }
        }
        return result;
    }

    public static <R1, R2> List<Record<R1, R2>> joinOn(R1 r1, List<R2> table2, Filter<R1, R2> onFilter) {
        List<Record<R1, R2>> result = new ArrayList<>();
        for (R2 r2 : table2) {
            if (Objects.nonNull(onFilter) ? onFilter.accept(r1, r2) : true) {
                result.add(Record.build(r1, r2));
            }
        }
        return result;
    }

    @Test
    public void innerJoin() {
        List<Table1> table1 = Arrays.asList(Table1.build(1), Table1.build(2), Table1.build(3));
        List<Table2> table2 = Arrays.asList(Table2.build(3), Table2.build(4), Table2.build(5));

        join(table1, table2, JoinType.innerJoin, null, null).forEach(System.out::println);
        System.out.println("-----------------");
        join(table1, table2, JoinType.innerJoin, (r1, r2) -> r1.a == r2.b, null).forEach(System.out::println);
    }

    @Test
    public void leftJoin() {
        List<Table1> table1 = Arrays.asList(Table1.build(1), Table1.build(2), Table1.build(3));
        List<Table2> table2 = Arrays.asList(Table2.build(3), Table2.build(4), Table2.build(5));

        join(table1, table2, JoinType.leftJoin, (r1, r2) -> r1.a == r2.b, null).forEach(System.out::println);
        System.out.println("-----------------");
        join(table1, table2, JoinType.leftJoin, (r1, r2) -> r1.a > 10, null).forEach(System.out::println);
    }

}

The method in the code innerJoin()simulates the following sql:

mysql> select * from test1 t1,test2 t2;
+------+------+
| a    | b    |
+------+------+
|    1 |    3 |
|    2 |    3 |
|    3 |    3 |
|    1 |    4 |
|    2 |    4 |
|    3 |    4 |
|    1 |    5 |
|    2 |    5 |
|    3 |    5 |
+------+------+
9 rows in set (0.00 sec)

mysql> select * from test1 t1,test2 t2 where t1.a = t2.b;
+------+------+
| a    | b    |
+------+------+
|    3 |    3 |
+------+------+
1 row in set (0.00 sec)

Run it and innerJoin()the output is as follows:

Record{r1=Table1{a=1}, r2=Table2{b=3}}
Record{r1=Table1{a=1}, r2=Table2{b=4}}
Record{r1=Table1{a=1}, r2=Table2{b=5}}
Record{r1=Table1{a=2}, r2=Table2{b=3}}
Record{r1=Table1{a=2}, r2=Table2{b=4}}
Record{r1=Table1{a=2}, r2=Table2{b=5}}
Record{r1=Table1{a=3}, r2=Table2{b=3}}
Record{r1=Table1{a=3}, r2=Table2{b=4}}
Record{r1=Table1{a=3}, r2=Table2{b=5}}
-----------------
Record{r1=Table1{a=3}, r2=Table2{b=3}}

Comparing the results of SQL and Java, the number of output results and data are basically the same. The only difference is that the order is different. Why the order is inconsistent will be introduced briefly .

The method in the code leftJoin()simulates the following sql:

mysql> select * from test1 t1 left join test2 t2 on t1.a = t2.b;
+------+------+
| a    | b    |
+------+------+
|    3 |    3 |
|    1 | NULL |
|    2 | NULL |
+------+------+
3 rows in set (0.00 sec)

mysql> select * from test1 t1 left join test2 t2 on t1.a>10;
+------+------+
| a    | b    |
+------+------+
|    1 | NULL |
|    2 | NULL |
|    3 | NULL |
+------+------+
3 rows in set (0.00 sec)

Run leftJoin(), the results are as follows:

Record{r1=Table1{a=3}, r2=Table2{b=3}}
Record{r1=Table1{a=1}, r2=null}
Record{r1=Table1{a=2}, r2=null}
-----------------
Record{r1=Table1{a=1}, r2=null}
Record{r1=Table1{a=2}, r2=null}
Record{r1=Table1{a=3}, r2=null}

The effect is exactly the same as that of SQL and can be matched.

Now let's discuss why the order of java output is inconsistent with sql?

The connection query between the two tables in the above java code uses a nested loop. Every time the outer loop is executed, the tables in the inner loop will be traversed once. If placed in mysql, it is equivalent to scanning all the internal standards (the entire table at once) io read operation), if the main table (outer loop) has n pieces of data, then the slave table needs to scan the entire table n times. The table data is stored in the disk, and each full table scan requires io operations. io The operation is the most time-consuming. If MySQL is implemented according to the above Java method, the efficiency will definitely be very low.

So how is mysql optimized?

msql uses a memory cache space internally, let's call it join_buffer, first put the data in the outer loop join_buffer, then traverse the table, take a piece of data from the table and join_buffercompare it with the data, and then take the third piece of data from the table 2 join_bufferare compared with the data until the slave table traversal is completed. Use this method to reduce the number of io scans of the slave table. When it is large enough join_bufferto store all the data in the master table, then the slave table only needs to scan the entire table once. (That is, only one full table io read operation is required).

This method is called in mysql Block Nested Loop.

Improve the java code to implement the join_buffer process.

Improved version of java code

package com.itsoku.sql;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

import com.itsoku.sql.Test1.*;

public class Test2 {

    public static int joinBufferSize = 10000;
    public static List<?> joinBufferList = new ArrayList<>();

    public static <R1, R2> List<Record<R1, R2>> join(List<R1> table1, List<R2> table2, JoinType joinType, Filter<R1, R2> onFilter, Filter<R1, R2> whereFilter) {
        if (Objects.isNull(table1) || Objects.isNull(table2) || joinType == null) {
            return new ArrayList<>();
        }

        List<Test1.Record<R1, R2>> result = new CopyOnWriteArrayList<>();

        int table1Size = table1.size();
        int fromIndex = 0, toIndex = joinBufferSize;
        toIndex = Integer.min(table1Size, toIndex);
        while (fromIndex < table1Size && toIndex <= table1Size) {
            joinBufferList = table1.subList(fromIndex, toIndex);
            fromIndex = toIndex;
            toIndex += joinBufferSize;
            toIndex = Integer.min(table1Size, toIndex);

            List<Record<R1, R2>> blockNestedLoopResult = blockNestedLoop((List<R1>) joinBufferList, table2, onFilter);
            result.addAll(blockNestedLoopResult);
        }

        if (joinType == JoinType.leftJoin) {
            List<R1> r1Record = result.stream().map(Record::getR1).collect(Collectors.toList());
            List<Record<R1, R2>> leftAppendList = new ArrayList<>();
            for (R1 r1 : table1) {
                if (!r1Record.contains(r1)) {
                    leftAppendList.add(Record.build(r1, null));
                }
            }
            result.addAll(leftAppendList);
        }
        if (Objects.nonNull(whereFilter)) {
            for (Record<R1, R2> record : result) {
                if (!whereFilter.accept(record.r1, record.r2)) {
                    result.remove(record);
                }
            }
        }
        return result;
    }

    public static <R1, R2> List<Record<R1, R2>> blockNestedLoop(List<R1> joinBufferList, List<R2> table2, Filter<R1, R2> onFilter) {
        List<Record<R1, R2>> result = new ArrayList<>();
        for (R2 r2 : table2) {
            for (R1 r1 : joinBufferList) {
                if (Objects.nonNull(onFilter) ? onFilter.accept(r1, r2) : true) {
                    result.add(Record.build(r1, r2));
                }
            }
        }
        return result;
    }

    @Test
    public void innerJoin() {
        List<Table1> table1 = Arrays.asList(Table1.build(1), Table1.build(2), Table1.build(3));
        List<Table2> table2 = Arrays.asList(Table2.build(3), Table2.build(4), Table2.build(5));

        join(table1, table2, JoinType.innerJoin, null, null).forEach(System.out::println);
        System.out.println("-----------------");
        join(table1, table2, JoinType.innerJoin, (r1, r2) -> r1.a == r2.b, null).forEach(System.out::println);
    }

    @Test
    public void leftJoin() {
        List<Table1> table1 = Arrays.asList(Table1.build(1), Table1.build(2), Table1.build(3));
        List<Table2> table2 = Arrays.asList(Table2.build(3), Table2.build(4), Table2.build(5));

        join(table1, table2, JoinType.leftJoin, (r1, r2) -> r1.a == r2.b, null).forEach(System.out::println);
        System.out.println("-----------------");
        join(table1, table2, JoinType.leftJoin, (r1, r2) -> r1.a > 10, null).forEach(System.out::println);
    }
}

Execute innerJoin(), output:

Record{r1=Table1{a=1}, r2=Table2{b=3}}
Record{r1=Table1{a=2}, r2=Table2{b=3}}
Record{r1=Table1{a=3}, r2=Table2{b=3}}
Record{r1=Table1{a=1}, r2=Table2{b=4}}
Record{r1=Table1{a=2}, r2=Table2{b=4}}
Record{r1=Table1{a=3}, r2=Table2{b=4}}
Record{r1=Table1{a=1}, r2=Table2{b=5}}
Record{r1=Table1{a=2}, r2=Table2{b=5}}
Record{r1=Table1{a=3}, r2=Table2{b=5}}
-----------------
Record{r1=Table1{a=3}, r2=Table2{b=3}}

Execute leftJoin(), output:

Record{r1=Table1{a=3}, r2=Table2{b=3}}
Record{r1=Table1{a=1}, r2=null}
Record{r1=Table1{a=2}, r2=null}
-----------------
Record{r1=Table1{a=1}, r2=null}
Record{r1=Table1{a=2}, r2=null}
Record{r1=Table1{a=3}, r2=null}

The result is exactly the same as the sql result.

Expand

You can also use the previously learned group by, having, order by, in table joins limit.

These keywords are equivalent to operating on the results of table joins. You can practice them and deepen your understanding.

Guess you like

Origin blog.csdn.net/weixin_46228112/article/details/132664321