Skip to main content
PySpark.inData Engineering
Tutorials
  • Python
  • SQL
  • PySpark
  • Machine Learning
  • NLP
  • Deep Learning
  • Linear Algebra
  • Data Engineering
  • All Tutorials
Challenge Arena Compiler Interview Questions Certifications Blogs Jobs Projects CV Builder
Menu
  • All Tutorials
  • Python
  • SQL
  • PySpark
  • Data Engineering
  • Learning Paths
  • Certificate Tracks
  • PySpark Compiler
  • Challenge Arena
  • Projects
  • Production Incidents
  • Boss Battles
  • Datasets
  • Interview Questions
  • Interview Mode
  • Company Prep
  • Certifications
  • DE Roadmap
  • Jobs
  • CV Builder
  • Blogs
  • About
  • Contact

We use cookies to run the site, remember your progress, and serve ads via Google AdSense. By continuing you agree to our Privacy Policy.

Explore

homeAll TutorialscodeLearn PythonanalyticsLearn PySparkterminalOnline Compileremoji_eventsChallenge ArenaarticleBlogsquizInterview QuestionsinfoAbout Uscontact_mailContact Us

Popular Topics

#python#pyspark#sql#spark#dataengineering#bigdata
Home›Interview Questions›PySpark Coding
💻 Interview Prep

PySpark Coding
Interview Questions

Hands-on PySpark problems: joins, window functions, aggregations, UDFs, and performance tuning scenarios.

JoinsWindow FnUDFsAggregationOptimization
10Questions
FreeAlways
search
pyspark's profile picture
pyspark·
2d agoInterview Question
Q.1

Scenario: for each customer, show the month-over-month change and a running total.

Medium

Given monthly spend per customer, add the previous month's amount, the percentage change and the cumulative spend so far.

🐍 script.py 19 lines
1from pyspark.sql import SparkSession, functions as F
2from pyspark.sql.window import Window
3
4spark = SparkSession.builder.appName("MonthOverMonth").getOrCreate()
5
6sales = spark.createDataFrame([
7 ("C1", "2026-01", 1200.0), ("C1", "2026-02", 1500.0), ("C1", "2026-03", 900.0),
8 ("C2", "2026-01", 400.0), ("C2", "2026-02", 400.0), ("C2", "2026-03", 650.0),
9], ["customer_id", "month", "amount"])
10
11w = Window.partitionBy("customer_id").orderBy("month")
12running = w.rowsBetween(Window.unboundedPreceding, Window.currentRow)
13
14result = (sales
15 .withColumn("prev_amount", F.lag("amount").over(w))
16 .withColumn("change_pct", F.round((F.col("amount") - F.col("prev_amount")) / F.col("prev_amount") * 100, 1))
17 .withColumn("running_total", F.sum("amount").over(running)))
18
19result.orderBy("customer_id", "month").show()
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 10 lines
1+-----------+-------+------+-----------+----------+-------------+
2|customer_id| month|amount|prev_amount|change_pct|running_total|
3+-----------+-------+------+-----------+----------+-------------+
4| C1|2026-01|1200.0| NULL| NULL| 1200.0|
5| C1|2026-02|1500.0| 1200.0| 25.0| 2700.0|
6| C1|2026-03| 900.0| 1500.0| -40.0| 3600.0|
7| C2|2026-01| 400.0| NULL| NULL| 400.0|
8| C2|2026-02| 400.0| 400.0| 0.0| 800.0|
9| C2|2026-03| 650.0| 400.0| 62.5| 1450.0|
10+-----------+-------+------+-----------+----------+-------------+
▶ Run to see output
✦ AI Explanation

Points interviewers look for

  • The first month has no previous month, so lag returns NULL and so does the change: do not turn it into 0%.
  • An explicit rowsBetween(unboundedPreceding, currentRow) frame. With only orderBy, the default frame is RANGE-based, so rows with the same month would all get the same running total.
  • A missing month (no row for February) makes lag compare March with January; fill the calendar first if that matters.

Practise this: Month-over-month growth percentage (runs in the browser, with test cases).

pyspark's profile picture
pyspark·
2d agoInterview Question
Q.2

Scenario: find the top 2 salaries in each department, keeping employees who tie.

Medium

Return every employee whose salary is among the two highest salary levels of their department. Two people with the same salary must both appear.

