[Copy and Paste Ready] Mastering SQL COUNT Function â From Basics to Advanced
When developing websites or applications, youâll often find yourself needing to know things like âWhat is the total number of users?â or âHow many different products are in a specific category?â In such cases, the SQL COUNT() function becomes extremely useful.
COUNT() is an aggregate function used to count the number of records (rows) in a table. At first glance, it may seem simple, but depending on how it's used, it can extract various kinds of informationâmaking it a surprisingly powerful function. In this article, weâll walk through everything from basic usage to practical applications, along with plenty of âcopy-and-paste readyâ code for beginners aspiring to become web creators.
The goal of this article is to help you experience the excitement of âSQL actually works when you write it!â Forget the complicated theory for now! First, copy the code, run it, and see the results for yourself to discover how fun SQL can be.
Letâs Warm Up! Prepare Sample Data
To try out SQL, you need a table with some data. For this tutorial, letâs create a users table that simulates a simple âuser list.â The SQL below will create the table and insert some sample data.
All the code introduced in this article will work with this users table.
-- Delete the table if it exists (so you can try multiple times)
DROP TABLE IF EXISTS users;
-- Create users table
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
prefecture TEXT NOT NULL,
email TEXT
);
-- Insert data
INSERT INTO users (id, name, prefecture, email) VALUES
(1, 'Taro Yamada', 'Tokyo', 'yamada@example.com'),
(2, 'Hanako Suzuki', 'Osaka', 'suzuki@example.com'),
(3, 'Jiro Sato', 'Tokyo', NULL),
(4, 'Sakura Ito', 'Fukuoka', 'ito@example.com'),
(5, 'Saburo Watanabe', 'Hokkaido', 'watanabe@example.com'),
(6, 'Shiro Takahashi', 'Tokyo', 'takahashi@example.com'),
(7, 'Misaki Tanaka', 'Osaka', NULL);
This table includes columns for ID, name, prefecture, and email. Note that the email fields for Sato (ID 3) and Tanaka (ID 7) are set to NULL (i.e., blank). This will be important later when we discuss how the COUNT() function behaves.
[Basic 1] Count All Records with `COUNT(*)`
Letâs start with the most basic usage: COUNT(*). The asterisk (*) means âall columns,â and COUNT(*) returns the total number of records in the table. Use this when you simply want to ask, âHow many entries are in this table?â
Letâs count all users in the users table.
SELECT COUNT(*) FROM users;
Result:
7
Since we inserted data for 7 users earlier, the result is correctly returned as â7.â This is the foundation of using COUNT().
[Basic 2] Count Specific Columns with `COUNT(column_name)`
Next, letâs look at COUNT(column_name), which counts the number of records that have a value in the specified column.
This is important: COUNT(column_name) ignores NULL values. In other words, it does not count records where the column is empty.
Letâs count how many users in the users table have registered an email address.
SELECT COUNT(email) FROM users;
Result:
5
The result is â5.â Thatâs fewer than the 7 from COUNT(*), because the 2 users (Sato and Tanaka) who have NULL in the email column are excluded.
So remember: COUNT(*) gives the total number of rows, while COUNT(column_name) counts only the rows where that column has data.
[Advanced 1] Rename the Result Column with `AS`
By default, the result of COUNT() appears as something like COUNT(*) or COUNT(email), which isnât very readable. This can be inconvenient when handling the result later.
In such cases, use AS to assign a more readable alias (name) to the result column.
SELECT COUNT(*) AS total_users FROM users;
Result:
total_users
-----------
7
By adding AS total_users, the result column is renamed to total_users. This makes it instantly clear that this value represents the total number of users. It also makes it easier to access the result in code, such as result['total_users'].
[Advanced 2] Count Unique Values with `COUNT(DISTINCT column_name)`
Next up is COUNT(DISTINCT), which is widely used in web analytics. The DISTINCT keyword means âremove duplicates,â allowing you to count the number of unique values.
For example, you might want to know âHow many different prefectures are our users from?â
In the users table, 3 users are from Tokyo and 2 from Osaka. Letâs count how many unique prefectures there are.
SELECT COUNT(DISTINCT prefecture) AS unique_prefectures FROM users;
Result:
unique_prefectures
------------------
4
The result is â4.â The prefectures listed in the users table are Tokyo, Osaka, Fukuoka, and Hokkaidoâfour unique values.
This is useful in countless situations, like counting product categories in an e-commerce site or calculating unique visitors from access logs.
[Advanced 3] Count by Group with `GROUP BY`
COUNT() truly shines when used with the GROUP BY clause. This groups rows with the same value in a specified column and applies COUNT() to each group.
Want to know the number of users from each prefecture? This is exactly where GROUP BY comes in.
SELECT
prefecture,
COUNT(*) AS user_count
FROM
users
GROUP BY
prefecture;
Result:
prefecture | user_count
-----------|------------
Osaka | 2
Hokkaido | 1
Tokyo | 3
Fukuoka | 1
Perfect! We got a list of user counts by prefecture. The prefecture column is used to create groups, and COUNT(*) counts the number of rows in each group.
This is an essential technique for website analysis, such as figuring out which regions have the most users.
[Pro Tip] Filter Aggregated Results with `HAVING`
Sometimes you may want to filter results after aggregation with GROUP BY. For example, you might want to display only prefectures with two or more users.
Be careful: the WHERE clause filters individual records before aggregation, so you canât use it to filter aggregated results like user_count.
To filter after aggregation, use the HAVING clause.
SELECT
prefecture,
COUNT(*) AS user_count
FROM
users
GROUP BY
prefecture
HAVING
user_count >= 2;
Result:
prefecture | user_count
-----------|------------
Osaka | 2
Tokyo | 3
By adding HAVING user_count >= 2, only prefectures with two or more usersâOsaka and Tokyoâare returned.
Remember: WHERE is for filtering individual records before aggregation, and HAVING is for filtering after GROUP BY.
[Interactive Corner] Try Running SQL in Your Browser!
Thank you for waiting! Here, we've prepared an environment where you can actually run the SQL you've learned so far with your own hands.
Copy the entire HTML code below, save it as a file named sql_test.html (or similar), and open it in your browser. The users table introduced in this article is already prepared, so try various SQL statements and enjoy seeing how the results change!
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SQL execution environment for COUNT()</title>
<style>
body { font-family: sans-serif; line-height: 1.6; color: #333; max-width: 800px; margin: 2rem auto; padding: 0 1rem; }
h1 { color: #444; }
textarea { width: 100%; height: 150px; font-family: monospace; font-size: 16px; padding: 10px; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; margin-bottom: 1rem; }
button { background-color: #007bff; color: white; border: none; padding: 10px 20px; font-size: 16px; border-radius: 4px; cursor: pointer; }
button:hover { background-color: #0056b3; }
button:disabled { background-color: #ccc; cursor: not-allowed; }
#result-container { margin-top: 2rem; border: 1px solid #ddd; padding: 1rem; border-radius: 4px; background: #f9f9f9; min-height: 50px; }
#error-message { color: #d9534f; font-weight: bold; }
table { border-collapse: collapse; width: 100%; margin-top: 1rem; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/sql-wasm.js"></script>
</head>
<body>
<h1>Try SQL!</h1>
<p>Enter SQL in the text area below and click the "Run" button. Try out various SQL examples introduced in this article!</p>
<textarea id="sql-input">SELECT prefecture, COUNT(*) AS user_count
FROM users
GROUP BY prefecture
HAVING user_count >= 2;</textarea>
<button id="execute-btn">Run</button>
<div id="result-container">
<p id="error-message"></p>
<div id="result-output"></div>
</div>
<script>
const sqlInput = document.getElementById('sql-input');
const executeBtn = document.getElementById('execute-btn');
const errorMsg = document.getElementById('error-message');
const resultOutput = document.getElementById('result-output');
let db;
async function initDb() {
executeBtn.disabled = true;
executeBtn.textContent = 'Initializing...';
try {
const SQL = await initSqlJs({
locateFile: file => `https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.3/${file}`
});
db = new SQL.Database();
// Setup initial table and data
const setupSql = `
DROP TABLE IF EXISTS users;
CREATE TABLE users (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
prefecture TEXT NOT NULL,
email TEXT
);
INSERT INTO users (id, name, prefecture, email) VALUES
(1, 'Taro Yamada', 'Tokyo', 'yamada@example.com'),
(2, 'Hanako Suzuki', 'Osaka', 'suzuki@example.com'),
(3, 'Jiro Sato', 'Tokyo', NULL),
(4, 'Sakura Ito', 'Fukuoka', 'ito@example.com'),
(5, 'Saburo Watanabe', 'Hokkaido', 'watanabe@example.com'),
(6, 'Shiro Takahashi', 'Tokyo', 'takahashi@example.com'),
(7, 'Misaki Tanaka', 'Osaka', NULL);
`;
db.run(setupSql);
executeBtn.disabled = false;
executeBtn.textContent = 'Run';
resultOutput.innerHTML = '<p>Ready! Enter your SQL and click Run.</p>';
} catch (err) {
errorMsg.textContent = 'Failed to initialize database: ' + err.message;
console.error(err);
}
}
function executeSql() {
if (!db) return;
const sql = sqlInput.value;
errorMsg.textContent = '';
resultOutput.innerHTML = '';
try {
const results = db.exec(sql);
if (results.length === 0) {
resultOutput.innerHTML = '<p>The query succeeded but returned no result set (e.g., INSERT, UPDATE etc.)</p>';
return;
}
results.forEach(result => {
const table = document.createElement('table');
const thead = document.createElement('thead');
const tbody = document.createElement('tbody');
const headerRow = document.createElement('tr');
result.columns.forEach(colName => {
const th = document.createElement('th');
th.textContent = colName;
headerRow.appendChild(th);
});
thead.appendChild(headerRow);
result.values.forEach(row => {
const bodyRow = document.createElement('tr');
row.forEach(cellValue => {
const td = document.createElement('td');
td.textContent = cellValue === null ? 'NULL' : cellValue;
bodyRow.appendChild(td);
});
tbody.appendChild(bodyRow);
});
table.appendChild(thead);
table.appendChild(tbody);
resultOutput.appendChild(table);
});
} catch (err) {
errorMsg.textContent = 'SQL Error: ' + err.message;
console.error(err);
}
}
executeBtn.addEventListener('click', executeSql);
initDb();
</script>
</body>
</html>
[Give It a Try!]
- Try counting the number of users who do not have an email registered. (Hint: the difference between
COUNT(*)andCOUNT(email)) - Try counting only the users whose prefecture is âTokyo.â (Hint: use a
WHEREclause) - Execute a new
INSERTstatement yourself to add data, then confirm whether the count increases usingCOUNT(*).
Things to Watch Out For & Trivia
COUNT(*)vsCOUNT(1)vsCOUNT(column_name)-
You may see the syntax
COUNT(1). This means assigning the constant â1â to each row and counting it. In most databases, thereâs no difference in behavior or performance betweenCOUNT(*)andCOUNT(1); both count all rows. On the other hand,COUNT(column_name)does not countNULLvalues, as explained earlier, so the purpose is different. When in doubt, useCOUNT(*)when you want to count all rows, orCOUNT(column_name)when you want to count only non-NULLs. - Performance
-
Running
COUNT(*)on a huge table with millions or tens of millions of rows can take considerable time, especially when youâre counting all rows without any condition, as the entire table needs to be scanned. If you frequently need the total count, consider alternatives like summary tablesâbut for now, knowing the basic usage is sufficient.
Related Functions: Other Aggregates
Once youâve learned COUNT(), it becomes easy to pick up other aggregate functions. These become even more powerful when used with GROUP BY.
SUM(column_name): Calculates the total of a numeric column. (e.g., total sales)AVG(column_name): Calculates the average of a numeric column. (e.g., average age, average price)MAX(column_name): Retrieves the maximum value in a column. (e.g., highest temperature, highest score)MIN(column_name): Retrieves the minimum value in a column. (e.g., lowest price)
For example, to find the highest user ID, use the following:
SELECT MAX(id) AS latest_user_id FROM users;
Conclusion
In this article, we've covered the COUNT() function for counting recordsâfrom basic usage to advanced techniquesâin a brisk overview.
COUNT(*): Counts all records in the table.COUNT(column_name): Counts the records in which the specified column is notNULL.COUNT(DISTINCT column_name): Counts the unique data values, excluding duplicates.AS alias: Gives a clear alias to the result column.GROUP BY: Use withCOUNT()to aggregate by groups.
COUNT() is a fundamental step in data analysis. Try running the code in this article several times to get a feel for âcounting data.â Once you're comfortable with SQL, your ability to analyze and interpret data will expand dramatically. Keep learning, and enjoy the journey!