別再數錯了:每個 SQL 初學者都該懂的三種 COUNT() 函數

更新 發佈閱讀 15 分鐘

上週,我請三個人幫我統計資料庫裡的顧客總數。我的助理工程師得出 1,247 這個數字。我同事算出 1,089。我主管則說是 47。

他們都用了 SQL 的 COUNT() 函數。都是查詢同一張資料表。結果三個數字竟然都是對的。

如果你覺得很困惑,別擔心,你不是唯一一個。COUNT() 函數是 SQL 初學者最早接觸到的功能之一,卻也是最容易被誤解的。問題在哪?其實 COUNT() 有三種不同的用法,而用錯了也不會報錯,只會默默給你錯誤的數據。

讀完這篇文章,你就能清楚知道在每種情況下該用哪種 COUNT(),以及為什麼用錯會讓你的數據分析完全不可靠。這是連有經驗的開發者在初學時也常踩的坑。

讓我們一起解決這個問題吧。


問題所在:為什麼 COUNT() 讓每個人都困惑

這是最常讓 SQL 初學者卡關的情境:

你的主管問:「我們有多少位顧客?」

你寫:SELECT COUNT(email) FROM customers;

你同事寫:SELECT COUNT(*) FROM customers;

你主管寫:SELECT COUNT(DISTINCT country) FROM customers;

大家都按下執行。結果出來三個不同的數字。誰是對的?

真相是:三個人都對——你們只是在數不同的東西。

每種 COUNT() 實際上做的事情是:

  1. COUNT(*) - 計算資料表中的每一列(row)
  2. COUNT(欄位名稱) - 只計算該欄位不是 NULL 的列
  3. COUNT(DISTINCT 欄位名稱) - 只計算不重複且不是 NULL 的值

最危險的是:用錯任何一種都不會報錯。你只會得到錯誤的數據,做出錯誤的決策,而且永遠不知道為什麼數字對不上。

讓我們逐一拆解,從此不再數錯。


第一種:COUNT(*) —— 「全部都數」函數

它做什麼

COUNT(*) 會計算資料表或查詢結果中的所有列,包括含有 NULL 值的列。這是最直接的計數方式——就是告訴我有多少列資料。

什麼時候用

當你需要單純的列數統計時使用 COUNT(*)

  • 「我們有多少位顧客?」
  • 「今天下了多少筆訂單?」
  • 「總共有幾筆記錄?」

實際範例

SELECT COUNT(*) AS total_customers
FROM customers;

-- 結果:1,247(每一列都算)

關鍵行為

這是 COUNT(*) 的特殊之處:它不在乎 NULL 值。即使某一列的每個欄位都是 NULL,它還是會計算這一列。

用範例資料來說明:

id | name  | email
1  | John  | [john@email.com](mailto:john@email.com)
2  | Sarah | NULL
3  | Mike  | [mike@email.com](mailto:mike@email.com)
SELECT COUNT(*) FROM customers;

