如何在SparkSQL或Dataframe API中使用半联接实现以下SQL?
select *
from foo
left join a on foo.id = a.id
left join b on foo.id = b.id
where exists (select 1 from a x where foo.id = x.id)
or exists (select 1 from b x where foo.id = x.id)
;
我已经尝试过了,但是它的作用是AND
.join(loincDF, foo("id") <=> a("id"), "leftsemi")
.join(loincDF, foo("id") <=> b("id"), "leftsemi")
答案 0 :(得分:1)
您可以尝试以下操作:
foo.join(a, Seq("id"), "leftsemi")
.union( foo.join(b, Seq("id"), "leftsemi") )
.distinct
答案 1 :(得分:0)
正如@Elmar Macek的解决方案中指出的那样,left_semi
的并集模仿OR
子句的exists
条件。但是,left_semi
连接不会从right
DataFrame中产生相应的列。要生成与涉及left join
的SQL等效的结果,您可以先执行left_outer
连接,然后再应用模仿exists
函数的过滤逻辑。
以下是几种方法:
方法1:先执行left_outer
次加入,然后进行left_semi
次加入
val foo = Seq(
(1, "f1"), (2, "f2"), (3, "f3"), (4, "f4"), (5, "f5")
).toDF("id", "name")
val a = Seq(
(1, "a1"), (3, "a3")
).toDF("id", "desc")
val b = Seq(
(1, "b1"), (4, "b4")
).toDF("id", "desc")
val bar = foo.
join(a, Seq("id"), "left_outer").
join(b, Seq("id"), "left_outer")
bar.join(a, Seq("id"), "left_semi").
union(
bar.join(b, Seq("id"), "left_semi")
).
distinct.
show
// +---+----+----+----+
// | id|name|desc|desc|
// +---+----+----+----+
// | 4| f4|null| b4|
// | 1| f1| a1| b1|
// | 3| f3| a3|null|
// +---+----+----+----+
方法2:执行left_outer
连接,然后null
检查非关键列
val aNonKeyCols = a.columns.filter(_ != "id")
val a2 = a.withColumn("aCols", struct(aNonKeyCols.map(col): _*)).
select("id", "aCols")
val bNonKeyCols = b.columns.filter(_ != "id")
val b2 = b.withColumn("bCols", struct(aNonKeyCols.map(col): _*)).
select("id", "bCols")
val bar = foo.
join(a2, Seq("id"), "left_outer").
join(b2, Seq("id"), "left_outer").
where($"aCols".isNotNull || $"bCols".isNotNull).
select("id", "name", "aCols.*", "bCols.*")
请注意,假设存在许多列,a
和b
的非关键列分别放置在struct
中,以简化{{ 1}}检查。