別再數錯了:每個 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
Leon Wong 282
4會員
23內容數
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
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
在 vocus 與你一起探索內容、發掘靈感的路上,我們又將啟動新的冒險——vocus App 正式推出! 現在起,你可以在 iOS App Store 下載全新上架的 vocus App。 無論是在通勤路上、日常空檔,或一天結束後的放鬆時刻,都能自在沈浸在內容宇宙中。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
Thumbnail
vocus 慶祝推出 App,舉辦 2026 全站慶。推出精選內容與數位商品折扣,訂單免費與紅包抽獎、新註冊會員專屬活動、Boba Boost 贊助抽紅包,以及全站徵文,並邀請你一起來回顧過去的一年, vocus 與創作者共同留下了哪些精彩創作。
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,結構化查詢語言)開始。在此分享目前為止學到的一些小小心得。
Thumbnail
你知道 SELECT 除了回傳欄位、使用聚集函數外,還可以更進一步做加減乘除喔!這個系列是 QUERY 函式大解析的第六篇文章,如果還不知道什麼是 QUERY 的話,我還是很建議你從第一篇慢慢看、跟著我們的練習實際操作,就會更有概念囉~
Thumbnail
你知道 SELECT 除了回傳欄位、使用聚集函數外,還可以更進一步做加減乘除喔!這個系列是 QUERY 函式大解析的第六篇文章,如果還不知道什麼是 QUERY 的話,我還是很建議你從第一篇慢慢看、跟著我們的練習實際操作,就會更有概念囉~
Thumbnail
今天要介紹的是進階的 SELECT 功能,可以即時對 QUERY 的結果運算,迅速取得數值的平均、總和、最大值、最小值和數量,省去拉資料透視表(pivot table)的麻煩!
Thumbnail
今天要介紹的是進階的 SELECT 功能,可以即時對 QUERY 的結果運算,迅速取得數值的平均、總和、最大值、最小值和數量,省去拉資料透視表(pivot table)的麻煩!
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News