MySQL系列复习(11)深入了解连接查询及原理

环境:mysql5.7.30,cmd命令中进行演示。
当我们查询的数据来源于多张表的时候,我们需要用到连接查询,连接查询使用率非常高。

目录

准备数据:

1、笛卡尔积

1.1、sql中笛卡尔积语法

2、内连接

2.1、示例1:有连接条件

2.2、示例2:无连接条件

2.3、组合条件进行查询

2.4、总结

3、外连接

4、左连接

4.1、示例1

4.2、示例2

5、右连接

5.1、示例

6、表连接的原理

6.1、示例1:内连接

6.2、示例2:左连接

7、使用java实现连接查询,加深理解


准备数据:

2张表:
t_team:组表。
t_employee:员工表,内部有个team_id引用组表的id。

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,'myronJava',1),(2,'张三',2),(3,'李四',3),(4,'王五',0),(5,'赵六',0);

t_team 表4条记录,如下:

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

t_employee 表5条记录,如下:

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

mysql>

1、笛卡尔积

介绍连接查询之前,我们需要先了解一下笛卡尔积。
笛卡尔积简单点理解:有两个集合A和B,笛卡尔积表示A集合中的元素和B集合中的元素任意相互关联产生的所有可能的结果。
假如A中有m个元素,B中有n个元素,A、B笛卡尔积产生的结果有m*n个结果,相当于循环遍历两个集合中的元素,任意组合。
java伪代码表示如下:

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

过程:拿A集合中的第1行,去匹配集合B中所有的行,然后再拿集合A中的第2行,去匹配集合B中所有的行,最后结果数量为m*n。

1.1、sql中笛卡尔积语法

select 字段 from 表1,表2[,表N];
或者
select 字段 from 表1 join 表2 [join 表N];
mysql> select * from t_team;
+----+-----------+
| id | team_name |
+----+-----------+
|  1 | 架构组    |
|  2 | 测试组    |
|  3 | java组    |
|  4 | 前端组    |
+----+-----------+
4 rows in set (0.00 sec)

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

mysql> select * from t_team,t_employee;
+----+-----------+----+-----------+---------+
| id | team_name | id | emp_name  | team_id |
+----+-----------+----+-----------+---------+
|  1 | 架构组    |  1 | myronJava |       1 |
|  2 | 测试组    |  1 | myronJava |       1 |
|  3 | java组    |  1 | myronJava |       1 |
|  4 | 前端组    |  1 | myronJava |       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)

mysql>

t_team表4条记录,t_employee表5条记录,笛卡尔积结果输出了20行记录。

2、内连接

语法:

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

内连接相当于在笛卡尔积的基础上加上了连接条件。

当没有连接条件的时候,内连接上升为笛卡尔积。

过程用java伪代码如下:

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

2.1、示例1:有连接条件

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 |
+-----------+-----------+
| myronJava | 架构组    |
| 张三      | 测试组    |
| 李四      | 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 |
+-----------+-----------+
| myronJava | 架构组    |
| 张三      | 测试组    |
| 李四      | 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 |
+-----------+-----------+
| myronJava | 架构组    |
| 张三      | 测试组    |
| 李四      | java组    |
+-----------+-----------+
3 rows in set (0.00 sec)

mysql>

上面相当于获取了2个表的交集,查询出了两个表都有的数据。

2.2、示例2:无连接条件

无条件内连接,上升为笛卡尔积,如下:

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

mysql>

2.3、组合条件进行查询

查询架构组的员工,3种写法

-- 方式1:on中使用了组合条件。
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 |
+-----------+-----------+
| myronJava | 架构组    |
+-----------+-----------+
1 row in set (0.00 sec)

-- 方式2:在连接的结果之后再进行过滤,相当于先获取连接的结果,然后使用where中的条件再对连接
结果进行过滤。
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 |
+-----------+-----------+
| myronJava | 架构组    |
+-----------+-----------+
1 row in set (0.00 sec)

-- 方式3:直接在where后面进行过滤。
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 |
+-----------+-----------+
| myronJava | 架构组    |
+-----------+-----------+
1 row in set (0.00 sec)

mysql>

2.4、总结

内连接建议使用第3种语法,简洁:

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

3、外连接

外连接涉及到2个表,分为:主表和从表,要查询的信息主要来自于哪个表,谁就是主表。
外连接查询结果为主表中所有记录。如果从表中有和它匹配的,则显示匹配的值,这部分相当于内连接
查询出来的结果;如果从表中没有和它匹配的,则显示null。
最终:外连接查询结果 = 内连接的结果 + 主表中有的而内连接结果中没有的记录。
外连接分为2种:
左外链接:使用left join关键字,left join左边的是主表。
右外连接:使用right join关键字,right join右边的是主表。

4、左连接

语法:

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

4.1、示例1

查询所有员工信息,并显示员工所在组,如下:

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 |
+-----------+-----------+
| myronJava | 架构组    |
| 张三      | 测试组    |
| 李四      | java组    |
| 王五      | NULL      |
| 赵六      | NULL      |
+-----------+-----------+
5 rows in set (0.00 sec)

mysql>

上面查询出了所有员工,员工team_id=0的,team_name为NULL。

4.2、示例2

查询员工姓名、组名、返回组名不为空的记录,如下:

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 |
+-----------+-----------+
| myronJava | 架构组    |
| 张三      | 测试组    |
| 李四      | java组    |
+-----------+-----------+
3 rows in set (0.02 sec)

mysql>

上面先使用内连接获取连接结果,然后再使用where对连接结果进行过滤。

5、右连接

语法:

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

5.1、示例

我们使用右连接来实现上面左连接实现的功能,如下:

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  |
+-----------+-----------+
| 架构组    | myronJava |
| 测试组    | 张三      |
| 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  |
+-----------+-----------+
| 架构组    | myronJava |
| 测试组    | 张三      |
| java组    | 李四      |
+-----------+-----------+
3 rows in set (0.00 sec)

mysql>

6、表连接的原理

准备数据:

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)

mysql>

6.1、示例1:内连接

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)

mysql>

6.2、示例2:左连接

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 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)

mysql>

上面的左连接第一个好理解。
第2个sql连接条件 t1.a>10 ,这个条件只关联了test1表,再看看结果,是否可以理解?不理解的继续
向下看,我们用java代码来实现连接查询。
第3个sql中的连接条件1=1值为true,返回结果为笛卡尔积。

7、使用java实现连接查询,加深理解

下面是一个简略版的实现

package com.myron.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);
 }
}

代码中的 innerJoin() 方法模拟了下面的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)

mysql>

运行一下 innerJoin() 输出如下:

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}}

对比一下sql和java的结果,输出的结果条数、数据基本上一致,唯一不同的是顺序上面不一样,顺序为
何不一致,稍微介绍。
代码中的 leftJoin() 方法模拟了下面的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)

mysql>

运行 leftJoin() ,结果如下:

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}

效果和sql的效果完全一致,可以对上。
现在我们来讨论java输出的顺序为何和sql不一致?

上面java代码中两个表的连接查询使用了嵌套循环,外循环每执行一次,内循环的表都会全部遍历一次,如果放到mysql中,就相当于内表(被驱动表)全部扫描了一次(一次全表io读取操作),主表(外循环)如果有n条数据,那么从表就需要全表扫描n次,表的数据是存储在磁盘中,每次全表扫描都需要做io操作,io操作是最耗时间的,如果mysql按照上面的java方式实现,那效率肯定很低。
那mysql是如何优化的呢?

msql内部使用了一个内存缓存空间,就叫他 join_buffer 吧,先把外循环的数据放到join_buffer 中,然后对从表进行遍历,从表中取一条数据和 join_buffer 的数据进行比较,然后从表中再取第2条和 join_buffer 数据进行比较,直到从表遍历完成,使用这方方式来减少从表的io扫描次数,当 join_buffer 足够大的时候,大到可以存放主表所有数据,那么从表只需
要全表扫描一次(即只需要一次全表io读取操作)。mysql中这种方式叫做 Block Nested Loop 。
java代码改进一下,来实现join_buffer的过程。

java代码改进版本

package com.myron.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.myron.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);
 }
}

执行 innerJoin() ,输出:

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}}

执行 leftJoin() ,输出:

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}

结果和sql的结果完全一致。

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值