Data 360 SQL and Tableau Hyper API
Syntax
WITH Clause
SELECT List
FROM Clause
GROUP BY Clause
WINDOW Clause
UNION, INTERSECT, and EXCEPT Operators
ORDER BY Clause
LIMIT, FETCH, and OFFSET Clauses
VALUES
Window Functions
WITH ClauseThe WITH clause allows you to create and use one or more subqueries. The subqueries act as temporary tables or views. Each subquery can be a SELECT or VALUES statement.
WITH queries evaluate one time per execution of the primary query, even if the primary query refers to them more than one time. The primary query and WITH queries execute at the same time.
To create a WITH clause, specify a name. Optionally, you can provide a list of column names. If you don’t provide column names, the column names are inferred from the subquery.
RECURSIVE allows a SELECT subquery to reference itself by name. The subquery syntax is <non_recursive_term> UNION [ ALL | DISTINCT ] <recursive_term>. Use the recursive self-reference on the right side of the UNION. Only one recursive self-reference is allowed per query. Make sure that the recursive part of the query eventually returns no tuples, or the query loops indefinitely.
1[WITH [RECURSIVE] <with_query>[, ...]]
2SELECT [ALL | DISTINCT [ON (<expression>[, ...])]]
3...
4[{UNION | INTERSECT | EXCEPT} [ALL | DISTINCT] <select>]
5...where with_query is:
1<with_query_name>[(<column_name>[, ...])] AS (<select>)This example creates a simple CTE to filter and aggregate data before using it in the main query.
1WITH high_value_orders AS (
2 SELECT customer_id, order_date, total_amount
3 FROM orders
4 WHERE total_amount > 1000
5)
6SELECT customer_id, COUNT(*) AS order_count, AVG(total_amount) AS avg_amount
7FROM high_value_orders
8GROUP BY customer_id;You can define multiple CTEs in a single query by separating them with commas.
1WITH sales_summary AS (
2 SELECT customer_id, SUM(amount) AS total_sales
3 FROM orders
4 WHERE order_date >= '2024-01-01'
5 GROUP BY customer_id
6),
7customer_info AS (
8 SELECT customer_id, customer_name, region
9 FROM customers
10 WHERE status = 'active'
11)
12SELECT ci.customer_name, ci.region, ss.total_sales
13FROM customer_info ci
14JOIN sales_summary ss ON ci.customer_id = ss.customer_id
15ORDER BY ss.total_sales DESC;This example shows how to specify column names explicitly in the CTE definition.
1WITH regional_sales(region_name, total_revenue, order_count) AS (
2 SELECT region, SUM(amount), COUNT(*)
3 FROM orders o
4 JOIN customers c ON o.customer_id = c.customer_id
5 GROUP BY region
6)
7SELECT region_name, total_revenue, order_count,
8 total_revenue / order_count AS avg_order_value
9FROM regional_sales
10WHERE total_revenue > 50000;CTEs can also use VALUES statements to create temporary data sets.
1WITH month_names(month_num, month_name) AS (
2 VALUES (1, 'January'), (2, 'February'), (3, 'March'),
3 (4, 'April'), (5, 'May'), (6, 'June'),
4 (7, 'July'), (8, 'August'), (9, 'September'),
5 (10, 'October'), (11, 'November'), (12, 'December')
6)
7SELECT mn.month_name, COALESCE(SUM(o.amount), 0) as monthly_sales
8FROM month_names mn
9LEFT JOIN orders o ON EXTRACT(MONTH FROM o.order_date) = mn.month_num
10 AND EXTRACT(YEAR FROM o.order_date) = 2024
11GROUP BY mn.month_num, mn.month_name
12ORDER BY mn.month_num;This example demonstrates using UNION within a CTE to combine data from multiple sources.
1WITH all_contacts AS (
2 SELECT customer_id, email, 'customer' AS contact_type
3 FROM customers
4 WHERE email IS NOT NULL
5 UNION ALL
6 SELECT vendor_id, email, 'vendor' AS contact_type
7 FROM vendors
8 WHERE email IS NOT NULL
9)
10SELECT contact_type, COUNT(*) as contact_count
11FROM all_contacts
12GROUP BY contact_type;This example uses WITH RECURSIVE to find all direct or indirect subordinates of employee Mary, and their level of indirectness, from a table that shows only direct subordinates.
1WITH RECURSIVE employee_recursive(distance, employee_name, manager_name) AS (
2 SELECT 1, employee_name, manager_name
3 FROM employee
4 WHERE manager_name = 'Mary'
5 UNION ALL
6 SELECT er.distance + 1, e.employee_name, e.manager_name
7 FROM employee_recursive er, employee e
8 WHERE er.employee_name = e.manager_name
9 )
10SELECT distance, employee_name FROM employee_recursive;