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

SQL GROUP BY 與聚合函數直觀理解:虛擬分組表思維模型,徹底搞懂為什麼不能 SELECT *

     編輯:Java 綜合教學

SQL GROUP BY 與聚合函數直觀理解:虛擬分組表思維模型,徹底搞懂為什麼不能 SELECT *

很多開發者知道 GROUP BY 後只能選分組列或聚合函數,但不清楚本質原因。本文引入「虛擬分組表」思維模型,將分組過程可視化,一次性講透分組邏輯、多字段分組、聚合函數角色與常見報錯根因。

原始數據表(test)

idnamenumber
1aa2
2aa3
3bb5
4cc7

執行 SELECT name FROM test GROUP BY name 的三階段模型

階段 1:FROM test

得到原始表,無變化。

階段 2:GROUP BY name → 生成「虛擬分組表」

將 name 相同的行合併為一行,非分組列的值收集為集合放入同一單元格:

name (分組鍵)id (集合)number (集合)
aa{1, 2}{2, 3}
bb{3}{5}
cc{4}{7}

關鍵洞察:關系數據庫要求單元格原子性(單值),虛擬表中 id、number 單元格包含多值,不符合關系模型,故不能直接 SELECT *。

階段 3:SELECT 列投影

  • SELECT name:分組鍵列,每格單值 → 合法。
  • SELECT id / SELECT number:非分組鍵,多值 → 非法(報錯:not a GROUP BY expression)。
  • SELECT name, SUM(number):聚合函數輸入多值集合,輸出單值 → 合法。
    • SUM({2,3}) = 5,結果表:
nameSUM(number)
aa5
bb5
cc7

多字段分組:將多列視為「整體分組鍵」

GROUP BY name, number 等價於按 (name, number) 元組分組:

(name, number)id (集合)
(aa, 2){1}
(aa, 3){2}
(bb, 5){3}
(cc, 7){4}

此時 name 和 number 單元格均為單值(因為它們是分組鍵的一部分),可直接 SELECT;id 仍需聚合。

示例:SELECT name, SUM(id) FROM test GROUP BY name, number

nameSUM(id)
aa1
aa2
bb3
cc4

聚合函數本質:多值 → 單值的歸約運算

常見報錯場景與修正

函數輸入輸出別名
COUNT集合大小整數行數
SUM數值集合總和求和
AVG數值集合平均值平均
MAX/MIN可比較集合極值極值
GROUP_CONCAT字符串集合拼接字符串列轉行

最佳實踐清單

  1. SELECT 列表 = GROUP BY 列 + 聚合函數,嚴格遵守,避免 MySQL ONLY_FULL_GROUP_BY 模式報錯。
  2. 多字段分組時,視為組合鍵,SELECT 列表可包含組合鍵中任意子集。
  3. 需求「保留非分組列原始值」:用窗口函數 ROW_NUMBER() OVER (PARTITION BY a ORDER BY b) 或子查詢,不要濫用 ANY_VALUE()(MySQL 非標準)。
  4. 性能優化:分組列有索引可避免臨時表排序;大數據集考慮預聚合物化視圖。

總結

GROUP BY 本質是將原始行按鍵合併,非鍵列變為多值集合。聚合函數是將多值集合歸約為單值的橋樑,使結果符合關系模型的原子性約束。 虛擬分組表模型能幫你在寫 SQL 前腦補分組後的結構,直接判斷 SELECT 列表是否合法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
錯誤 SQL報錯原因修正方案
SELECT * FROM t GROUP BY a非分組列多值列出分組列 + 聚合函數
SELECT a, b FROM t GROUP BY ab 非分組列非聚合SELECT a, MAX(b) 或 GROUP BY a, b
SELECT a, COUNT(*) FROM t GROUP BY a, b語法合法,但語義可能不符預期確認是否需 GROUP BY a