🐍 script.py 15 lines
1from pyspark.sql import SparkSession, functions as F
2from pyspark.sql.window import Window
3
4spark = SparkSession.builder.appName("TopNPerGroup").getOrCreate()
5
6emp = spark.createDataFrame([
7 ("Anil", "IT", 90000), ("Bina", "IT", 85000), ("Chetan", "IT", 85000), ("Divya", "IT", 70000),
8 ("Esha", "HR", 60000), ("Farid", "HR", 55000), ("Gita", "HR", 50000),
9 ("Hari", "Sales", 65000),
10], ["name", "department", "salary"])
11
12w = Window.partitionBy("department").orderBy(F.col("salary").desc())
13
14top2 = emp.withColumn("rnk", F.dense_rank().over(w)).filter("rnk <= 2")
15top2.orderBy("department", "rnk", "name").show()
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 10 lines
1+------+----------+------+---+
2| name|department|salary|rnk|
3+------+----------+------+---+
4| Esha| HR| 60000| 1|
5| Farid| HR| 55000| 2|
6| Anil| IT| 90000| 1|
7| Bina| IT| 85000| 2|
8|Chetan| IT| 85000| 2|
9| Hari| Sales| 65000| 1|
10+------+----------+------+---+
▶ Run to see output
✦ AI Explanation

Choosing the ranking function

FunctionIT ranks for 90k, 85k, 85k, 70kUse when
row_number1, 2, 3, 4Exactly N rows per group; ties broken arbitrarily
rank1, 2, 2, 4Ties share a rank and the next rank is skipped
dense_rank1, 2, 2, 3Top N distinct values; ties kept, no gaps

Sales has one employee, so it returns one row: “top 2” never invents rows.

Practise this: Top 3 highest-paid employees in each department (runs in the browser, with test cases).

pyspark's profile picture
pyspark·
2d agoInterview Question
Q.3

Scenario: a table receives several updates per customer. How do you keep only the latest record per key?

Medium

A CDC feed or a daily extract often carries more than one version of the same customer. Keep the newest version of each key, deterministically, even when two updates share a timestamp.

🐍 script.py 25 lines
1from pyspark.sql import SparkSession, functions as F
2from pyspark.sql.window import Window
3
4spark = SparkSession.builder.appName("LatestPerKey").getOrCreate()
5
6updates = spark.createDataFrame([
7 (101, "Asha", "Pune", "2026-01-05 10:00:00", 1),
8 (101, "Asha", "Mumbai", "2026-03-12 09:30:00", 4),
9 (102, "Ravi", "Delhi", "2026-02-01 08:00:00", 2),
10 (103, "Meera", "Chennai", "2026-01-20 18:45:00", 3),
11 (103, "Meera", "Bengaluru", "2026-02-28 11:15:00", 5),
12 (103, "Meera", "Hyderabad", "2026-02-28 11:15:00", 6),
13], ["customer_id", "name", "city", "updated_at", "ingest_seq"])
14
15updates = updates.withColumn("updated_at", F.to_timestamp("updated_at"))
16
17# Newest first; ingest_seq breaks a tie between two updates at the same timestamp
18w = Window.partitionBy("customer_id").orderBy(F.col("updated_at").desc(), F.col("ingest_seq").desc())
19
20latest = (updates
21 .withColumn("rn", F.row_number().over(w))
22 .filter("rn = 1")
23 .drop("rn"))
24
25latest.orderBy("customer_id").show(truncate=False)
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 7 lines
1+-----------+-----+---------+-------------------+----------+
2|customer_id|name |city |updated_at |ingest_seq|
3+-----------+-----+---------+-------------------+----------+
4|101 |Asha |Mumbai |2026-03-12 09:30:00|4 |
5|102 |Ravi |Delhi |2026-02-01 08:00:00|2 |
6|103 |Meera|Hyderabad|2026-02-28 11:15:00|6 |
7+-----------+-----+---------+-------------------+----------+
▶ Run to see output
✦ AI Explanation

What the interviewer is checking

  • row_number(), not rank(): rank would keep both tied rows for customer 103.
  • A deterministic tie-breaker (an ingestion sequence or offset). Without it, which tied row survives can change between runs.
  • Why not dropDuplicates(["customer_id"]): it keeps an arbitrary row, not the latest.
  • On Delta Lake, the same window result feeds a MERGE so the target table holds one current row per key.

Practise this: Deduplicate: keep the latest record per customer (runs in the browser, with test cases).

Vishal Taneja's profile picture
Vishal Taneja·
Sep 13, 2026Interview Question
Q.4

You receive employee data in Spark. How would you calculate a 15% bonus column?

Easy

🐍 script.py 37 lines
1from pyspark.sql import SparkSession
2from pyspark.sql.functions import col
3
4# Create SparkSession
5spark = SparkSession.builder \
6 .appName("EmployeeBonus") \
7 .master("local[*]") \
8 .getOrCreate()
9
10# Sample data
11data = [
12 (1, "Amit", 50000),
13 (2, "Rahul", 60000)
14]
15
16# Column names
17columns = ["id", "name", "salary"]
18
19# Create DataFrame
20df = spark.createDataFrame(data, columns)
21
22# Display original data
23print("Original Data:")
24df.show()
25
26# Calculate 15% bonus
27result = df.withColumn(
28 "bonus",
29 col("salary") * 0.15
30)
31
32# Display result
33print("Employee Bonus:")
34result.show()
35
36# Stop Spark
37spark.stop()
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 6 lines
1+---+-----+------+------+
2| id| name|salary| bonus|
3+---+-----+------+------+
4| 1| Amit| 50000|7500.0|
5| 2|Rahul| 60000|9000.0|
6+---+-----+------+------+
▶ Run to see output
✦ AI Explanation

Practise this: Add a bonus column with withColumn (runs in the browser, with test cases).

Vishal Taneja's profile picture
Vishal Taneja·
Sep 13, 2026Interview Question
Q.5

Find employees whose salary is greater than 55,000

Easy

🐍 script.py 30 lines
1from pyspark.sql import SparkSession
2from pyspark.sql.functions import col
3# 1. Create SparkSession
4spark = SparkSession.builder \
5 .appName("EmployeeFiltering") \
6 .master("local[*]") \
7 .getOrCreate()
8# 2. Create sample employee data
9data = [
10 (1, "Amit", 50000),
11 (2, "Rahul", 60000),
12 (3, "John", 75000),
13 (4, "Priya", 55000),
14 (5, "Neha", 90000)
15]
16
17# 3. Define columns
18columns = ["employee_id", "name", "salary"]
19# 4. Create DataFrame
20df = spark.createDataFrame(data, columns)
21# 5. Display original DataFrame
22print("Original Data:")
23df.show()
24# 6. Filter employees whose salary is greater than 55,000
25result = df.filter(col("salary") > 55000)
26# 7. Display filtered result
27print("Employees with salary greater than 55,000:")
28result.show()
29# 8. Stop Spark
30spark.stop()
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 7 lines
1+-----------+-----+------+
2|employee_id| name|salary|
3+-----------+-----+------+
4| 2|Rahul| 60000|
5| 3| John| 75000|
6| 5| Neha| 90000|
7+-----------+-----+------+
▶ Run to see output
✦ AI Explanation

Priya earns exactly 55,000, so > 55000 excludes her; use >= to include it.

Practise this: Filter rows with a condition (runs in the browser, with test cases).

Vishal Taneja's profile picture
Vishal Taneja·
Sep 4, 2026Interview Question
Q.6

A bank wants to identify customers whose salary has significantly declined over the last 3 months.

Hard

Business Requirement

A bank wants to identify customers whose salary has significantly declined over the last 3 months.

Risk Criteria

  1. Customer should have monthly salary credits.
  2. Compare the latest month's salary with the average salary of the previous 3 months.
  3. If the salary has dropped by more than 40%, flag the customer.
  4. Ignore customers having fewer than 4 salary credits.

Input DataFrame

account_transactions

account_idtxn_datetxn_typeamount
10012024-01-05CREDIT100000
10012024-02-05CREDIT105000
10012024-03-05CREDIT98000
10012024-04-05CREDIT50000
10022024-01-05CREDIT70000
10022024-02-05CREDIT72000
10022024-03-05CREDIT71000
10022024-04-05CREDIT70000

Expected Output

account_idavg_previous_3_monthscurrent_salarydrop_percentagerisk_flag
1001101000.005000050.50%FLAG
100271000.00700001.41%NOT_FLAG


🐍 script.py 197 lines
1from pyspark.sql import SparkSession
2from pyspark.sql.functions import (
3 col,
4 avg,
5 count,
6 round,
7 when,
8 row_number
9)
10from pyspark.sql.window import Window
11# ============================================================
12# 1. Create Spark Session
13# ============================================================
14spark = SparkSession.builder \
15 .appName("SalaryDropAnalysis") \
16 .master("local[*]") \
17 .getOrCreate()
18# ============================================================
19# 2. Create Source Data
20# ============================================================
21data = [
22 (1001, "2024-01-05", "CREDIT", 100000),
23 (1001, "2024-02-05", "CREDIT", 105000),
24 (1001, "2024-03-05", "CREDIT", 98000),
25 (1001, "2024-04-05", "CREDIT", 50000),
26 (1002, "2024-01-05", "CREDIT", 70000),
27 (1002, "2024-02-05", "CREDIT", 72000),
28 (1002, "2024-03-05", "CREDIT", 71000),
29 (1002, "2024-04-05", "CREDIT", 70000),
30
31 # Only 3 credits - should be ignored
32 (1003, "2024-02-05", "CREDIT", 80000),
33 (1003, "2024-03-05", "CREDIT", 82000),
34 (1003, "2024-04-05", "CREDIT", 40000)
35]
36
37columns = [
38 "account_id",
39 "txn_date",
40 "txn_type",
41 "amount"
42]
43
44# ============================================================
45# 3. Create DataFrame
46# ============================================================
47df = spark.createDataFrame(data, columns)
48print("SOURCE DATA")
49df.show()
50# ============================================================
51# 4. Convert transaction date to date
52# ============================================================
53df = df.withColumn(
54 "txn_date",
55 col("txn_date").cast("date")
56)
57
58# ============================================================
59# 5. Keep only salary CREDIT transactions
60# ============================================================
61salary_df = df.filter(
62 col("txn_type") == "CREDIT"
63)
64print("SALARY CREDIT DATA")
65salary_df.show()
66
67# ============================================================
68# 6. Check customers having at least 4 salary credits
69# ============================================================
70valid_customers = salary_df \
71 .groupBy("account_id") \
72 .agg(
73 count("*").alias("credit_count")
74 ) \
75 .filter(
76 col("credit_count") >= 4
77 )
78
79print("CUSTOMERS WITH AT LEAST 4 CREDITS")
80valid_customers.show()
81# ============================================================
82# 7. Keep only valid customers
83# ============================================================
84salary_df = salary_df.join(
85 valid_customers.select("account_id"),
86 on="account_id",
87 how="inner"
88)
89
90# ============================================================
91# 8. Create Window
92#
93# Latest transaction gets rn = 1
94# Previous transactions get rn = 2, 3, 4
95# ============================================================
96window_spec = Window \
97 .partitionBy("account_id") \
98 .orderBy(col("txn_date").desc())
99# ============================================================
100# 9. Assign row number
101# ============================================================
102salary_df = salary_df.withColumn(
103 "rn",
104 row_number().over(window_spec)
105)
106print("DATA WITH ROW NUMBER")
107salary_df.show()
108# ============================================================
109# 10. Get latest salary
110# ============================================================
111current_salary_df = salary_df \
112 .filter(col("rn") == 1) \
113 .select(
114 "account_id",
115 col("amount").alias("current_salary")
116 )
117print("CURRENT SALARY")
118current_salary_df.show()
119# ============================================================
120# 11. Get previous 3 months average salary
121# ============================================================
122previous_salary_df = salary_df \
123 .filter(col("rn").between(2, 4)) \
124 .groupBy("account_id") \
125 .agg(
126 avg("amount").alias("avg_previous_3_months")
127 )
128print("AVERAGE OF PREVIOUS 3 MONTHS")
129previous_salary_df.show()
130# ============================================================
131# 12. Join current salary and previous salary
132# ============================================================
133
134result_df = current_salary_df.join(
135 previous_salary_df,
136 on="account_id",
137 how="inner"
138)
139
140# ============================================================
141# 13. Calculate salary drop percentage
142#
143# Drop % =
144# ((Previous Average - Current Salary)
145# / Previous Average) * 100
146# ============================================================
147
148result_df = result_df.withColumn(
149 "drop_percentage",
150 round(
151 (
152 (
153 col("avg_previous_3_months")
154 - col("current_salary")
155 )
156 / col("avg_previous_3_months")
157 ) * 100,
158 2
159 )
160)
161
162# ============================================================
163# 14. Apply Risk Rule
164#
165# Drop > 40% --> FLAG
166# Otherwise --> NOT_FLAG
167# ============================================================
168
169result_df = result_df.withColumn(
170 "risk_flag",
171 when(
172 col("drop_percentage") > 40,
173 "FLAG"
174 ).otherwise("NOT_FLAG")
175)
176
177# ============================================================
178# 15. Final Result
179# ============================================================
180
181final_df = result_df.select(
182 "account_id",
183 "avg_previous_3_months",
184 "current_salary",
185 "drop_percentage",
186 "risk_flag"
187).orderBy("account_id")
188
189print("FINAL RESULT")
190
191final_df.show(truncate=False)
192
193# ============================================================
194# 16. Stop Spark
195# ============================================================
196
197spark.stop()
▶ Run to see output
✦ AI Explanation

