一文详解pyspark中sql的join

大家好,今天分享一下pyspark中各种sql join。

数据准备

本文以学生和班级为单位进行介绍。

学生表有sid(学生id)、sname(学生姓名)、sclass(学生班级id)。

班级表有cid(班级id)、cname(班级名称)。

通过学生表的sclass和班级表的cid将两张表关联在一起。

下面是数据文件

数据的重点在于:

学生表的sclass是1,2,3,4,5

班级表的cid是1,2,4,6

即学生表比班级表多了3,5,班级表比学生表多了6

students.json

{"sid": 1, "sname": "xiaoming", "sclass":1}
{"sid": 2, "sname": "xiaogang", "sclass":2}
{"sid": 3, "sname": "xiaozhi", "sclass":3}
{"sid": 4, "sname": "xiaofang", "sclass":4}
{"sid": 5, "sname": "xiaohong", "sclass":5}

classes.json

{"cid": 1, "cname":"class1"}
{"cid": 2, "cname":"class2"}
{"cid": 4, "cname":"class4"}
{"cid": 6, "cname":"class6"}
数据读取
from pyspark.sql import SparkSession

spark = SparkSession.builder.enableHiveSupport().getOrCreate()

stu_df = spark.read.json('./data/students.json')
class_df = spark.read.json('./data/classes.json')

注意两个json文件的路径,我是放在了当前工作目录的data子目录下。

然后看下读取的学生df和班级df。

stu_df.show()
+------+---+--------+
|sclass|sid|   sname|
+------+---+--------+
|     1|  1|xiaoming|
|     2|  2|xiaogang|
|     3|  3| xiaozhi|
|     4|  4|xiaofang|
|     5|  5|xiaohong|
+------+---+--------+
class_df.show()
+---+------+
|cid| cname|
+---+------+
|  1|class1|
|  2|class2|
|  4|class4|
|  6|class6|
+---+------+
创建视图

下面的代码帮助我们创建了stu和class两个视图。 

stu_df.createOrReplaceTempView("stu")
class_df.createOrReplaceTempView("class")

 然后看一下视图中的数据

首先是视图stu 

temp_df = spark.sql("select * from stu")
temp_df.show()
+------+---+--------+
|sclass|sid|   sname|
+------+---+--------+
|     1|  1|xiaoming|
|     2|  2|xiaogang|
|     3|  3| xiaozhi|
|     4|  4|xiaofang|
|     5|  5|xiaohong|
+------+---+--------+

 然后是视图class

temp_df = spark.sql("select * from class")
temp_df.show()
+---+------+
|cid| cname|
+---+------+
|  1|class1|
|  2|class2|
|  4|class4|
|  6|class6|
+---+------+
join表达式定义

我们是通过学生表的sclass和班级表的cid将两张表关联在一起,所以定义join表达式如下

expr = stu_df["sclass"]==class_df["cid"]
inner join

inner join比较容易理解,就是把两张表中互相匹配的行选择出来。

sql写法:

spark.sql("select sid, sclass, cname from stu join class on stu.sclass = class.cid").show()

df写法:

stu_df.join(class_df, expr).select("sid", "sclass", "cname").show()

上面提到:

学生表的sclass是1,2,3,4,5

班级表的cid是1,2,4,6

公共部分就是1,2,4

所以上述两行代码的输出都是

+---+------+------+
|sid|sclass| cname|
+---+------+------+
|  1|     1|class1|
|  2|     2|class2|
|  4|     4|class4|
+---+------+------+
full join/full outer join

这种join就是把两张表的所有记录选择出来,如果一张表里有对应数据,另一张表里没有对应数据,就用NULL代替。

 sql写法:

spark.sql("select sid, sclass, cname from stu full outer join class on stu.sclass = class.cid").show()

df写法:

stu_df.join(class_df, expr, "outer").select("sid", "sclass", "cname").show()

上面提到:

学生表的sclass是1,2,3,4,5

班级表的cid是1,2,4,6

并集就是1,2,3,4,5,6

所以上述两行代码的输出都是

+----+------+------+
| sid|sclass| cname|
+----+------+------+
|   1|     1|class1|
|   2|     2|class2|
|   3|     3|  NULL|
|   4|     4|class4|
|   5|     5|  NULL|
|NULL|  NULL|class6|
+----+------+------+
left join/left outer join

这种join就是把左边的表的所有行都取出来,如果右边表有匹配的行,就用匹配的行,如果右边表没有匹配的行,就用NULL代替。

 sql写法:

spark.sql("select sid, sclass, cname from stu left outer join class on stu.sclass = class.cid").show()

df写法:

stu_df.join(class_df, expr, "left_outer").select("sid", "sclass", "cname").show()

