Skip to content

Commit 49d9e13

Browse files
committed
docs(notes): add 2025-03-24-db2-cte-en.md
1 parent 42499ec commit 49d9e13

File tree

1 file changed

+204
-0
lines changed

1 file changed

+204
-0
lines changed

notes/2025-03-24-db2-cte-en.md

+204
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
---
2+
title: Common Table Expressions (CTEs) in IBM Db2
3+
lang: en
4+
layout: post
5+
audio: false
6+
translated: false
7+
generated: true
8+
---
9+
10+
Common Table Expressions (CTEs) are temporary result sets that exist only within the execution scope of a single SQL statement. They're particularly useful for improving code readability and working with recursive queries. Let me explain how CTEs work in IBM Db2 with examples.
11+
12+
## Basic CTE Syntax
13+
14+
The basic syntax for a CTE in Db2 follows this pattern:
15+
16+
```sql
17+
WITH cte_name (column_list) AS (
18+
SELECT statement
19+
)
20+
SELECT * FROM cte_name;
21+
```
22+
23+
Your example demonstrates a multi-level CTE that:
24+
1. Creates `regional_sales` to calculate total sales by region
25+
2. Uses that to create `top_regions` containing the top 3 regions by sales
26+
3. Finally joins back to the original orders table to get orders over $1000 from those top regions
27+
28+
## Simple CTE Example
29+
30+
Let's start with a basic example:
31+
32+
```sql
33+
WITH employee_salaries AS (
34+
SELECT department, AVG(salary) as avg_salary
35+
FROM employees
36+
GROUP BY department
37+
)
38+
SELECT department, avg_salary
39+
FROM employee_salaries
40+
WHERE avg_salary > 50000
41+
ORDER BY avg_salary DESC;
42+
```
43+
44+
This query calculates the average salary by department and then filters to show only departments with average salaries above $50,000.
45+
46+
## Multiple CTEs
47+
48+
As shown in your example, you can define multiple CTEs separated by commas:
49+
50+
```sql
51+
WITH dept_summary AS (
52+
SELECT department, COUNT(*) as emp_count
53+
FROM employees
54+
GROUP BY department
55+
),
56+
salary_summary AS (
57+
SELECT department, AVG(salary) as avg_salary
58+
FROM employees
59+
GROUP BY department
60+
)
61+
SELECT d.department, d.emp_count, s.avg_salary
62+
FROM dept_summary d
63+
JOIN salary_summary s ON d.department = s.department
64+
ORDER BY emp_count DESC;
65+
```
66+
67+
## Recursive CTEs
68+
69+
One of the most powerful features of CTEs in Db2 is recursive queries. Here's an example to generate a sequence of dates:
70+
71+
```sql
72+
WITH RECURSIVE date_sequence (date_value) AS (
73+
-- Anchor member
74+
SELECT DATE '2025-01-01' FROM SYSIBM.SYSDUMMY1
75+
UNION ALL
76+
-- Recursive member
77+
SELECT date_value + 1 DAY
78+
FROM date_sequence
79+
WHERE date_value < DATE '2025-01-10'
80+
)
81+
SELECT date_value FROM date_sequence;
82+
```
83+
84+
This will generate dates from January 1, 2025, to January 10, 2025.
85+
86+
## Employee Hierarchy Example
87+
88+
A classic use of recursive CTEs is traversing hierarchical data:
89+
90+
```sql
91+
WITH RECURSIVE emp_hierarchy (emp_id, name, manager_id, level) AS (
92+
-- Anchor: Select the CEO (employee with no manager)
93+
SELECT emp_id, name, manager_id, 1 as level
94+
FROM employees
95+
WHERE manager_id IS NULL
96+
97+
UNION ALL
98+
99+
-- Recursive: Join to get direct reports
100+
SELECT e.emp_id, e.name, e.manager_id, h.level + 1
101+
FROM employees e
102+
JOIN emp_hierarchy h ON e.manager_id = h.emp_id
103+
)
104+
SELECT emp_id, name, level,
105+
REPEAT(' ', level-1) || name as org_chart
106+
FROM emp_hierarchy
107+
ORDER BY level, name;
108+
```
109+
110+
This query builds an organizational chart showing the hierarchy of employees.
111+
112+
## CTEs for Data Analysis
113+
114+
CTEs are excellent for breaking down complex analytical queries:
115+
116+
```sql
117+
WITH monthly_sales AS (
118+
SELECT MONTH(order_date) as month,
119+
SUM(amount) as total_sales
120+
FROM orders
121+
WHERE YEAR(order_date) = 2024
122+
GROUP BY MONTH(order_date)
123+
),
124+
monthly_growth AS (
125+
SELECT month,
126+
total_sales,
127+
LAG(total_sales) OVER (ORDER BY month) as prev_month_sales
128+
FROM monthly_sales
129+
)
130+
SELECT month,
131+
total_sales,
132+
prev_month_sales,
133+
(total_sales - prev_month_sales) as sales_change,
134+
CASE
135+
WHEN prev_month_sales IS NULL THEN NULL
136+
ELSE DECIMAL((total_sales - prev_month_sales) * 100.0 / prev_month_sales, 5, 2)
137+
END as growth_percentage
138+
FROM monthly_growth
139+
ORDER BY month;
140+
```
141+
142+
This example calculates month-over-month sales growth using CTEs to break the calculation into clear steps.
143+
144+
## Performance Considerations
145+
146+
In Db2, CTEs are materialized (stored in memory) if they're referenced multiple times in the query. Some tips:
147+
148+
1. If a CTE is used only once, the optimizer typically inlines it (treats it like a subquery)
149+
2. For complex queries, CTEs can improve performance by avoiding redundant calculations
150+
3. Use the EXPLAIN command to understand how Db2 is processing your CTE queries
151+
4. Consider creating indexes on commonly joined or filtered columns in the base tables
152+
153+
## Db2-Specific CTE Features
154+
155+
IBM Db2 supports some specific features for CTEs:
156+
157+
```sql
158+
-- Using XMLTABLE with a CTE
159+
WITH xml_data(doc) AS (
160+
SELECT XMLPARSE(DOCUMENT '<root><item id="1">Apple</item><item id="2">Orange</item></root>')
161+
FROM SYSIBM.SYSDUMMY1
162+
)
163+
SELECT x.id, x.name
164+
FROM xml_data,
165+
XMLTABLE('//item' PASSING doc
166+
COLUMNS id INTEGER PATH '@id',
167+
name VARCHAR(50) PATH 'text()') AS x;
168+
```
169+
170+
## Using CTEs with INSERT, UPDATE, and DELETE
171+
172+
CTEs can be used with modification statements in Db2:
173+
174+
```sql
175+
-- Using a CTE with INSERT
176+
WITH top_customers AS (
177+
SELECT customer_id, SUM(amount) as total_spent
178+
FROM orders
179+
GROUP BY customer_id
180+
ORDER BY total_spent DESC
181+
FETCH FIRST 100 ROWS ONLY
182+
)
183+
INSERT INTO premium_customers (customer_id, total_spent, join_date)
184+
SELECT customer_id, total_spent, CURRENT DATE
185+
FROM top_customers;
186+
187+
-- Using a CTE with UPDATE
188+
WITH avg_dept_salaries AS (
189+
SELECT department, AVG(salary) as dept_avg
190+
FROM employees
191+
GROUP BY department
192+
)
193+
UPDATE employees e
194+
SET salary = salary * 1.1
195+
WHERE EXISTS (
196+
SELECT 1 FROM avg_dept_salaries a
197+
WHERE e.department = a.department
198+
AND a.dept_avg < 50000
199+
);
200+
```
201+
202+
These examples show how CTEs can simplify data manipulation operations by clearly separating the data selection logic from the actual modification.
203+
204+
Would you like me to elaborate further on any specific aspect of CTEs in Db2?

0 commit comments

Comments
 (0)