Practise this: Detect significant salary declines (runs in the browser, with test cases).

pyspark's profile picture
pyspark·
Sep 4, 2026Interview Question
Q.7

Given a DataFrame containing flight/train routes and fares, find the cheapest fare between a source and destination, including the possibility of travelling through an intermediate city?

Medium

​Input DataFrame

Suppose we have this route data:

sourcedestinationfare
DelhiMumbai5000
DelhiPune3000
PuneMumbai1500
DelhiBangalore4000
BangaloreMumbai2500
DelhiChennai4500
ChennaiMumbai3000

We want to find the cheapest way to travel:

Delhi → Mumbai

Possible routes

RouteCalculationTotal Fare
Delhi → Mumbai50005000
Delhi → Pune → Mumbai3000 + 15004500
Delhi → Bangalore → Mumbai4000 + 25006500
Delhi → Chennai → Mumbai4500 + 30007500

Therefore:

Cheapest fare = ₹4,500

Route = Delhi → Pune → Mumbai

🐍 script.py 26 lines
1from pyspark.sql import SparkSession, functions as F
2
3spark = SparkSession.builder.appName("CheapestFare").getOrCreate()
4
5routes = spark.createDataFrame([
6 ("Delhi", "Mumbai", 5000), ("Delhi", "Pune", 3000), ("Pune", "Mumbai", 1500),
7 ("Delhi", "Bangalore", 4000), ("Bangalore", "Mumbai", 2500),
8 ("Delhi", "Chennai", 4500), ("Chennai", "Mumbai", 3000),
9], ["source", "destination", "fare"])
10
11src, dst = "Delhi", "Mumbai"
12
13# Direct routes
14direct = (routes
15 .filter((F.col("source") == src) & (F.col("destination") == dst))
16 .select(F.concat_ws(" -> ", "source", "destination").alias("route"),
17 F.col("fare").alias("total_fare")))
18
19# One-stop routes: self join, first leg's destination = second leg's source
20a, b = routes.alias("a"), routes.alias("b")
21one_stop = (a.join(b, F.col("a.destination") == F.col("b.source"))
22 .filter((F.col("a.source") == src) & (F.col("b.destination") == dst))
23 .select(F.concat_ws(" -> ", "a.source", "a.destination", "b.destination").alias("route"),
24 (F.col("a.fare") + F.col("b.fare")).alias("total_fare")))
25
26direct.unionByName(one_stop).orderBy("total_fare").limit(1).show(truncate=False)
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 5 lines
1+-----------------------+----------+
2|route |total_fare|
3+-----------------------+----------+
4|Delhi -> Pune -> Mumbai|4500 |
5+-----------------------+----------+
▶ Run to see output
✦ AI Explanation

Why include the direct route?

The question asks for the cheapest fare including one stop, so a direct flight must compete too. With only the self join, a cheaper direct fare is never considered: change Delhi → Mumbai to 4000 and the one-stop-only version still answers 4500, while this one answers 4000 (Delhi -> Mumbai).

How to explain it: “I build the candidates two ways: direct routes by filtering, and one-stop routes by self-joining the table on destination = source. I union them, sort by total fare and take the first row. For more than one stop this becomes a graph problem (shortest path), not a fixed number of joins.”

Remember the logic

