Skip to main content

CTE (Common Table Expression)

What is a CTE?

A CTE (Common Table Expression) is a named, temporary result set that you define within a SQL query using a WITH clause. Think of it as a virtual table that exists only for the duration of the query it's part of, it doesn't get stored in the database, but you can reference it just like a regular table within that query.

Example:

WITH cte_name AS (
SELECT column1, column2
FROM acb_table
WHERE condition
)
SELECT *
FROM cte_name
WHERE another_condition;

You can also define multiple CTEs in a single query, and have later CTEs reference earlier ones:

WITH sales_summary AS (
SELECT customer_id, SUM(amount) AS total_sales
FROM orders
GROUP BY customer_id
),
top_customers AS (
SELECT customer_id, total_sales
FROM sales_summary
WHERE total_sales > 10000
)
SELECT *
FROM top_customers
ORDER BY total_sales DESC;

How is a CTE Used?

CTEs are typically used to:

  • Break complex queries into readable steps: instead of one dense, nested query, you build up logic in clearly named stages.

  • Reuse a result set multiple times: within the same query, without repeating the same subquery logic over and over.

  • Simplify aggregations and joins: by pre-calculating a result set before joining or filtering on it.

  • Enable recursive queries: (e.g., traversing hierarchical data like org charts or category trees) using WITH RECURSIVE.

Why is a CTE Better Than a Subquery?

Both CTEs and subqueries can often achieve the same result, but CTEs tend to be the better choice for several reasons:

Aspect

CTE

Subquery

Readability

Named, step-by-step structure, easy to follow

Can become deeply nested and hard to read

Reusability

Can be referenced multiple times in the same query

Must be repeated each time it's needed

Maintainability

Easy to isolate, test, and modify a single step

Harder to isolate logic buried inside nested queries

Recursion

Supports recursive logic (WITH RECURSIVE)

Not supported

Debugging

You can run the CTE block on its own to check results

Harder to test in isolation without rewriting the query

In short: subqueries work fine for simple, one-off filtering, but once a query involves multiple steps, repeated logic, or needs to stay readable for other people to maintain, a CTE is almost always the cleaner and more maintainable option.


Using CTEs in Bright Analytics

Bright Analytics allows you to use CTEs directly when building a subquery datasource. This is useful when you want to shape, filter, or pre-aggregate data before it becomes an available datasource for your reports and dashboards.

Steps

  1. Select your datasource table. From the datasource list, choose the base table you want to build your query on.

  2. Create a new subquery datasource. Use the "New Subquery Datasource" option to open the query editor.

  3. Write your CTE query. In the query editor, you can write a full CTE (WITH ... AS (...)) query, just as you would in standard SQL. This lets you structure your logic into clear, named steps before producing the final result set.

  4. Save the subquery datasource. Once your query runs successfully, save it.

As like other datasources, you can reference the fields when creating metric and dimensions.

Did this answer your question?