MySQL 與 Oracle 在 SQL 方言、數據類型、函數、存儲過程、事務控制等方面存在顯著差異。本文從實戰遷移角度,系統對比 18 大核心差異點,提供對照表與改寫模式,助力異構數據庫遷移與多數據庫兼容開發。
| 類別 | Oracle | MySQL | 改寫要點 |
|---|---|---|---|
| 日期時間 | SYSDATE | NOW() / SYSDATE() | MySQL SYSDATE() 為動態值,NOW() 為語句開始時固定值 |
TO_CHAR(date, 'fmt') | DATE_FORMAT(date, '%fmt') | 格式符不同:YYYY→%Y, MM→%m, DD→%d, HH24→%H, MI→%i, SS→%s | |
ADD_MONTHS(d, n) | DATE_ADD(d, INTERVAL n MONTH) | MySQL INTERVAL 關鍵字靈活支持 YEAR/QUARTER/MONTH/DAY/HOUR/MINUTE/SECOND | |
| 字符串 | || 拼接 | CONCAT(str1, str2, ...) | MySQL || 為邏輯 OR(除非開啟 PIPES_AS_CONCAT SQL 模式) |
SUBSTR(str, pos, len) | SUBSTRING(str, pos, len) / MID() | MySQL 位置從 1 起算,支持負數倒數;Oracle 同 | |
NVL(expr1, expr2) | IFNULL(expr1, expr2) / COALESCE() | COALESCE 為標準 SQL,多參數優先用它 | |
| 分頁/限制 | ROWNUM 偽列 | LIMIT offset, count | Oracle 需子查詢包裹 WHERE rn BETWEEN a AND b;MySQL 直觀 |
FETCH FIRST n ROWS ONLY (12c+) | LIMIT n | 標準 SQL 寫法 Oracle 12c+ 支持,MySQL 8.0.21+ 亦支持 | |
| 變量聲明 | DECLARE v INT; v := 1; | SET @v = 1; (用戶變量)DECLARE v INT DEFAULT 1; (存儲過程局部變量,無 @) | MySQL 用戶變量 @var 跨會話可見(同連接),局部變量無 @ 且需在 BEGIN...END 內聲明 |
| 存儲過程 | CREATE PROCEDURE p(p1 IN INT) AS BEGIN ... END; | CREATE PROCEDURE p(IN p1 INT) BEGIN ... END | MySQL 需 DELIMITER // 修改結束符;參數模式 IN/OUT/INOUT 關鍵字前置 |
| 游標 | 隱式屬性 %NOTFOUND | DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=1; | MySQL 無隱式游標屬性,必須用 Handler 捕獲 NOT FOUND 異常 |
| GROUP BY | 嚴格模式:SELECT 列必須出現在 GROUP BY 或聚合函數中 | 默認非嚴格:允許選取未分組列(取組內第一行),ONLY_FULL_GROUP_BY 開啟後一致 | 遷移時建議開啟 ONLY_FULL_GROUP_BY 確保語義正確 |
| 條件表達式 | DECODE(expr, search, result, ...) | CASE WHEN ... THEN ... ELSE ... END | MySQL 不支持 DECODE,統一用標準 CASE |
| 類型轉換 | TO_NUMBER, TO_DATE | CAST(expr AS TYPE), CONVERT(expr, TYPE) | MySQL CAST(... AS SIGNED/UNSIGNED/DECIMAL/DATE/DATETIME/CHAR) |
| 自增/序列 | SEQUENCE / SEQ.NEXTVAL | AUTO_INCREMENT 列 | MySQL 插入後獲取 ID:LAST_INSERT_ID() / JDBC getGeneratedKeys() |
| 唯一標識 | SYS_GUID() (RAW 16字節) | UUID() (VARCHAR 36字節) | MySQL 8.0 UUID_TO_BIN()/BIN_TO_UUID() 可存為 BINARY(16) 節省空間 |
| 空值排序 | ORDER BY col NULLS FIRST/LAST | ORDER BY IS NULL(col), col (模擬) | MySQL 8.0.2+ 支持 NULLS FIRST/LAST 語法 |
| 合併查詢 | MINUS (差集) | EXCEPT (8.0.31+) | 舊版用 LEFT JOIN ... WHERE IS NULL 或 NOT IN/EXISTS 模擬 |
| 雙表更新 | UPDATE (SELECT ... FROM a JOIN b) SET ... | UPDATE a JOIN b ON ... SET a.col = b.col WHERE ... | MySQL 支持多表 UPDATE/JOIN 語法,更直觀 |
-- Oracle
CREATE OR REPLACE PROCEDURE proc_demo (p_id IN NUMBER, p_result OUT VARCHAR2) AS
BEGIN
SELECT name INTO p_result FROM t WHERE id = p_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN p_result := 'NOT_FOUND';
END;
-- MySQL
DELIMITER //
CREATE PROCEDURE proc_demo (IN p_id INT, OUT p_result VARCHAR(100))
BEGIN
DECLARE done INT DEFAULT 0;
DECLARE v_name VARCHAR(100);
DECLARE cur CURSOR FOR SELECT name FROM t WHERE id = p_id;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
OPEN cur;
FETCH cur INTO v_name;
IF done = 1 THEN
SET p_result = 'NOT_FOUND';
ELSE
SET p_result = v_name;
END IF;
CLOSE cur;
END //
DELIMITER ;
核心差異:異常處理 → Handler + 狀態變量、游標必須顯式 OPEN/FETCH/CLOSE、變量聲明區分 @用戶變量 與 無@局部變量。
SET sql_mode='ORACLE'(8.0.31+ 實驗性)可部分兼容 ||、ROWNUM、NVL 等語法,但不建議生產依賴,應徹底改寫。MySQL 與 Oracle 差異本質上源於架構哲學不同:Oracle 重企業級特性、複雜 PL/SQL、共享池;MySQL 重輕量、標準 SQL 合規、存儲引擎插件化。遷移核心策略:Schema 結構對標、業務邏輯下沉應用層、存儲過程重寫為應用代碼、利用中間件(ShardingSphere/Seata)彌補分布式事務能力。本文對照表可作為遷移項目「核對清單」逐項驗收。