Direct routes ∪ (self join → add fares) → sort ascending → limit(1)

pyspark's profile picture
pyspark·
Sep 4, 2026Interview Question
Q.8

Given a sales DataFrame containing product_id, unit_price, and quantity, write PySpark code to calculate the total amount for each product and the overall total sales amount.

Easy

1. Input DataFrame

Think of the DataFrame like this table:

product_idunit_pricequantity
101100.02
102200.03
10350.04
104150.02

For each row:

Total Amount = unit_price × quantity


🐍 script.py 32 lines
1from pyspark.sql import SparkSession
2from pyspark.sql.functions import col, sum
3# Create Spark Session
4spark = SparkSession.builder \
5 .appName("SalesCalculation") \
6 .getOrCreate()
7# Sample sales data
8data = [
9 (101, 100.0, 2),
10 (102, 200.0, 3),
11 (103, 50.0, 4),
12 (104, 150.0, 2)
13]
14columns = ["product_id", "unit_price", "quantity"]
15# Create DataFrame
16sales_df = spark.createDataFrame(data, columns)
17print("Input Data:")
18sales_df.show()
19# Calculate total amount for each row
20sales_with_amount = sales_df.withColumn(
21 "total_amount",
22 col("unit_price") * col("quantity")
23)
24print("Sales with Total Amount:")
25sales_with_amount.show()
26# Calculate overall total sales
27total_sales = sales_with_amount.agg(
28 sum("total_amount").alias("total_sales_amount")
29)
30print("Overall Total Sales:")
31total_sales.show()
32spark.stop()
▶ Run to see output
✦ AI Explanation


Expected output

📄 code.txt 14 lines
1+----------+----------+--------+------------+
2|product_id|unit_price|quantity|total_amount|
3+----------+----------+--------+------------+
4| 101| 100.0| 2| 200.0|
5| 102| 200.0| 3| 600.0|
6| 103| 50.0| 4| 200.0|
7| 104| 150.0| 2| 300.0|
8+----------+----------+--------+------------+
9
10+------------------+
11|total_sales_amount|
12+------------------+
13| 1300.0|
14+------------------+
▶ Run to see output
✦ AI Explanation

Vishal Taneja's profile picture
Vishal Taneja·
Apr 20, 2026Interview Question
Q.9

Find the number of transactions that occurred for each product. Output the product name along with the transaction count and sort by product_id

Hard

You are given two datasets:

1. Inventory Table

  product_id

  product_name

2. Transactions Table

transaction_id

time

product_id

Output the product name along with the transaction count and sort by product_id.

Handle duplicate transactions (keep latest)

Count the number of transactions per product

Exclude products with no transactions

Sort the result by product_id

🐍 script.py 58 lines
1inventory_data = [
2 (1, 'strawberry'),
3 (2, 'apple_fuji'),
4 (3, 'orange'),
5 (4, 'clementines'),
6 (5, 'blood_orange'),
7 (6, 'banana') # no transactions (to test filtering)
8]
9
10inv_cols = ["product_id", "product_name"]
11
12transaction_data = [
13 (153, '2016-01-06 08:57:52', 1),
14 (91, '2016-01-07 12:17:27', 1),
15 (31, '2016-01-05 13:19:25', 1),
16 (24, '2016-01-03 10:47:44', 3),
17 (4, '2016-01-06 17:57:42', 3),
18 (163, '2016-01-03 10:11:22', 3),
19 (92, '2016-01-08 12:03:20', 2),
20 (32, '2016-01-04 19:37:14', 4),
21 (253, '2016-01-06 14:15:20', 5),
22 (118, '2016-01-06 14:27:33', 5),
23 (118, '2016-01-07 14:27:33', 5), # duplicate (keep latest)
24 (300, '2016-01-02 09:00:00', 7) # product not in inventory (to test join)
25]
26
27trans_cols = ["transaction_id", "time", "product_id"]
28from pyspark.sql import SparkSession
29from pyspark.sql.functions import col, row_number, count
30from pyspark.sql.window import Window
31
32spark = SparkSession.builder.appName("InterviewSolution").getOrCreate()
33
34# DataFrames
35inv_df = spark.createDataFrame(inventory_data, ["product_id", "product_name"])
36trans_df = spark.createDataFrame(transaction_data, ["transaction_id", "time", "product_id"])
37
38# Step 1: Cast time to timestamp
39trans_df = trans_df.withColumn("time", col("time").cast("timestamp"))
40
41# Step 2: Deduplicate using window
42window_spec = Window.partitionBy("transaction_id").orderBy(col("time").desc())
43
44dedup_df = trans_df.withColumn("rn", row_number().over(window_spec)) \
45 .filter(col("rn") == 1) \
46 .drop("rn")
47
48# Step 3: Inner join
49joined_df = dedup_df.join(inv_df, on="product_id", how="inner")
50
51# Step 4: Aggregate
52result_df = joined_df.groupBy("product_id", "product_name") \
53 .agg(count("*").alias("transaction_count"))
54
55# Step 5: Sort
56final_df = result_df.orderBy("product_id")
57
58final_df.show()
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 9 lines
1+----------+------------+-----------------+
2|product_id|product_name|transaction_count|
3+----------+------------+-----------------+
4| 1| strawberry| 3|
5| 2| apple_fuji| 1|
6| 3| orange| 3|
7| 4| clementines| 1|
8| 5|blood_orange| 2|
9+----------+------------+-----------------+
▶ Run to see output
✦ AI Explanation

