Skip to content
Everyone knows 4 min read · SQL 2 practice problems ↓

spark.sql and temp views

Mix SQL and DataFrames: register views, run spark.sql, and pass parameters safely.

You will learn

  • How to register a DataFrame as a view and query it with spark.sql
  • The difference between temp views, global temp views and tables
  • How to pass parameters into SQL safely
  • Why SQL and DataFrame code run at the same speed

Read first

Comfortable with these? Read on.

TL;DR df.createOrReplaceTempView("orders") gives a DataFrame a name for this session; spark.sql("SELECT ... FROM orders") returns a new DataFrame. Both APIs compile to the same plan, so choose whichever is clearer. Pass values with parameters, spark.sql(query, args={...}), not with f-strings.

Going back and forth

PySpark · DataFrame → SQL → DataFrame
orders.createOrReplaceTempView("orders")

top = spark.sql("""
    SELECT customer, SUM(amount) AS total
    FROM orders
    GROUP BY customer
""")

result = top.filter(F.col("total") > 1000).orderBy(F.desc("total"))

The result of spark.sql is an ordinary DataFrame: you can keep chaining DataFrame methods, register it as another view, or write it out. Nothing runs until an action, exactly as with DataFrame code.

Views and tables

KindCreated withVisible toLives until
Temp viewcreateOrReplaceTempViewThis Spark session onlyThe session ends
Global temp viewcreateOrReplaceGlobalTempView; query as global_temp.nameAll sessions in the same applicationThe application ends
TablesaveAsTable, CREATE TABLEEveryone using the catalogDropped
Permanent viewCREATE VIEW in SQLEveryone using the catalogDropped; stores only the query, not data

A temp view stores no data. It is a name for a plan: querying it re-runs the plan, including reading the source, unless the DataFrame is cached.

Passing parameters safely

Building SQL with f-strings breaks on quotes in values and opens the door to SQL injection when values come from users or files. Spark 3.4+ supports named parameters:

PySpark · Parameters, not string formatting
# Fragile: breaks for O'Brien, and unsafe with untrusted input
spark.sql(f"SELECT * FROM orders WHERE customer = '{name}'")

# Safe: the value is passed separately
spark.sql("SELECT * FROM orders WHERE customer = :name AND amount > :min",
          args={"name": name, "min": 100})

# DataFrames can be passed straight in (Spark 3.4+)
spark.sql("SELECT * FROM {o} WHERE amount > 100", o=orders)

Same plan, same speed

SQL text and DataFrame calls are two front ends to the same engine. Both are parsed into a logical plan, optimised by CatalystCatalyst: Spark's query optimizer. It rewrites your DataFrame code into a faster equivalent plan before running it. Learn more → and executed the same way. explain() on either shows identical physical plans for equivalent queries. Choose by readability: SQL for analysts and long set-based logic, DataFrames when you build queries dynamically in Python (loops over columns, reusable functions, unit tests).

SQL · text

Spark parses the string into an unresolved plan.

The command

spark.sql("SELECT customer, SUM(amount) AS revenue FROM orders WHERE amount > 0 GROUP BY customer")
SELECT customer, SUM(amount) AS revenue FROM orders WHERE amount > 0 GROUP BY customer

DataFrame · calls

Each method call adds a node to the same kind of plan.

The command

orders.filter("amount > 0").groupBy("customer").agg(F.sum("amount").alias("revenue"))

Catalyst · optimise

Both are resolved against the catalog, optimised (filters pushed down, columns pruned) and turned into the same physical plan. From here on there is no difference.

Mixing them well

  • F.expr("CASE WHEN ... END") and df.selectExpr("amount * 1.18 AS gross") embed SQL expressions inside DataFrame code.
  • df.filter("amount > 100") accepts a SQL condition string.
  • Register intermediate results as views to break a long SQL pipeline into readable steps, or use CTEs (WITH ... AS) inside one query.
  • Use spark.table("db.orders") to read a catalog table as a DataFrame.

Common mistakes

f-strings for values

Breaks on quotes and is open to injection. Use args or the DataFrame API.

Expecting a temp view to be visible in another notebook or job

Temp views live in one session. Write a table to share data.

Believing SQL is faster (or slower) than DataFrames

Both compile to the same plan.

Treating a view as cached

A view re-runs its plan every time it is queried.

Key takeaways

  • createOrReplaceTempView names a DataFrame for SQL in one session.
  • spark.sql returns a lazy DataFrame.
  • Pass values with args, never with f-strings.
  • SQL and DataFrames compile to the same plan and run at the same speed.

Check yourself

3 questions

1. Where is a temp view visible?

Show the answer

Only in the session that created it. Temp views are session-scoped; global temp views are application-scoped.

2. Does a temp view store data?

Show the answer

No, it names a plan that is re-run when queried. A view is a name for a query plan; cache the DataFrame if you need it kept.

3. Which is the safe way to filter by a user-supplied name?

Show the answer

spark.sql with args={"name": name}. Parameters are passed separately from the SQL text, so quotes cannot break or inject into the query.

Practice it

Interview problems that use this: write the PySpark, run it, and get graded on hidden tests.

Solve: Conditional Aggregation →

Keep going

Up next · lesson 15 of 35 · 3 min read
row_number / rank
Number and rank rows inside a window, and how the three ranking functions treat ties.

Related lessons

Previous: dropDuplicates

Primary sources: SparkSession.sql · DataFrame.createOrReplaceTempView