首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> Oracle 資料庫 >> Oracle 資料庫基礎

Oracle SQL 查詢與函數進階教學 (中):操作符、單行函數、群組函數、分析函數完整詳解

     編輯:Oracle 資料庫基礎

操作符優先級與分類

Oracle SQL 操作符按優先級從高到低:

  1. 算術操作符:+、-、*、/
  2. 串接操作符:||
  3. 比較操作符:=、!=/^=/<>、>、<、>=、<=、BETWEEN ... AND、IN、LIKE、IS [NOT] NULL
  4. 邏輯操作符:NOT、AND、OR
  5. 集合操作符:UNION/UNION ALL、INTERSECT、MINUS

使用括號 () 可強制改變評估順序,提升可讀性。

單行函數:逐行運算,逐行返回

字元函數

函數說明範例結果
UPPER/LOWER/INITCAP大小寫轉換INITCAP('oracle db')Oracle Db
SUBSTR(str, pos, len)子字串 (支援負位置)SUBSTR('ABCDEFG', -3)EFG
INSTR(str, substr, pos, occ)搜尋子字串位置INSTR('hello', 'l', 1, 2)4
LENGTH字元長度LENGTH('中文')2
LPAD/RPAD(str, n, pad)左/右填充LPAD('123', 6, '0')000123
LTRIM/RTRIM/TRIM去除空白/指定字元TRIM(' abc ')abc
REPLACE(str, old, new)替換REPLACE('a_b_c', '_', '-')a-b-c
TRANSLATE字元級轉換TRANSLATE('123', '12', 'ab')ab3
ASCII/CHR字元碼互轉CHR(65)A
CONCAT串接 (兩參數)CONCAT('A','B')AB

數值函數

函數說明範例
ROUND(n, m)四捨五入 (m 位小數,負數向左)ROUND(123.456, -1)=120
TRUNC(n, m)截斷 (不四捨五入)TRUNC(123.456, 1)=123.4
CEIL/FLOOR向上/向下取整CEIL(3.1)=4
MOD(m,n)餘數MOD(10,3)=1
POWER/SQRT冪/平方根POWER(2,10)=1024
SIGN符號 (1/0/-1)SIGN(-5)=-1
ABS絕對值ABS(-5)=5

日期函數

函數說明範例
SYSDATE / SYSTIMESTAMP當前日期/時間戳SYSDATE
ADD_MONTHS(d, n)加減月份ADD_MONTHS(SYSDATE, -3)
MONTHS_BETWEEN(d1, d2)月份差 (可含小數)MONTHS_BETWEEN('2024-12-31','2024-01-01')≈11.97
LAST_DAY(d)該月最後一天LAST_DAY(SYSDATE)
NEXT_DAY(d, '星期X')下一個指定週幾NEXT_DAY(SYSDATE, 'FRIDAY')
ROUND/TRUNC(date, 'fmt')日期捨入/截斷TRUNC(SYSDATE, 'MM')=月初
EXTRACT(field FROM date)提取欄位 (YEAR/MONTH/DAY/HOUR...)EXTRACT(MONTH FROM SYSDATE)
TO_CHAR(date, 'fmt')日期轉字串TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS')
TO_DATE(str, 'fmt')字串轉日期TO_DATE('2024-01-01', 'YYYY-MM-DD')

轉換函數

  • TO_CHAR(number/date, 'fmt'):格式化輸出。
  • TO_NUMBER(str, 'fmt'):字串轉數值,格式模型如 '999G999D99'。
  • TO_DATE / TO_TIMESTAMP:字串轉日期/時間戳。
  • CAST(expr AS type):ANSI 標準轉換,如 CAST('123' AS NUMBER)。

通用函數 (空值處理、條件邏輯)

函數說明範例
NVL(expr1, expr2)expr1 為 NULL 回傳 expr2NVL(comm, 0)
NVL2(expr1, expr2, expr3)expr1 不為 NULL 回傳 expr2,否則 expr3NVL2(comm, 'Y', 'N')
NULLIF(expr1, expr2)兩值相等回傳 NULL,否則 expr1NULLIF(len, 0)
COALESCE(expr1, expr2, ...)回傳第一個非 NULL 值 (ANSI 標準)COALESCE(comm, sal, 0)
DECODE(expr, srch1, res1, ..., default)等值比較分支 (Oracle 專有)DECODE(deptno, 10, 'ACCT', 20, 'RES', 'OTHER')
CASE expr WHEN v1 THEN r1 ... ELSE re END標準 SQL 條件分支 (支援範圍/複合條件)CASE WHEN sal>5000 THEN 'HIGH' ELSE 'LOW' END

群組函數:多行輸入,單行輸出