Transaction 118 appears twice for product 5; keeping only its latest row leaves 2 transactions, not 3. Banana (no transactions) and product 7 (not in the inventory) drop out of the inner join.

Vishal Taneja's profile picture
Vishal Taneja·
Apr 20, 2026Interview Question
Q.10

Find customers who have placed at least one order (PySpark join)

Easy

Write a PySpark program to perform an JOIN and return only customers who have placed at least one order.


🐍 script.py 31 lines
1customers = [
2 ("C001", "Arjun", "Chennai"),
3 ("C002", "Priya", None),
4 ("C003", "Ravi", None)
5]
6
7orders = [
8 ("C001", "Idli", 50),
9 ("C002", "Coffee", 120),
10 ("C004", "Dosa", 60)
11]
12
13from pyspark.sql import SparkSession
14from pyspark.sql.functions import col
15
16# Create Spark session
17spark = SparkSession.builder.appName("CustomerOrders").getOrCreate()
18
19# Create DataFrames
20customers_df = spark.createDataFrame(customers, ["customer_id", "name", "city"])
21orders_df = spark.createDataFrame(orders, ["customer_id", "item", "amount"])
22
23# Perform INNER JOIN
24result_df = customers_df.join(orders_df, on="customer_id", how="inner")
25
26# Select only customer columns
27final_df = result_df.select("customer_id", "name", "city")
28
29# Show result
30
31final_df.show()
▶ Run to see output
✦ AI Explanation

Better: a left semi join

The inner join returns a customer once per order. Give C001 a second order and C001 appears twice. A left_semi join keeps each matching customer once and returns only the customer columns:

🐍 script.py 2 lines
1result_df = customers_df.join(orders_df, on="customer_id", how="left_semi")
2result_df.show()
▶ Run to see output
✦ AI Explanation

Expected output

📄 code.txt 6 lines
1+-----------+-----+-------+
2|customer_id| name| city|
3+-----------+-----+-------+
4| C001|Arjun|Chennai|
5| C002|Priya| NULL|
6+-----------+-----+-------+
▶ Run to see output
✦ AI Explanation

The opposite question, customers with no orders, is how="left_anti".

Practise this: Customers with at least one order (runs in the browser, with test cases).

PySpark.inData Engineering

A learning and career platform for Data Engineering — structured tutorials, a browser-based PySpark compiler, coding challenges, interview preparation and certifications.

Learn

  • Python
  • SQL
  • PySpark
  • Machine Learning
  • NLP
  • Deep Learning
  • Linear Algebra
  • Data Engineering
  • All Tutorials

Practise

  • PySpark Compiler
  • Challenge Arena
  • Challenges by Topic
  • Dataset Library
  • Interview Questions

Career

  • Certifications
  • CV Builder
  • Jobs

Resources

  • Blogs
  • Projects
  • Certificate Tracks

Company

  • About
  • Contact
  • Terms
  • Privacy Policy

Stay ahead in Data Engineering

Weekly tutorials, PySpark tips, SQL challenges and interview questions.

© 2026 PySpark.in. All rights reserved.

TermsPrivacyCookies