-- 結果:3(包含 Sarah,即使她的 email 是 NULL

Sarah 的列依然被計算,因為這一列本身存在,不管 email 欄位有沒有填。

常見使用情境

  • 儀表板指標:「本月總訂單數」
  • 資料驗證:「從 CSV 匯入了幾筆資料?」
  • 基準計數:在篩選前先取得總數

小訣竅:COUNT(*) 通常是最快的選項,因為資料庫可以優化它而不用檢查個別欄位的值。它只是單純計算列數。


第二種:COUNT(欄位名稱) —— 「非空值計數器」

這裡開始變得有趣了——也是大多數初學者會犯錯的地方。

它做什麼

COUNT(欄位名稱) 只計算該欄位不是 NULL 的值。如果某個欄位是 NULL,那一列就會被完全忽略。

什麼時候用

當你要衡量資料完整度時使用 COUNT(欄位名稱)

  • 「有多少位顧客提供了 email?」
  • 「有多少商品有描述?」
  • 「有多少筆訂單有追蹤號碼?」

實際範例

SELECT COUNT(email) AS customers_with_email
FROM customers;

-- 結果:1,089(只有 email IS NOT NULL 的列)

為什麼這很重要

這是初學者最容易卡住的地方。用 COUNT(欄位) 而不是 COUNT(*) 會得到完全不同的數字——兩者都沒有「錯」,只是在回答不同的問題。

用剛才的範例資料:

id | name  | email
1  | John  | [john@email.com](mailto:john@email.com)
2  | Sarah | NULL
3  | Mike  | [mike@email.com](mailto:mike@email.com)
SELECT 
    COUNT(*) AS total_customers,
    COUNT(email) AS customers_with_email
FROM customers;

-- 結果:
-- total_customers: 3
-- customers_with_email: 2

看出差異了嗎?Sarah 的列存在(所以 COUNT(*) 包含她),但她的 email 是 NULL(所以 COUNT(email) 排除她)。

衡量資料完整度

這對資料品質檢查非常有用:

SELECT 
    COUNT(*) AS total_products,
    COUNT(description) AS products_with_description,
    COUNT(*) - COUNT(description) AS products_missing_description
FROM products;

這個查詢能一次告訴你資料的完整程度。

常見錯誤

初學者常這樣計算 NULL 值:

錯誤:

SELECT COUNT(email) FROM customers WHERE email = NULL;

-- 結果:0(因為 NULL = NULL 永遠是 false!)

正確:

SELECT COUNT(*) FROM customers WHERE email IS NULL;

更好的做法——用差值法:

SELECT 
    COUNT(*) AS total,
    COUNT(email) AS with_email,
    COUNT(*) - COUNT(email) AS without_email
FROM customers;

這種方法更簡潔,一次就能看到完整的資訊。


第三種:COUNT(DISTINCT 欄位名稱) —— 「不重複值計數器」

現在要介紹真正強大的功能了。

它做什麼

COUNT(DISTINCT 欄位名稱) 只計算該欄位中不重複且不是 NULL 的值。如果同一個值出現 100 次,只算一次。NULL 值會被忽略。

什麼時候用

當你想計算不重複的類別或數值時使用 COUNT(DISTINCT)

  • 「我們的顧客來自幾個不同的國家?」
  • 「這個月賣出了幾種不同的商品?」
  • 「我們合作幾家不同的供應商?」

實際範例

SELECT COUNT(DISTINCT country) AS countries_served
FROM customers;

-- 結果:47(只有不重複的國家)

DISTINCT 的威力

這是 SQL 在分析上真正強大的地方。用範例資料來說明:

customer_id | country
1           | USA
2           | USA
3           | Canada
4           | USA
5           | Canada
6           | NULL
SELECT 
    COUNT(*) AS total_customers,
    COUNT(country) AS customers_with_country,
    COUNT(DISTINCT country) AS unique_countries
FROM customers;

-- 結果:
-- total_customers: 6
-- customers_with_country: 5(排除 NULL
-- unique_countries: 2USA 和 Canada 各算一次)

同一個欄位,三個完全不同的數字。

實際應用情境

活躍顧客分析:

SELECT COUNT(DISTINCT customer_id) AS active_customers
FROM orders
WHERE order_date >= '2025-10-01';

這會告訴你本月有幾位不同的顧客下訂——而不是下了幾筆訂單(可能包含回購顧客)。

商品多樣性:

SELECT COUNT(DISTINCT product_id) AS unique_products_sold
FROM order_items;

這告訴你銷售的廣度,而不是銷量。

參與度指標:

SELECT COUNT(DISTINCT user_id) AS daily_active_users
FROM login_logs
WHERE login_date = CURRENT_DATE;

這是追蹤每日不重複活躍用戶的經典指標。

什麼時候不該用

COUNT(DISTINCT) 比一般的 COUNT() 慢,因為資料庫必須先識別並移除重複值。只在真正需要不重複計數時才用。別為了保險就預設用 DISTINCT——要有目的性。


並排比較:三種全部用上

讓我們用一個實際情境把所有東西串起來。

情境說明

你有一張訂單資料表,主管問了三個問題:

資料:

  • 總共 10,000 筆訂單記錄
  • 8,500 筆訂單有追蹤號碼(1,500 筆是 NULL,因為還在處理中)
  • 2,300 位不重複的顧客下了這些訂單

查詢:

SELECT 
    COUNT(*) AS total_orders,
    COUNT(tracking_number) AS orders_with_tracking,
    COUNT(DISTINCT customer_id) AS unique_customers
FROM orders;

-- 結果:
-- total_orders: 10,000
-- orders_with_tracking: 8,500
-- unique_customers: 2,300

各自告訴你什麼:

  • COUNT(*) → 有幾筆訂單記錄存在
  • COUNT(tracking_number) → 有幾筆訂單已出貨(有追蹤號碼)
  • COUNT(DISTINCT customer_id) → 有幾位不同的顧客下訂

三個答案都很有價值——但回答的是完全不同的商業問題。


常見錯誤與避免方法

錯誤 #1:該用 COUNT(*) 時卻用了 COUNT(欄位)

錯誤假設:「它們基本上是一樣的。」

現實:如果那個欄位有任何 NULL 值,你的計數就會是錯的。

解決方法:想要總列數時用 COUNT(*),不管有沒有 NULL。

錯誤 #2:忘記 NULL 值的存在

錯誤思維:

SELECT COUNT(email) FROM customers;

-- 「這會算出所有顧客吧?」

現實:這只會算有提供 email 的顧客。如果 20% 的顧客沒填 email,你就少算了 20%。

解決方法:永遠問自己:「我在乎 NULL 值嗎?」如果不在乎,用 COUNT(*)

錯誤 #3:不該用 DISTINCT 時卻沒用

如果你想要不重複的值卻忘了 DISTINCT,就會嚴重高估。

-- 錯誤:算的是每筆訂單(包含重複顧客)

SELECT COUNT(customer_id) FROM orders;

-- 結果:10,000 筆訂單
-- 正確:算的是不重複顧客

SELECT COUNT(DISTINCT customer_id) FROM orders;

-- 結果:2,300 位不重複顧客


快速決策樹:我該用哪種 COUNT?

從這裡開始:我想數什麼?

所有列?COUNT(*)

只有該欄位有值(不是 NULL)的列?COUNT(欄位名稱)

只有該欄位的不重複值?COUNT(DISTINCT 欄位名稱)

還是不確定?問自己:

  • 「我在乎這個欄位是不是 NULL 嗎?」→ 如果不在乎,用 COUNT(*)
  • 「我在乎重複值嗎?」→ 如果不在乎,用 COUNT(欄位);如果在乎,用 COUNT(DISTINCT 欄位)


結語

三種 COUNT() 不能互換——它們回答的是根本不同的問題。

COUNT(*) 數全部。

COUNT(欄位) 數完整度。

COUNT(DISTINCT 欄位) 數不重複性。

最重要的一點:在寫 COUNT 查詢之前,先問自己:「我到底想數什麼?」答案會決定你該用哪種 COUNT()。

親自試試看

現在就打開你的資料庫,在任何資料表上執行這個查詢:

SELECT 
    COUNT(*) AS all_rows,
    COUNT(some_column) AS non_null_values,
    COUNT(DISTINCT some_column) AS unique_values
FROM your_table;

觀察三個數字的差異。那就是你真正理解的時刻。

下次有人問你「我們有多少位顧客?」——你會知道要反問:「你是指總顧客數、有 email 的顧客,還是不重複的顧客區隔?」然後你就會知道該用哪種 COUNT()。

對 SQL 有疑問,或想分享你自己踩過的 COUNT() 地雷嗎?歡迎在底下留言,我會一一回覆。


留言
avatar-img
留言分享你的想法!
avatar-img
Leon Wong 282
3會員
17內容數
Hi,我是 Leon Wong(亮之)——電腦科學與開發愛好者,也是 Notion 重度使用者。如果你想更高效地學習與創作,這裡會是你的實用資源。
Leon Wong 282的其他內容
2025/10/25
剛裝好 VS Code 卻不知道怎麼設定?這 7 個內建設定只要 5 分鐘,就能讓你避免程式碼遺失、排版混亂、眼睛疲勞等新手常見問題。不需要任何擴充套件,立即提升寫程式體驗。
Thumbnail
2025/10/25
剛裝好 VS Code 卻不知道怎麼設定?這 7 個內建設定只要 5 分鐘,就能讓你避免程式碼遺失、排版混亂、眼睛疲勞等新手常見問題。不需要任何擴充套件,立即提升寫程式體驗。
Thumbnail
2025/10/24
手動下載軟體浪費時間又有資安風險。這篇文章教你用 10 分鐘設定 Homebrew 套件管理工具,從此一行指令就能安裝、更新所有 Mac 軟體。適合完全新手,只需要會複製貼上。
Thumbnail
2025/10/24
手動下載軟體浪費時間又有資安風險。這篇文章教你用 10 分鐘設定 Homebrew 套件管理工具,從此一行指令就能安裝、更新所有 Mac 軟體。適合完全新手,只需要會複製貼上。
Thumbnail
2025/10/23
學習如何在 15 分鐘內設定免費的 Cloudflare R2 圖片託管。10GB 儲存、無限流量、全球 CDN。不需要寫程式,完整步驟教學。
Thumbnail
2025/10/23
學習如何在 15 分鐘內設定免費的 Cloudflare R2 圖片託管。10GB 儲存、無限流量、全球 CDN。不需要寫程式,完整步驟教學。
Thumbnail
看更多
你可能也想看
Thumbnail
※ 何時該使用 JOIN? JOIN 使用的時機是:當你需要同時查詢一張以上的資料表的時候。 ※ SQL有哪些TABLE JOIN的方式? INNER JOIN LEFT JOIN RIGHT JOIN SELF JOIN ※ 使用 JOIN 的時候,我們需要考慮到: 我要使用哪一種
Thumbnail
※ 何時該使用 JOIN? JOIN 使用的時機是:當你需要同時查詢一張以上的資料表的時候。 ※ SQL有哪些TABLE JOIN的方式? INNER JOIN LEFT JOIN RIGHT JOIN SELF JOIN ※ 使用 JOIN 的時候,我們需要考慮到: 我要使用哪一種
Thumbnail
※ 關聯式資料庫(RDBMS)是什麼? 關聯式資料庫(RDBMS)是一種傳統的資料庫系統,以結構化查詢語言(SQL)為基礎,將資料儲存於預定義的表格中。這些表格包括行和列,彼此之間存在明確的關聯性。 ※ 關聯式資料庫(RDBMS)有兩個重要元素: 關聯(Relational): 關聯式資料庫
Thumbnail
※ 關聯式資料庫(RDBMS)是什麼? 關聯式資料庫(RDBMS)是一種傳統的資料庫系統,以結構化查詢語言(SQL)為基礎,將資料儲存於預定義的表格中。這些表格包括行和列,彼此之間存在明確的關聯性。 ※ 關聯式資料庫(RDBMS)有兩個重要元素: 關聯(Relational): 關聯式資料庫
Thumbnail
題目敘述 題目會給我們一張Views資料表。裡面分別有article_id、author_id、viewer_id、view_date等欄位。題目說這張資料表沒有主鍵Primary key,而且可能有重複欄位。 題目要求我們列出所有讀過自己寫的文章的作者ID 輸出答案時,請以作者ID做升序排列
Thumbnail
題目敘述 題目會給我們一張Views資料表。裡面分別有article_id、author_id、viewer_id、view_date等欄位。題目說這張資料表沒有主鍵Primary key,而且可能有重複欄位。 題目要求我們列出所有讀過自己寫的文章的作者ID 輸出答案時,請以作者ID做升序排列
Thumbnail
聚合函數 可以對資料的筆數、平均、最大、最小和加總的運算,提供查詢結果:如下表示: COUNT(Column):計算筆數,「*」是統計紀錄數。 AVG(Column):計算欄位平均值。 MAX(Column):計算欄位最大值。 MIN(Column):計算欄位最小值。 SUM(Colum
Thumbnail
聚合函數 可以對資料的筆數、平均、最大、最小和加總的運算,提供查詢結果:如下表示: COUNT(Column):計算筆數,「*」是統計紀錄數。 AVG(Column):計算欄位平均值。 MAX(Column):計算欄位最大值。 MIN(Column):計算欄位最小值。 SUM(Colum
Thumbnail
查詢範圍 指定欄位 SELECT column1, column2, column3,... FROM your_table_name 不重複欄位 SELECT DISTINCT column1 FROM your_table_name 欄位別名 SELECT column1 A
Thumbnail
查詢範圍 指定欄位 SELECT column1, column2, column3,... FROM your_table_name 不重複欄位 SELECT DISTINCT column1 FROM your_table_name 欄位別名 SELECT column1 A
Thumbnail
聚合函數 aggregate function
Thumbnail
聚合函數 aggregate function
Thumbnail
在資料庫管理中,SQL(Structured Query Language)是一種強大的工具,用於處理資料庫中的資料。本篇教學將介紹 SQL 中的基本操作,包括 SELECT、UPDATE、INSERT 和 DELETE,讓您能夠有效地查詢、更新、插入和刪除資料。
Thumbnail
在資料庫管理中,SQL(Structured Query Language)是一種強大的工具,用於處理資料庫中的資料。本篇教學將介紹 SQL 中的基本操作,包括 SELECT、UPDATE、INSERT 和 DELETE,讓您能夠有效地查詢、更新、插入和刪除資料。
Thumbnail
在準備轉職期間,為了能更接近數據分析的領域,首先決定要進修的領域是程式語言,首先從門檻相對不高的SQL(Structured Query Language,結構化查詢語言)開始。在此分享目前為止學到的一些小小心得。
Thumbnail
在準備轉職期間,為了能更接近數據分析的領域,首先決定要進修的領域是程式語言,首先從門檻相對不高的SQL(Structured Query Language,結構化查詢語言)開始。在此分享目前為止學到的一些小小心得。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News