上週,我請三個人幫我統計資料庫裡的顧客總數。我的助理工程師得出 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() 實際上做的事情是:
- COUNT(*) - 計算資料表中的每一列(row)
- COUNT(欄位名稱) - 只計算該欄位不是 NULL 的列
- 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: 2(USA 和 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() 地雷嗎?歡迎在底下留言,我會一一回覆。















