文章目錄
- MySQL連接配接查詢及原理
- 1、本文内容
- 2、準備資料
- 3、笛卡爾積
- sql中笛卡爾積文法
- 4、内連接配接
- 示例1:有連接配接條件
- 示例2:無連接配接條件
- 示例3:組合條件進行查詢
- 總結
- 5、外連接配接
- 左連接配接
- 右連接配接
- 6、了解表連接配接原理
- 示例1:内連接配接
- 示例2:左連接配接
- 7、java代碼實作連接配接查詢
- 8、java代碼改進版本
- 8、擴充
MySQL連接配接查詢及原理
1、本文内容
笛卡爾積
内連接配接
外連接配接
左連接配接
右連接配接
表連接配接的原理
使用java實作連接配接查詢,加深了解
2、準備資料
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,'路人甲Java',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 | 路人甲Java | 1 |
| 2 | 張三 | 2 |
| 3 | 李四 | 3 |
| 4 | 王五 | 0 |
| 5 | 趙六 | 0 |
+----+---------------+---------+
5 rows in set (0.00 sec)
3、笛卡爾積
介紹連接配接查詢之前,我們需要先了解一下笛卡爾積。
笛卡爾積簡單點了解:有兩個集合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。
sql中笛卡爾積文法
select 字段 from 表1,表2[,表N];
或者
select 字段 from 表1 join 表2 [join 表N];
示例:
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)
t_team表4條記錄,t_employee表5條記錄,笛卡爾積結果輸出了20行記錄。
4、内連接配接
文法:
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);
}
}
}
示例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 |
+---------------+-----------+
| 路人甲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)
上面相當于擷取了2個表的交集,查詢出了兩個表都有的資料。
示例2:無連接配接條件
無條件内連接配接,上升為笛卡爾積,如下:
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)
示例3:組合條件進行查詢
查詢架構組的員工,3種寫法
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)
上面3中方式解說:
- 方式1:on中使用了組合條件。(select 字段 from 表1 inner join 表2 on 連接配接條件 and 條件)
- 方式2:在連接配接的結果之後再進行過濾,相當于先擷取連接配接的結果,然後使用where中的條件再對連接配接結果進行過濾。(select 字段 from 表1 inner join 表2 on 連接配接條件 where 關聯條件)
- 方式3:直接在where後面進行過濾。(select 字段 from 表1,表2 where 關聯條件 and 條件)
總結
内連接配接建議使用第3種文法,簡潔:(但用的多的還是: 表1inner join表2 on 連接配接條件)
select 字段 from 表1, 表2 [where 關聯條件];
5、外連接配接
外連接配接涉及到2個表,分為:主表和從表,要查詢的資訊主要來自于哪個表,誰就是主表。
外連接配接查詢結果為主表中所有記錄。如果從表中有和它比對的,則顯示比對的值,這部分相當于内連接配接查詢出來的結果;如果從表中沒有和它比對的,則顯示null。
最終:外連接配接查詢結果 = 内連接配接的結果 + 主表中有的而内連接配接結果中沒有的記錄。
外連接配接分為2種:
- 左外連結:使用left join關鍵字,left join左邊的是主表。
- 右外連接配接:使用right join關鍵字,right join右邊的是主表。
左連接配接
文法:
select 列 from 主表 left join 從表 on 連接配接條件;
示例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 |
+---------------+-----------+
| 路人甲Java | 架構組 |
| 張三 | 測試組 |
| 李四 | java組 |
| 王五 | NULL |
| 趙六 | NULL |
+---------------+-----------+
5 rows in set (0.00 sec)
上面查詢出了所有員工,員工team_id=0的,team_name為NULL。
示例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 |
+---------------+-----------+
| 路人甲Java | 架構組 |
| 張三 | 測試組 |
| 李四 | java組 |
+---------------+-----------+
3 rows in set (0.00 sec)
上面先使用内連接配接擷取連接配接結果,然後再使用where對連接配接結果進行過濾。
右連接配接
文法:
select 列 from 從表 right join 主表 on 連接配接條件;
示例:
我們使用右連接配接來實作上面左連接配接實作的功能,如下:
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)
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)
我們來寫幾個連接配接,看看效果。
示例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)
9條資料正常。
示例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 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)
上面的左連接配接第一個好了解。
第2個sql連接配接條件t1.a>10,這個條件隻關聯了test1表,再看看結果,是否可以了解?不了解的繼續向下看,我們用java代碼來實作連接配接查詢。
第3個sql中的連接配接條件1=1值為true,傳回結果為笛卡爾積。
7、java代碼實作連接配接查詢
下面是一個簡略版的實作
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);
}
}
代碼中的 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)
運作一下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)
運作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的過程。
8、java代碼改進版本
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);
}
}
執行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的結果完全一緻。