308

I have an SQL SELECT query that also uses a GROUP BY, I want to count all the records after the GROUP BY clause filtered the resultset.

Is there any way to do this directly with SQL? For example, if I have the table users and want to select the different towns and the total number of users:

SELECT `town`, COUNT(*)
FROM `user`
GROUP BY  `town`;

I want to have a column with all the towns and another with the number of users in all rows.

An example of the result for having 3 towns and 58 users in total is:

Town Count
Copenhagen 58
New York 58
Athens 58
6
  • you mean you want your result set to have 2 counts one for towns and one for users? Commented Apr 27, 2010 at 16:37
  • 2
    So you want one row for each town, and in each row, column 2 contains the total count of all users? So column 2 has the same value for each row? If you edit to include sample data and required output we will be able to give you exactly what you want. Commented Apr 28, 2010 at 7:33
  • 2
    Related question: stackoverflow.com/questions/5146978/… Commented Jun 11, 2014 at 12:29
  • 2
    Caveat to readers: Most of the answers fail to provide an answer for the query as updated. Commented Jul 7, 2018 at 19:58
  • 1
    Isn't your query correct? Commented Jun 23, 2021 at 4:33

11 Answers 11

355

This will do what you want (list of towns, with the number of users in each):

SELECT `town`, COUNT(`town`)
FROM `user`
GROUP BY `town`;

You can use most aggregate functions when using a GROUP BY statement (COUNT, MAX, COUNT DISTINCT etc.)

Update: You can declare a variable for the number of users and save the result there, and then SELECT the value of the variable:

DECLARE @numOfUsers INT
SET @numOfUsers = SELECT COUNT(*) FROM `user`;

SELECT DISTINCT `town`, @numOfUsers FROM `user`;
Sign up to request clarification or add additional context in comments.

Comments

195

You can use COUNT(DISTINCT ...) :

SELECT COUNT(DISTINCT town) 
FROM user

13 Comments

I think they mean if you put COUNT(DISTINCT town) in the WHERE clause. That is because it is an aggregate function and needs to be provided in the HAVING clause. This SQL query is misleading to some as SELECT COUNT(DISTINCT town) turns into an implicit GROUP BY, due to both the COUNT and DISTINCT keywords, each keyword on their own would also implicitly group.
That query comes back with simply "3", not a list of the 3 towns, nor the total user count.
@milkovsky - Thanks for deleting that wrong answer. I am on a campaign to get rid of the rest of the "wrong answers". This answer is still wrong -- the OP is asking for 2 columns; your query gives only one.
@milkovsky - No you don't have to delete it. I just find it irritation that this Question plus the many Answers have bifurcated into solving two different problems. Your answer deviates in two ways -- no town column, and it COUNTs the wrong thing (town instead of user).
@rogerdpack COUNT(DISTINCT ...) does work with GROUP BY, just make sure your grouping field is present in the SELECT statement. Example: SELECT COUNT(DISTINCT town), street FROM user GROUP BY street
|
49

The other way is:

/* Number of rows in a derived table called d1. */
select count(*) from
(
  /* Number of times each town appears in user. */
  select town, count(*)
  from user
  group by town
) d1

1 Comment

needs alias otherwise wouldnt work in mysql. select count(*) from( ) agr
13

Ten non-deleted answers; most do not do what the user asked for. Most Answers mis-read the question as thinking that there are 58 users in each town instead of 58 in total. Even the few that are correct are not optimal.

mysql> flush status;
Query OK, 0 rows affected (0.00 sec)

SELECT  province, total_cities
    FROM       ( SELECT  DISTINCT province  FROM  canada ) AS provinces
    CROSS JOIN ( SELECT  COUNT(*) total_cities  FROM  canada ) AS tot;
+---------------------------+--------------+
| province                  | total_cities |
+---------------------------+--------------+
| Alberta                   |         5484 |
| British Columbia          |         5484 |
| Manitoba                  |         5484 |
| New Brunswick             |         5484 |
| Newfoundland and Labrador |         5484 |
| Northwest Territories     |         5484 |
| Nova Scotia               |         5484 |
| Nunavut                   |         5484 |
| Ontario                   |         5484 |
| Prince Edward Island      |         5484 |
| Quebec                    |         5484 |
| Saskatchewan              |         5484 |
| Yukon                     |         5484 |
+---------------------------+--------------+
13 rows in set (0.01 sec)

