一、建立資料表 #
1. 建立員工表 EMPLOYEES
#
sql
CREATE TABLE employees (
emp_id NUMBER PRIMARY KEY,
emp_name VARCHAR2(50),
dept_id NUMBER,
salary NUMBER,
hire_date DATE
);
INSERT INTO employees VALUES (1, 'Alice', 10, 6000, TO_DATE('2015-01-10', 'YYYY-MM-DD'));
INSERT INTO employees VALUES (2, 'Bob', 10, 8000, TO_DATE('2016-03-12', 'YYYY-MM-DD'));
INSERT INTO employees VALUES (3, 'Charlie', 20, 5000, TO_DATE('2017-06-01', 'YYYY-MM-DD'));
INSERT INTO employees VALUES (4, 'David', 30, 9000, TO_DATE('2014-08-20', 'YYYY-MM-DD'));
INSERT INTO employees VALUES (5, 'Eva', 20, 7000, TO_DATE('2018-11-15', 'YYYY-MM-DD'));
INSERT INTO employees VALUES (6, 'Frank', 30, 8000, TO_DATE('2015-12-01', 'YYYY-MM-DD'));查詢結果:
sql
SELECT * FROM employees;| EMP_ID | EMP_NAME | DEPT_ID | SALARY | HIRE_DATE |
|---|---|---|---|---|
| 1 | Alice | 10 | 6000 | 2015-01-10 |
| 2 | Bob | 10 | 8000 | 2016-03-12 |
| 3 | Charlie | 20 | 5000 | 2017-06-01 |
| 4 | David | 30 | 9000 | 2014-08-20 |
| 5 | Eva | 20 | 7000 | 2018-11-15 |
| 6 | Frank | 30 | 8000 | 2015-12-01 |
2. 建立部門表 DEPARTMENTS
#
sql
CREATE TABLE departments (
dept_id NUMBER PRIMARY KEY,
dept_name VARCHAR2(50)
);
INSERT INTO departments VALUES (10, 'Sales');
INSERT INTO departments VALUES (20, 'IT');
INSERT INTO departments VALUES (30, 'HR');查詢結果:
sql
SELECT * FROM departments;| DEPT_ID | DEPT_NAME |
|---|---|
| 10 | Sales |
| 20 | IT |
| 30 | HR |
3. 建立專案表 PROJECTS
#
sql
CREATE TABLE projects (
project_id NUMBER PRIMARY KEY,
project_name VARCHAR2(50),
emp_id NUMBER,
start_date DATE,
end_date DATE
);
INSERT INTO projects VALUES (101, 'ERP Upgrade', 1, TO_DATE('2020-01-01','YYYY-MM-DD'), TO_DATE('2020-12-31','YYYY-MM-DD'));
INSERT INTO projects VALUES (102, 'Mobile App', 3, TO_DATE('2021-03-01','YYYY-MM-DD'), TO_DATE('2021-09-30','YYYY-MM-DD'));
INSERT INTO projects VALUES (103, 'Data Migration', 5, TO_DATE('2019-05-01','YYYY-MM-DD'), TO_DATE('2020-03-31','YYYY-MM-DD'));
INSERT INTO projects VALUES (104, 'Cloud Migration', 2, TO_DATE('2021-06-01','YYYY-MM-DD'), TO_DATE('2022-02-28','YYYY-MM-DD'));查詢結果:
sql
SELECT * FROM projects;| PROJECT_ID | PROJECT_NAME | EMP_ID | START_DATE | END_DATE |
|---|---|---|---|---|
| 101 | ERP Upgrade | 1 | 2020-01-01 | 2020-12-31 |
| 102 | Mobile App | 3 | 2021-03-01 | 2021-09-30 |
| 103 | Data Migration | 5 | 2019-05-01 | 2020-03-31 |
| 104 | Cloud Migration | 2 | 2021-06-01 | 2022-02-28 |
二、SQL 常用查詢 #
1. SELECT #
執行前資料:
sql
SELECT emp_id, emp_name, salary FROM employees ORDER BY salary DESC;| EMP_ID | EMP_NAME | SALARY |
|---|---|---|
| 4 | David | 9000 |
| 2 | Bob | 8000 |
| 6 | Frank | 8000 |
| 5 | Eva | 7000 |
| 1 | Alice | 6000 |
| 3 | Charlie | 5000 |
執行後結果:
sql
-- 查詢薪資超過 7000 的員工,按薪資降序排列
SELECT emp_id, emp_name, salary
FROM employees
WHERE salary > 7000
ORDER BY salary DESC;結果:
| EMP_ID | EMP_NAME | SALARY |
|---|---|---|
| 4 | David | 9000 |
| 2 | Bob | 8000 |
| 6 | Frank | 8000 |
2. DISTINCT #
執行前資料:
sql
SELECT emp_name, dept_id FROM employees ORDER BY dept_id;| EMP_NAME | DEPT_ID |
|---|---|
| Alice | 10 |
| Bob | 10 |
| Charlie | 20 |
| Eva | 20 |
| David | 30 |
| Frank | 30 |
執行後結果:
sql
-- 查詢員工所屬的所有部門,去除重複值
SELECT DISTINCT dept_id
FROM employees;結果:
| DEPT_ID |
|---|
| 10 |
| 20 |
| 30 |
3. 字串處理 #
執行前資料:
sql
SELECT emp_name FROM employees ORDER BY emp_name;| EMP_NAME |
|---|
| Alice |
| Bob |
| Charlie |
| David |
| Eva |
| Frank |
執行後結果:
sql
-- 將員工姓名轉為大寫,並計算姓名長度
SELECT emp_name, UPPER(emp_name) AS upper_name, LENGTH(emp_name) AS name_len
FROM employees;結果:
| EMP_NAME | UPPER_NAME | NAME_LEN |
|---|---|---|
| Alice | ALICE | 5 |
| Bob | BOB | 3 |
| Charlie | CHARLIE | 7 |
| David | DAVID | 5 |
| Eva | EVA | 3 |
| Frank | FRANK | 5 |
4. 日期處理 #
執行前資料:
sql
SELECT emp_name, hire_date FROM employees ORDER BY hire_date;| EMP_NAME | HIRE_DATE |
|---|---|
| David | 2014-08-20 |
| Alice | 2015-01-10 |
| Frank | 2015-12-01 |
| Bob | 2016-03-12 |
| Charlie | 2017-06-01 |
| Eva | 2018-11-15 |
執行後結果:
sql
-- 計算員工雇用日期後 6 個月的日期,以及工作月數
SELECT emp_name,
hire_date,
ADD_MONTHS(hire_date, 6) AS after_6_months,
MONTHS_BETWEEN(SYSDATE, hire_date) AS months_worked
FROM employees;結果:
| EMP_NAME | HIRE_DATE | AFTER_6_MONTHS | MONTHS_WORKED |
|---|---|---|---|
| Alice | 2015-01-10 | 2015-07-10 | 108.5 |
| Bob | 2016-03-12 | 2016-09-12 | 96.8 |
| Charlie | 2017-06-01 | 2017-12-01 | 82.2 |
| David | 2014-08-20 | 2015-02-20 | 127.3 |
| Eva | 2018-11-15 | 2019-05-15 | 64.7 |
| Frank | 2015-12-01 | 2016-06-01 | 108.1 |
5. GROUP BY #
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 按部門分組,計算各部門的員工數、總薪資和平均薪資
SELECT dept_id,
COUNT(*) AS emp_count,
SUM(salary) AS total_salary,
ROUND(AVG(salary), 2) AS avg_salary
FROM employees
GROUP BY dept_id
ORDER BY dept_id;結果:
| DEPT_ID | EMP_COUNT | TOTAL_SALARY | AVG_SALARY |
|---|---|---|---|
| 10 | 2 | 14000 | 7000 |
| 20 | 2 | 12000 | 6000 |
| 30 | 2 | 17000 | 8500 |
三、JOIN 操作 #
1. INNER JOIN #
執行前資料:
sql
-- 員工表
SELECT emp_name, dept_id FROM employees ORDER BY dept_id, emp_name;| EMP_NAME | DEPT_ID |
|---|---|
| Alice | 10 |
| Bob | 10 |
| Charlie | 20 |
| Eva | 20 |
| David | 30 |
| Frank | 30 |
sql
-- 部門表
SELECT dept_id, dept_name FROM departments ORDER BY dept_id;| DEPT_ID | DEPT_NAME |
|---|---|
| 10 | Sales |
| 20 | IT |
| 30 | HR |
執行後結果:
sql
-- 連接員工表和部門表,顯示員工姓名和部門名稱
SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;結果:
| EMP_NAME | DEPT_NAME |
|---|---|
| Alice | Sales |
| Bob | Sales |
| Charlie | IT |
| David | HR |
| Eva | IT |
| Frank | HR |
2. LEFT JOIN #
執行前資料:
sql
-- 員工表
SELECT emp_name, dept_id FROM employees ORDER BY dept_id, emp_name;| EMP_NAME | DEPT_ID |
|---|---|
| Alice | 10 |
| Bob | 10 |
| Charlie | 20 |
| Eva | 20 |
| David | 30 |
| Frank | 30 |
sql
-- 部門表
SELECT dept_id, dept_name FROM departments ORDER BY dept_id;| DEPT_ID | DEPT_NAME |
|---|---|
| 10 | Sales |
| 20 | IT |
| 30 | HR |
執行後結果:
sql
-- 左連接員工表和部門表,保留所有員工資料
SELECT e.emp_name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;結果:
| EMP_NAME | DEPT_NAME |
|---|---|
| Alice | Sales |
| Bob | Sales |
| Charlie | IT |
| David | HR |
| Eva | IT |
| Frank | HR |
3. 多表 JOIN #
執行前資料:
sql
-- 員工表
SELECT emp_id, emp_name, dept_id FROM employees ORDER BY emp_name;| EMP_ID | EMP_NAME | DEPT_ID |
|---|---|---|
| 1 | Alice | 10 |
| 2 | Bob | 10 |
| 3 | Charlie | 20 |
| 4 | David | 30 |
| 5 | Eva | 20 |
| 6 | Frank | 30 |
sql
-- 部門表
SELECT dept_id, dept_name FROM departments ORDER BY dept_id;| DEPT_ID | DEPT_NAME |
|---|---|
| 10 | Sales |
| 20 | IT |
| 30 | HR |
sql
-- 專案表
SELECT emp_id, project_name FROM projects ORDER BY emp_id;| EMP_ID | PROJECT_NAME |
|---|---|
| 1 | ERP Upgrade |
| 2 | Cloud Migration |
| 3 | Mobile App |
| 5 | Data Migration |
執行後結果:
sql
-- 三表連接:員工表、部門表、專案表,顯示員工的部門和專案資訊
SELECT e.emp_name, d.dept_name, p.project_name
FROM employees e
JOIN departments d ON e.dept_id = d.dept_id
LEFT JOIN projects p ON e.emp_id = p.emp_id
ORDER BY e.emp_name;結果:
| EMP_NAME | DEPT_NAME | PROJECT_NAME |
|---|---|---|
| Alice | Sales | ERP Upgrade |
| Bob | Sales | Cloud Migration |
| Charlie | IT | Mobile App |
| David | HR | NULL |
| Eva | IT | Data Migration |
| Frank | HR | NULL |
四、分析函數 #
1. RANK()、DENSE_RANK()、ROW_NUMBER() #
- RANK(): 相同值會得到相同排名,下一個排名會跳過(如:1,1,3,4)
- DENSE_RANK(): 相同值會得到相同排名,下一個排名連續(如:1,1,2,3)
- ROW_NUMBER(): 每行都有唯一的連續編號,不考慮相同值
sql
-- 按部門分組,對每個部門內的員工按薪資進行排名
SELECT emp_name,
dept_id,
salary,
RANK() OVER(PARTITION BY dept_id ORDER BY salary DESC) AS rank_salary,
DENSE_RANK() OVER(PARTITION BY dept_id ORDER BY salary DESC) AS dense_rank_salary,
ROW_NUMBER() OVER(PARTITION BY dept_id ORDER BY salary DESC) AS row_num
FROM employees;結果:
| EMP_NAME | DEPT_ID | SALARY | RANK_SALARY | DENSE_RANK_SALARY | ROW_NUM |
|---|---|---|---|---|---|
| Bob | 10 | 8000 | 1 | 1 | 1 |
| Alice | 10 | 6000 | 2 | 2 | 2 |
| Eva | 20 | 7000 | 1 | 1 | 1 |
| Charlie | 20 | 5000 | 2 | 2 | 2 |
| David | 30 | 9000 | 1 | 1 | 1 |
| Frank | 30 | 8000 | 2 | 2 | 2 |
2. SUM() + PARTITION BY #
可以在每一行上計算聚合結果,而不需要 GROUP BY。PARTITION BY 用於分組,OVER() 定義計算範圍:
- SUM() OVER(): 計算分組內的總和
- AVG() OVER(): 計算分組內的平均值
- COUNT() OVER(): 計算分組內的記錄數
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 在每行顯示部門的總薪資、平均薪資和員工數
SELECT emp_name,
dept_id,
salary,
SUM(salary) OVER(PARTITION BY dept_id) AS dept_salary_total,
AVG(salary) OVER(PARTITION BY dept_id) AS dept_avg_salary,
COUNT(*) OVER(PARTITION BY dept_id) AS dept_emp_count
FROM employees;結果:
| EMP_NAME | DEPT_ID | SALARY | DEPT_SALARY_TOTAL | DEPT_AVG_SALARY | DEPT_EMP_COUNT |
|---|---|---|---|---|---|
| Alice | 10 | 6000 | 14000 | 7000 | 2 |
| Bob | 10 | 8000 | 14000 | 7000 | 2 |
| Charlie | 20 | 5000 | 12000 | 6000 | 2 |
| Eva | 20 | 7000 | 12000 | 6000 | 2 |
| David | 30 | 9000 | 17000 | 8500 | 2 |
| Frank | 30 | 8000 | 17000 | 8500 | 2 |
3. 累計計算 (Running Total) #
累計計算用於分析資料的累積趨勢,常見於財務報表、銷售分析等場景:
- ORDER BY: 定義累計的順序
- ROWS UNBOUNDED PRECEDING: 從分組開始到當前行的所有記錄
- 無 ROWS 子句: 從分組開始到當前行的累計(相同值會合併)
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 計算每個部門內按薪資降序的累計總和,區分不同累計方式
SELECT emp_name,
dept_id,
salary,
SUM(salary) OVER(PARTITION BY dept_id ORDER BY salary DESC) AS running_total,
SUM(salary) OVER(PARTITION BY dept_id ORDER BY salary DESC ROWS UNBOUNDED PRECEDING) AS cumulative_total
FROM employees;結果:
| EMP_NAME | DEPT_ID | SALARY | RUNNING_TOTAL | CUMULATIVE_TOTAL |
|---|---|---|---|---|
| Bob | 10 | 8000 | 8000 | 8000 |
| Alice | 10 | 6000 | 14000 | 14000 |
| Eva | 20 | 7000 | 7000 | 7000 |
| Charlie | 20 | 5000 | 12000 | 12000 |
| David | 30 | 9000 | 9000 | 9000 |
| Frank | 30 | 8000 | 17000 | 17000 |
4. 百分比計算 #
百分比計算用於分析各項指標在整體中的佔比,幫助理解資料的相對重要性:
- 部門內佔比: 員工薪資在部門總薪資中的百分比
- 整體佔比: 員工薪資在公司總薪資中的百分比
- ROUND(): 控制小數位數,提高可讀性
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 計算每個員工薪資在部門內和整體的佔比百分比
SELECT emp_name,
dept_id,
salary,
ROUND(salary * 100.0 / SUM(salary) OVER(PARTITION BY dept_id), 2) AS salary_percentage,
ROUND(salary * 100.0 / SUM(salary) OVER(), 2) AS total_percentage
FROM employees
ORDER BY dept_id, salary DESC;結果:
| EMP_NAME | DEPT_ID | SALARY | SALARY_PERCENTAGE | TOTAL_PERCENTAGE |
|---|---|---|---|---|
| Bob | 10 | 8000 | 57.14 | 18.60 |
| Alice | 10 | 6000 | 1 | 13.95 |
| Eva | 20 | 7000 | 58.33 | 16.28 |
| Charlie | 20 | 5000 | 41.67 | 11.63 |
| David | 30 | 9000 | 52.94 | 20.93 |
| Frank | 30 | 8000 | 47.06 | 18.60 |
5. 移動平均 (Moving Average) #
移動平均用於平滑資料波動,識別趨勢,常見於時間序列分析和財務分析:
- 3點移動平均: 當前行及其前後各1行的平均值
- 累計移動平均: 從分組開始到當前行的平均值
- ROWS BETWEEN: 定義移動平均的範圍
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 計算 3 點移動平均和累計移動平均,用於趨勢分析
SELECT emp_name,
dept_id,
salary,
ROUND(AVG(salary) OVER(PARTITION BY dept_id ORDER BY salary DESC ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING), 2) AS moving_avg_3,
ROUND(AVG(salary) OVER(PARTITION BY dept_id ORDER BY salary DESC ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW), 2) AS moving_avg_all
FROM employees;結果:
| EMP_NAME | DEPT_ID | SALARY | MOVING_AVG_3 | MOVING_AVG_ALL |
|---|---|---|---|---|
| Bob | 10 | 8000 | 7000.00 | 8000.00 |
| Alice | 10 | 6000 | 7000.00 | 7000.00 |
| Eva | 20 | 7000 | 6000.00 | 7000.00 |
| Charlie | 20 | 5000 | 6000.00 | 6000.00 |
| David | 30 | 9000 | 8500.00 | 9000.00 |
| Frank | 30 | 8000 | 8500.00 | 8500.00 |
6. 分位數計算 #
分位數計算用於將資料分成等份,識別資料的分布情況和相對位置:
- NTILE(): 將資料分成指定數量的等份(如3等份:1,2,3)
- PERCENT_RANK(): 計算每行在分組中的百分位排名(0.00 到 1.00)
- 應用場景: 薪資等級劃分、績效評估、風險分析等
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 將每個部門的員工按薪資分成 3 等份,並計算百分位排名
SELECT emp_name,
dept_id,
salary,
NTILE(3) OVER(PARTITION BY dept_id ORDER BY salary DESC) AS salary_tier,
PERCENT_RANK() OVER(PARTITION BY dept_id ORDER BY salary DESC) AS percentile_rank
FROM employees;結果:
| EMP_NAME | DEPT_ID | SALARY | SALARY_TIER | PERCENTILE_RANK |
|---|---|---|---|---|
| Bob | 10 | 8000 | 1 | 0.00 |
| Alice | 10 | 6000 | 2 | 1.00 |
| Eva | 20 | 7000 | 1 | 0.00 |
| Charlie | 20 | 5000 | 2 | 1.00 |
| David | 30 | 9000 | 1 | 0.00 |
| Frank | 30 | 8000 | 2 | 1.00 |
五、複雜查詢範例 #
1. 找出每個部門薪水最高的員工 #
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 使用子查詢和 RANK 函數,找出每個部門薪資最高的員工
SELECT emp_name, dept_id, salary
FROM (
SELECT emp_name,
dept_id,
salary,
RANK() OVER(PARTITION BY dept_id ORDER BY salary DESC) AS rk
FROM employees
)
WHERE rk = 1;結果:
| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Eva | 20 | 7000 |
| David | 30 | 9000 |
2. 找出每個部門薪水排名前 2 的員工 #
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 使用子查詢和 DENSE_RANK 函數,找出每個部門薪資排名前 2 的員工
SELECT emp_name, dept_id, salary
FROM (
SELECT emp_name,
dept_id,
salary,
DENSE_RANK() OVER(PARTITION BY dept_id ORDER BY salary DESC) AS rnk
FROM employees
)
WHERE rnk <= 2
ORDER BY dept_id, salary DESC;結果:
| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
3. 找出專案期間重疊的員工 #
執行前資料:
sql
SELECT emp_id, project_name, start_date, end_date FROM projects ORDER BY emp_id, start_date;| EMP_ID | PROJECT_NAME | START_DATE | END_DATE |
|---|---|---|---|
| 1 | ERP Upgrade | 2020-01-01 | 2020-12-31 |
| 2 | Cloud Migration | 2021-06-01 | 2022-02-28 |
| 3 | Mobile App | 2021-03-01 | 2021-09-30 |
| 5 | Data Migration | 2019-05-01 | 2020-03-31 |
執行後結果:
sql
-- 自連接專案表,找出同一個員工負責的時間重疊專案
SELECT p1.emp_id, p1.project_name, p2.project_name
FROM projects p1
JOIN projects p2
ON p1.emp_id = p2.emp_id
AND p1.project_id < p2.project_id
AND p1.start_date <= p2.end_date
AND p1.end_date >= p2.start_date;結果:
| EMP_ID | PROJECT_NAME | PROJECT_NAME_2 |
|---|---|---|
| 1 | ERP Upgrade | Cloud Migration |
| 3 | Mobile App | Data Migration |
4. GROUP BY + PARTITION BY 混合使用 #
執行前資料:
sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;| EMP_NAME | DEPT_ID | SALARY |
|---|---|---|
| Bob | 10 | 8000 |
| Alice | 10 | 6000 |
| Eva | 20 | 7000 |
| Charlie | 20 | 5000 |
| David | 30 | 9000 |
| Frank | 30 | 8000 |
執行後結果:
sql
-- 結合 GROUP BY 和 PARTITION BY,創建部門薪資綜合分析報表
SELECT
dept_id,
COUNT(*) AS dept_emp_count,
SUM(salary) AS dept_total_salary,
ROUND(AVG(salary), 2) AS dept_avg_salary,
MAX(salary) AS dept_max_salary,
MIN(salary) AS dept_min_salary,
ROUND(
(MAX(salary) - MIN(salary)) * 100.0 / AVG(salary), 2
) AS salary_range_percentage,
RANK() OVER(ORDER BY AVG(salary) DESC) AS dept_rank_by_avg,
ROUND(
AVG(salary) * 100.0 / SUM(AVG(salary)) OVER(), 2
) AS dept_avg_percentage
FROM employees
GROUP BY dept_id
ORDER BY dept_id;結果:
| DEPT_ID | DEPT_EMP_COUNT | DEPT_TOTAL_SALARY | DEPT_AVG_SALARY | DEPT_MAX_SALARY | DEPT_MIN_SALARY | SALARY_RANGE_PERCENTAGE | DEPT_RANK_BY_AVG | DEPT_AVG_PERCENTAGE |
|---|---|---|---|---|---|---|---|---|
| 10 | 2 | 14000 | 7000.00 | 8000 | 6000 | 28.57 | 2 | 33.33 |
| 20 | 2 | 12000 | 6000.00 | 7000 | 5000 | 33.33 | 3 | 28.57 |
| 30 | 2 | 17000 | 8500.00 | 9000 | 8000 | 11.76 | 1 | 38.10 |