上面提到:

学生表的sclass是1,2,3,4,5

班级表的cid是1,2,4,6

学生表是左表,班级表是右表,所以结果中会有1,2,3,4,5

3和5没有出现在右表中,所以对应字段用NULL代替。

所以上述两行代码的输出都是

+---+------+------+
|sid|sclass| cname|
+---+------+------+
|  1|     1|class1|
|  2|     2|class2|
|  3|     3|  NULL|
|  4|     4|class4|
|  5|     5|  NULL|
+---+------+------+
 right join/right outer join

这种join就是把右边的表的所有行都取出来,如果左边表有匹配的行,就用匹配的行,如果左边表没有匹配的行,就用NULL代替。

 sql写法:

spark.sql("select sid, sclass, cname from stu right outer join class on stu.sclass = class.cid").show()

df写法:

stu_df.join(class_df, expr, "right_outer").select("sid", "sclass", "cname").show()

上面提到:

学生表的sclass是1,2,3,4,5

班级表的cid是1,2,4,6

学生表是左表,班级表是右表,所以结果中会有1,2,4,6

6没有出现在左表中,所以对应字段用NULL代替。

所以上述两行代码的输出都是

+----+------+------+
| sid|sclass| cname|
+----+------+------+
|   1|     1|class1|
|   2|     2|class2|
|   4|     4|class4|
|NULL|  NULL|class6|
+----+------+------+
left semi join

这种join就是把左边表中能和右表中的行匹配的行取出来,只取左边表的记录。

  sql写法:

spark.sql("select * from stu left semi join class on stu.sclass = class.cid").show()

df写法:

stu_df.join(class_df, expr, "left_semi").show()

上面提到:

学生表的sclass是1,2,3,4,5

班级表的cid是1,2,4,6

学生表是左表,班级表是右表

两张表匹配的行是1,2,4

所以上述两行代码的输出都是

+------+---+--------+
|sclass|sid|   sname|
+------+---+--------+
|     1|  1|xiaoming|
|     2|  2|xiaogang|
|     4|  4|xiaofang|
+------+---+--------+
left anti join

这种join是把左边表中不能和右边表中的行匹配的行取出来,也是只取左边表中的行。

 sql写法:

spark.sql("select * from stu left anti join class on stu.sclass = class.cid").show()

df写法:

stu_df.join(class_df, expr, "left_anti").show()

上面提到:

学生表的sclass是1,2,3,4,5

班级表的cid是1,2,4,6

学生表是左表,班级表是右表

左边表的3和5不能和右边表中的行匹配

所以上述两行代码的输出都是

+------+---+--------+
|sclass|sid|   sname|
+------+---+--------+
|     3|  3| xiaozhi|
|     5|  5|xiaohong|
+------+---+--------+
cross join

这种join就是把左边表中的所有行和右边表的所有行做乘积,相当于左边表中的每一行都和右边表中的所有行组合一次,即左边表×右边表。

 sql写法:

spark.sql("select * from stu cross join class").show()

df写法:

stu_df.crossJoin(class_df).show()

所以上述两行代码的输出都是

+------+---+--------+---+------+
|sclass|sid|   sname|cid| cname|
+------+---+--------+---+------+
|     1|  1|xiaoming|  1|class1|
|     1|  1|xiaoming|  2|class2|
|     1|  1|xiaoming|  4|class4|
|     1|  1|xiaoming|  6|class6|
|     2|  2|xiaogang|  1|class1|
|     2|  2|xiaogang|  2|class2|
|     2|  2|xiaogang|  4|class4|
|     2|  2|xiaogang|  6|class6|
|     3|  3| xiaozhi|  1|class1|
|     3|  3| xiaozhi|  2|class2|
|     3|  3| xiaozhi|  4|class4|
|     3|  3| xiaozhi|  6|class6|
|     4|  4|xiaofang|  1|class1|
|     4|  4|xiaofang|  2|class2|
|     4|  4|xiaofang|  4|class4|
|     4|  4|xiaofang|  6|class6|
|     5|  5|xiaohong|  1|class1|
|     5|  5|xiaohong|  2|class2|
|     5|  5|xiaohong|  4|class4|
|     5|  5|xiaohong|  6|class6|
+------+---+--------+---+------+
参考

一文让你记住Pyspark下DataFrame的7种的Join 效果_pyspark dataframe join-CSDN博客

深入浅出leftsemijoin_笔记大全_设计学院

Spark权威指南之 - pyspark各种join - 知乎

Spark 系列(十二)—— Spark SQL JOIN 操作 - 掘金

JOIN - Spark 3.5.0 Documentation

你可能感兴趣的:(#,python数据分析,sql)