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

MySQL 與 Oracle GROUP BY 差異深度解析:非聚合欄位的隨機性陷阱

     編輯:MySQL 綜合教學

核心差異

資料庫GROUP BY 規則
Oracle嚴格模式:SELECT 列表中未出現在 GROUP BY 的欄位,必須套用聚合函數(MAX、MIN、COUNT 等),否則報錯 ORA-00979。
MySQL (預設 sql_mode)寬鬆模式:允許 SELECT 非聚合欄位,隨機返回該分組內任意一行的值(通常是物理存儲順序的第一行)。

實測案例

假設表 actor 與 actor_info 通過 actor_id 關聯,按 first_name 分組。

查詢 1:未聚合的 actor_id

SELECT actor.actor_id, actor.first_name
FROM actor
JOIN actor_info ON actor.actor_id = actor_info.actor_id
GROUP BY actor.first_name;

結果:

+----------+-------------+
| actor_id | first_name  |
+----------+-------------+
| 71       | ADAM        |
| 165      | AL          |
| 173      | ALAN        |
| ...      | ...         |

同一 first_name 下有多個 actor_id 時,MySQL 直接取分組內第一條記錄的 actor_id,結果不可預期、不可複現。

查詢 2:正確聚合寫法

SELECT actor.first_name, COUNT(actor.actor_id)
FROM actor
JOIN actor_info ON actor.actor_id = actor_info.actor_id
GROUP BY actor.first_name;

結果明確:每個名字對應的演員數量。

為什麼 MySQL 允許這種寫法?

早期版本為了兼容舊應用、提升寫法靈活性而設計。但這極易導致「開發環境正常、生產環境數據錯亂」的隱性 Bug。

最佳實踐:強制嚴格模式

-- 會話級生效
SET SESSION sql_mode = 'ONLY_FULL_GROUP_BY';
-- 或全域永久生效(my.cnf)
[mysqld]
sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'

開啟後,查詢 1 將直接報錯:ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause...,強迫開發者寫出標準、可移植的 SQL。

總結

  • MySQL 預設允許非聚合欄位進 SELECT,**返回值為分組內任意行(通常是第一行),業務含義模糊**。
  • Oracle 強制聚合,**結果確定、符合關係代數語義**。
  • 生產環境務必開啟 ONLY_FULL_GROUP_BY,避免跨資料庫遷移或版本升級時出現語義偏差。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved