快轉到主要內容
Oracle SQL 常用指令、操作

Oracle SQL 常用指令、操作

·
類別 
後端開發 常用指令
標籤 
Oracle Sql
Eason Chiu
作者
Eason Chiu
一個不做筆記就容易忘記的工程師
目錄

一、建立資料表
#

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_IDEMP_NAMEDEPT_IDSALARYHIRE_DATE
1Alice1060002015-01-10
2Bob1080002016-03-12
3Charlie2050002017-06-01
4David3090002014-08-20
5Eva2070002018-11-15
6Frank3080002015-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_IDDEPT_NAME
10Sales
20IT
30HR

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_IDPROJECT_NAMEEMP_IDSTART_DATEEND_DATE
101ERP Upgrade12020-01-012020-12-31
102Mobile App32021-03-012021-09-30
103Data Migration52019-05-012020-03-31
104Cloud Migration22021-06-012022-02-28

二、SQL 常用查詢
#

1. SELECT
#

執行前資料:

sql
SELECT emp_id, emp_name, salary FROM employees ORDER BY salary DESC;
EMP_IDEMP_NAMESALARY
4David9000
2Bob8000
6Frank8000
5Eva7000
1Alice6000
3Charlie5000

執行後結果:

sql
-- 查詢薪資超過 7000 的員工,按薪資降序排列
SELECT emp_id, emp_name, salary
FROM employees
WHERE salary > 7000
ORDER BY salary DESC;

結果:

EMP_IDEMP_NAMESALARY
4David9000
2Bob8000
6Frank8000

2. DISTINCT
#

執行前資料:

sql
SELECT emp_name, dept_id FROM employees ORDER BY dept_id;
EMP_NAMEDEPT_ID
Alice10
Bob10
Charlie20
Eva20
David30
Frank30

執行後結果:

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_NAMEUPPER_NAMENAME_LEN
AliceALICE5
BobBOB3
CharlieCHARLIE7
DavidDAVID5
EvaEVA3
FrankFRANK5

4. 日期處理
#

執行前資料:

sql
SELECT emp_name, hire_date FROM employees ORDER BY hire_date;
EMP_NAMEHIRE_DATE
David2014-08-20
Alice2015-01-10
Frank2015-12-01
Bob2016-03-12
Charlie2017-06-01
Eva2018-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_NAMEHIRE_DATEAFTER_6_MONTHSMONTHS_WORKED
Alice2015-01-102015-07-10108.5
Bob2016-03-122016-09-1296.8
Charlie2017-06-012017-12-0182.2
David2014-08-202015-02-20127.3
Eva2018-11-152019-05-1564.7
Frank2015-12-012016-06-01108.1

5. GROUP BY
#

執行前資料:

sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;
EMP_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_IDEMP_COUNTTOTAL_SALARYAVG_SALARY
102140007000
202120006000
302170008500

三、JOIN 操作
#

1. INNER JOIN
#

執行前資料:

sql
-- 員工表
SELECT emp_name, dept_id FROM employees ORDER BY dept_id, emp_name;
EMP_NAMEDEPT_ID
Alice10
Bob10
Charlie20
Eva20
David30
Frank30
sql
-- 部門表
SELECT dept_id, dept_name FROM departments ORDER BY dept_id;
DEPT_IDDEPT_NAME
10Sales
20IT
30HR

執行後結果:

sql
-- 連接員工表和部門表,顯示員工姓名和部門名稱
SELECT e.emp_name, d.dept_name
FROM employees e
INNER JOIN departments d ON e.dept_id = d.dept_id;

結果:

EMP_NAMEDEPT_NAME
AliceSales
BobSales
CharlieIT
DavidHR
EvaIT
FrankHR

2. LEFT JOIN
#

執行前資料:

sql
-- 員工表
SELECT emp_name, dept_id FROM employees ORDER BY dept_id, emp_name;
EMP_NAMEDEPT_ID
Alice10
Bob10
Charlie20
Eva20
David30
Frank30
sql
-- 部門表
SELECT dept_id, dept_name FROM departments ORDER BY dept_id;
DEPT_IDDEPT_NAME
10Sales
20IT
30HR

執行後結果:

sql
-- 左連接員工表和部門表,保留所有員工資料
SELECT e.emp_name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.dept_id;

結果:

EMP_NAMEDEPT_NAME
AliceSales
BobSales
CharlieIT
DavidHR
EvaIT
FrankHR

3. 多表 JOIN
#

執行前資料:

sql
-- 員工表
SELECT emp_id, emp_name, dept_id FROM employees ORDER BY emp_name;
EMP_IDEMP_NAMEDEPT_ID
1Alice10
2Bob10
3Charlie20
4David30
5Eva20
6Frank30
sql
-- 部門表
SELECT dept_id, dept_name FROM departments ORDER BY dept_id;
DEPT_IDDEPT_NAME
10Sales
20IT
30HR
sql
-- 專案表
SELECT emp_id, project_name FROM projects ORDER BY emp_id;
EMP_IDPROJECT_NAME
1ERP Upgrade
2Cloud Migration
3Mobile App
5Data 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_NAMEDEPT_NAMEPROJECT_NAME
AliceSalesERP Upgrade
BobSalesCloud Migration
CharlieITMobile App
DavidHRNULL
EvaITData Migration
FrankHRNULL

四、分析函數
#

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_NAMEDEPT_IDSALARYRANK_SALARYDENSE_RANK_SALARYROW_NUM
Bob108000111
Alice106000222
Eva207000111
Charlie205000222
David309000111
Frank308000222

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_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_NAMEDEPT_IDSALARYDEPT_SALARY_TOTALDEPT_AVG_SALARYDEPT_EMP_COUNT
Alice1060001400070002
Bob1080001400070002
Charlie2050001200060002
Eva2070001200060002
David3090001700085002
Frank3080001700085002

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_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_NAMEDEPT_IDSALARYRUNNING_TOTALCUMULATIVE_TOTAL
Bob10800080008000
Alice1060001400014000
Eva20700070007000
Charlie2050001200012000
David30900090009000
Frank3080001700017000

4. 百分比計算
#

百分比計算用於分析各項指標在整體中的佔比,幫助理解資料的相對重要性:

  • 部門內佔比: 員工薪資在部門總薪資中的百分比
  • 整體佔比: 員工薪資在公司總薪資中的百分比
  • ROUND(): 控制小數位數,提高可讀性

執行前資料:

sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;
EMP_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_NAMEDEPT_IDSALARYSALARY_PERCENTAGETOTAL_PERCENTAGE
Bob10800057.1418.60
Alice106000113.95
Eva20700058.3316.28
Charlie20500041.6711.63
David30900052.9420.93
Frank30800047.0618.60

5. 移動平均 (Moving Average)
#

移動平均用於平滑資料波動,識別趨勢,常見於時間序列分析和財務分析:

  • 3點移動平均: 當前行及其前後各1行的平均值
  • 累計移動平均: 從分組開始到當前行的平均值
  • ROWS BETWEEN: 定義移動平均的範圍

執行前資料:

sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;
EMP_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_NAMEDEPT_IDSALARYMOVING_AVG_3MOVING_AVG_ALL
Bob1080007000.008000.00
Alice1060007000.007000.00
Eva2070006000.007000.00
Charlie2050006000.006000.00
David3090008500.009000.00
Frank3080008500.008500.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_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_NAMEDEPT_IDSALARYSALARY_TIERPERCENTILE_RANK
Bob10800010.00
Alice10600021.00
Eva20700010.00
Charlie20500021.00
David30900010.00
Frank30800021.00


五、複雜查詢範例
#

1. 找出每個部門薪水最高的員工
#

執行前資料:

sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;
EMP_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_NAMEDEPT_IDSALARY
Bob108000
Eva207000
David309000

2. 找出每個部門薪水排名前 2 的員工
#

執行前資料:

sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;
EMP_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

3. 找出專案期間重疊的員工
#

執行前資料:

sql
SELECT emp_id, project_name, start_date, end_date FROM projects ORDER BY emp_id, start_date;
EMP_IDPROJECT_NAMESTART_DATEEND_DATE
1ERP Upgrade2020-01-012020-12-31
2Cloud Migration2021-06-012022-02-28
3Mobile App2021-03-012021-09-30
5Data Migration2019-05-012020-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_IDPROJECT_NAMEPROJECT_NAME_2
1ERP UpgradeCloud Migration
3Mobile AppData Migration

4. GROUP BY + PARTITION BY 混合使用
#

執行前資料:

sql
SELECT emp_name, dept_id, salary FROM employees ORDER BY dept_id, salary DESC;
EMP_NAMEDEPT_IDSALARY
Bob108000
Alice106000
Eva207000
Charlie205000
David309000
Frank308000

執行後結果:

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_IDDEPT_EMP_COUNTDEPT_TOTAL_SALARYDEPT_AVG_SALARYDEPT_MAX_SALARYDEPT_MIN_SALARYSALARY_RANGE_PERCENTAGEDEPT_RANK_BY_AVGDEPT_AVG_PERCENTAGE
102140007000.008000600028.57233.33
202120006000.007000500033.33328.57
302170008500.009000800011.76138.10

相關文章

Html2canvas + Fabricjs 應用
類別 
前端開發
標籤 
Html2canvas Fabricjs
把 Codepen 嵌入 Hugo文章上
類別 
Hugo網站相關
標籤 
Codepen Hugo
使用Can I Use 檢查瀏覽器相容性
類別 
前端開發
標籤 
Browser