Inner join — the default
The default join keeps only rows where the key matches on both sides. In Scala you pass the two DataFrames and a join condition; here we match each order's user_id to a person's id to attach the buyer's name.
def join(right: Dataset[_], joinExprs: Column): DataFrame // defaults to inner def join(right: Dataset[_], joinExprs: Column, joinType: String): DataFrame // joinType: inner | left | right | full | left_semi | left_anti | cross
people.join(orders, orders("user_id") === people("id"))
.select($"name", $"product", $"amount")
.orderBy($"name")
.show(false)user_id would too. That silent row loss is the #1 join surprise; if either side must be preserved, reach for a left/right/full outer join. When the key columns share a name you can shortcut with people.join(orders, Seq("id")), which also collapses the duplicate key column.