函數說明忽略 NULL
COUNT(*) / COUNT(expr)行數 / 非 NULL 個數*/是
SUM / AVG / MEDIAN加總 / 平均 / 中位數是
MAX / MIN最大 / 最小值是
STDDEV / VARIANCE標準差 / 變異數是
GROUPING / GROUPING_ID識別超級彙總行 (ROLLUP/CUBE)-

關鍵子句:GROUP BY 分組、HAVING 過濾群組結果 (可用群組函數)、ROLLUP/CUBE/GROUPING SETS 多維彙總。

群組函數實戰範例

-- 各部門薪資統計
SELECT deptno,
       COUNT(*) AS emp_cnt,
       AVG(sal) AS avg_sal,
       MAX(sal) AS max_sal,
       SUM(sal) AS total_sal
FROM emp
GROUP BY deptno
HAVING AVG(sal) > 2000
ORDER BY total_sal DESC;

-- 多維彙總
SELECT deptno, job,
       COUNT(*),
       SUM(sal),
       GROUPING(deptno) AS grp_dept,
       GROUPING(job) AS grp_job
FROM emp
GROUP BY ROLLUP (deptno, job);

分析函數:分組內排序、排名、移動統計

語法:analytic_function([args]) OVER (PARTITION BY ... ORDER BY ... [WINDOWING])

三大排名函數差異

函數相同值處理序號特性
ROW_NUMBER()強制唯一 (1,2,3,4...)連續、無間隙
RANK()相同並列 (1,2,2,4...)跳號
DENSE_RANK()相同並列 (1,2,2,3...)連續、無跳號

常用分析函數

  • LAG/LEAD(expr, offset, default):取前/後 N 行的值。
  • FIRST_VALUE / LAST_VALUE:視窗首/尾值。
  • NTILE(n):分桶 (如四分位數)。
  • SUM/AVG/COUNT... OVER:移動聚合 (配合 ROWS BETWEEN ... / RANGE BETWEEN ...)。
  • RATIO_TO_REPORT:佔比。

分析函數實戰:每部門薪資前三名

SELECT deptno, ename, sal,
       ROW_NUMBER() OVER (PARTITION BY deptno ORDER BY sal DESC) AS rn
FROM emp
QUALIFY rn <= 3;  -- Oracle 12c+ 支援 QUALIFY,舊版需包一層子查詢

-- 移動平均:最近 3 個月銷售額平均
SELECT sales_month, amount,
       AVG(amount) OVER (ORDER BY sales_month
                         ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) AS mov_avg_3m
FROM monthly_sales;

綜合實戰:銷售報表 (單行+群組+分析)

WITH sales_clean AS (
  SELECT TO_DATE(sale_dt, 'YYYYMMDD') AS sale_date,
         prod_id,
         NVL(qty,0) AS qty,
         NVL(amt,0) AS amt
  FROM staging_sales
  WHERE sale_dt IS NOT NULL
),
daily_agg AS (
  SELECT sale_date,
         SUM(amt) AS daily_amt,
         COUNT(DISTINCT prod_id) AS prod_cnt
  FROM sales_clean
  GROUP BY sale_date
),
final_report AS (
  SELECT sale_date,
         daily_amt,
         prod_cnt,
         AVG(daily_amt) OVER (ORDER BY sale_date
                              ROWS BETWEEN 6 PRECEDING AND CURRENT ROW) AS avg_7d,
         SUM(daily_amt) OVER (ORDER BY sale_date
                              ROWS BETWEEN 29 PRECEDING AND CURRENT ROW) AS sum_30d,
         LAG(daily_amt, 7) OVER (ORDER BY sale_date) AS amt_7d_ago,
         CASE WHEN daily_amt > LAG(daily_amt, 7) OVER (ORDER BY sale_date)
              THEN 'UP' ELSE 'DOWN' END AS wow_trend
  FROM daily_agg
)
SELECT TO_CHAR(sale_date, 'YYYY-MM-DD') AS date,
       daily_amt,
       ROUND(avg_7d,2) AS avg_7d,
       sum_30d,
       amt_7d_ago,
       wow_trend
FROM final_report
ORDER BY sale_date DESC;

最佳實務提醒

  • 函數嵌套慎用:UPPER(TRIM(SUBSTR(...))) 在大表 WHERE 條件會導致全表掃描,改用函數索引或應用層預處理。
  • 隱性轉換殺手:WHERE num_col = '123' → 隱性 TO_NUMBER,索引失效。統一用綁定變數或顯式轉換。
  • NULL 語意:NULL = NULL 是 UNKNOWN,非 TRUE。用 IS NULL/NVL/COALESCE。
  • 分析函數視窗:預設 RANGE UNBOUNDED PRECEDING (含同值行),大數據量時改用 ROWS 明確物理偏移,效能更穩定。
  • 群組 vs 分析:需明細行保留時用分析函數;僅需彙總行用群組函數,資源消耗差異大。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved