ChatGPT解决这个技术问题 Extra ChatGPT

How to use count and group by at the same select statement

I have an sql select query that has a group by. I want to count all the records after the group by statement. Is there a way for this directly from sql? For example, having a table with users I 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
NewYork      58
Athens       58
you mean you want your result set to have 2 counts one for towns and one for users?
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.
Caveat to readers: Most of the answers fail to provide an answer for the query as updated.
Isn't your query correct?

r
rogerdpack

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 GROUP BY:

(COUNT, MAX, COUNT DISTINCT etc.)

Update (following change to question and comments)

You can declare a variable for the number of users and set it to the number of users then select with that.

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

SELECT DISTINCT town, @numOfUsers
FROM user

that's exactly what the OP wrote? nvm, i see your difference, you're counting Town not *....
@Leslie - there is no difference between the two queries. They will return the same result set. I just dislike the use of *... The OP answered his own question, but did not seem to even test it, I am just validating that it is correct :) fredosaurus.com/notes-db/select/groupby.html
Again not what I hoped for, but it seems that this is the best solution.. ;) Thanks
m
milkovsky

You can use COUNT(DISTINCT ...) :

SELECT COUNT(DISTINCT town) 
FROM user

works as a charm... should be choosen the main answer.. except some probe that this is not good.
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.
Thanks. Upvote. Exactly what is needed - group + count in one op and get a single row in result.
@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
K
Kamil Slowikowski

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

needs alias otherwise wouldnt work in mysql. select count(*) from( ) agr
R
Rick James

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.


"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!
T
Tommi

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

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
R
Renato Probst

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

J
Jur P

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


M
Marcus

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

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.
S
Sal00m

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;

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

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

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.
J
JodyT

Try the following code:

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

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.