You can write the key in two ways. With a column name, "customer_id", Spark keeps one customer_id column.
With a column expression, Spark keeps both columns. Look at the expression form.
Joining on an expression keeps two key columnsworked example
joined = orders.join(customers, orders.customer_id == customers.customer_id)
joined.select("customer_id", "order_id", "name").show()
Error at the select (simplified)
| error | message |
|---|
| AnalysisException | Reference customer_id is ambiguous, could be: customer_id, customer_id. |
The joined table has two columns named customer_id. One is from orders and one is from customers. Spark cannot tell which one you mean. The exact message changes with the Spark version.
You have two fixes. Join on the name, or drop one key column. Here is the second fix.
Drop the extra key columnworked example
joined.drop(customers.customer_id) \
.select("customer_id", "order_id", "name").show()
show() prints (6 rows)
| customer_id | order_id | name |
|---|
| 1 | 101 | Asha |
| 1 | 102 | Asha |
| 2 | 103 | Ben |
| 3 | 104 | Carla |
| 3 | 105 | Carla |
| 4 | 106 | Dev |
Now there is one customer_id, from orders. Joining on the name "customer_id" gives the same shape in one step.
The second key problem is types. Suppose customers was read from a CSV file with no schema.
Then every column is a string. Look at the two types.
The key has two different typesworked example
orders.schema["customer_id"].dataType # IntegerType
customers_csv.schema["customer_id"].dataType # StringType
The type of customer_id
| table | customer_id type |
|---|
| orders | integer |
| customers_csv | string |
The value 1 and the text "1" are not the same type.
Spark casts one side for you, and shows no warning. Suppose one row has customer_id "" (empty text).
The cast turns it into NULL, and a NULL key never matches. That customer drops out of the join.
With ANSI mode on (the default in Spark 4), the bad value stops the job with an error instead.
Make the types the same before the join. Cast the string column to int.
Cast the key before joiningworked example
customers_ok = customers_csv.withColumn("customer_id", F.col("customer_id").cast("int"))
orders.join(customers_ok, "customer_id")
Both keys are now integers. You also see the cast in the plan, so you can check it.