SHOW session status LIKE 'Handler%';

+----------------------------+-------+
| Variable_name              | Value |
+----------------------------+-------+
| Handler_commit             | 1     |
| Handler_delete             | 0     |
| Handler_discover           | 0     |
| Handler_external_lock      | 4     |
| Handler_mrr_init           | 0     |
| Handler_prepare            | 0     |
| Handler_read_first         | 3     |
| Handler_read_key           | 16    |
| Handler_read_last          | 1     |
| Handler_read_next          | 5484  |  -- One table scan to get COUNT(*)
| Handler_read_prev          | 0     |
| Handler_read_rnd           | 0     |
| Handler_read_rnd_next      | 15    |
| Handler_rollback           | 0     |
| Handler_savepoint          | 0     |
| Handler_savepoint_rollback | 0     |
| Handler_update             | 0     |
| Handler_write              | 14    |  -- leapfrog through index to find provinces  
+----------------------------+-------+

In the OP's context:

SELECT  town, total_users
    FROM       ( SELECT  DISTINCT town  FROM  canada ) AS towns
    CROSS JOIN ( SELECT  COUNT(*) total_users  FROM  canada ) AS tot;

Since there is only one row from tot, the CROSS JOIN is not as voluminous as it might otherwise be.

The usual pattern is COUNT(*) instead of COUNT(town). The latter implies checking town for being not null, which is unnecessary in this context.

2 Comments

"The usual pattern is COUNT(*) instead of COUNT(town). The latter implies checking town for being not null, which is unnecessary in this context" Thank you for actually mentioning that, was having a tough time figuring the difference!
@Ayush - You are welcome. It seems that most users have not yet discovered that subtle distinction. In some other cases, one wants COUNT(DISTINCT town).
5

With Oracle you could use analytic functions:

select town, count(town), sum(count(town)) over () total_count from user
group by town

Your other options is to use a subquery:

select town, count(town), (select count(town) from user) as total_count from user
group by town

3 Comments

something like the last one would work, but I wanted to see if there is any other solution..
And cannot you use the first (analytic function) option? What database platform are you using?
@Stavros: The last one is slow
4

If you want to order by count (sound simple but i can`t found an answer on stack of how to do that) you can do:

        SELECT town, count(town) as total FROM user
        GROUP BY town ORDER BY total DESC

Comments

4

You can use DISTINCT inside the COUNT like what milkovsky said

in my case:

select COUNT(distinct user_id) from answers_votes where answer_id in (694,695);

This will pull the count of answer votes considered the same user_id as one count

Comments

2

I know this is an old post, in SQL Server:

select  isnull(town,'TOTAL') Town, count(*) cnt
from    user
group by town WITH ROLLUP

Town         cnt
Copenhagen   58
NewYork      58
Athens       58
TOTAL        174

2 Comments

There is nothing wrong with answering old posts. However, please include an explanation of your code as well as the code itself.
The MySQL equivalent (IFNULL instead of ISNULL) leads to different numbers for each town; the user wanted the total. According to the Question, 58, not 174, is the total.
1

If you want to select town and total user count, you can use this query below:

SELECT Town, (SELECT Count(*) FROM User) `Count` FROM user GROUP BY Town;

1 Comment

This assumes (perhaps reasonably) there there are no duplicate "users" in User.
1

if You Want to use Select All Query With Count Option, try this...

 select a.*, (Select count(b.name) from table_name as b where Condition) as totCount from table_name  as a where where Condition

1 Comment

Thank you for this code snippet, which might provide some limited, immediate help. A proper explanation would greatly improve its long-term value by showing why this is a good solution to the problem, and would make it more useful to future readers with other, similar questions. Please edit your answer to add some explanation, including the assumptions you've made.
0

Try the following code:

select ccode, count(empno) 
from company_details 
group by ccode;

1 Comment

we use this code to find how many total employee for present day calc in each and every ccode ( company code ) example : count(empno) is 1839 for ccode 1 and count(empno) is 9421 for ccode 47.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.