Как использовать count и group by в одном операторе выбора

223

У меня есть запрос выбора SQL, который имеет группу по. Я хочу посчитать все записи после группировки по заявлению. Есть ли способ для этого прямо из SQL? Например, имея таблицу с пользователями, я хочу выбрать разные города и общее количество пользователей.

select town, count(*) from user
group by town

Я хочу иметь столбец со всеми городами и другой с количеством пользователей во всех строках.

Пример результата для 3 городов и 58 пользователей:

Town         Count
Copenhagen   58
NewYork      58
Athens       58
Ставрос
источник
Вы хотите, чтобы в вашем наборе результатов было 2 счета, один для городов и один для пользователей?
Лесли
2
Итак, вы хотите одну строку для каждого города, а в каждой строке столбец 2 содержит общее количество всех пользователей? Таким образом, столбец 2 имеет одинаковое значение для каждой строки? Если вы отредактируете, чтобы включить образцы данных и требуемый вывод, мы сможем дать вам именно то, что вы хотите.
AakashM
Вы правы AakashM! Я только что отредактировал это.
Ставрос
2
Похожие вопросы: stackoverflow.com/questions/5146978/…
milkovsky
1
Предостережение для читателей: большинство ответов не содержат ответа на обновленный запрос.
Рик Джеймс

Ответы:

271

Это будет делать то, что вы хотите (список городов, с количеством пользователей в каждом):

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

Вы можете использовать большинство агрегатных функций при использовании GROUP BY.

Обновление (после изменения вопроса и комментариев)

Вы можете объявить переменную для количества пользователей и установить ее для количества пользователей, а затем выбрать с этим.

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

SELECT DISTINCT town, @numOfUsers
FROM user
Одед
источник
это именно то, что написал ОП? нвм, я вижу твою разницу, ты считаешь город не * ....
Лесли
@ Лесли - нет разницы между двумя запросами. Они вернут тот же набор результатов. Мне просто не нравится использование *... ОП ответил на свой вопрос, но, похоже, даже не проверял его, я просто проверяю, что это правильно :) fredosaurus.com/notes-db/select/groupby.html
Oded
Опять не то, на что я надеялся, но похоже, что это лучшее решение ..;) Спасибо
Ставрос
149

Вы можете использовать COUNT(DISTINCT ...):

SELECT COUNT(DISTINCT town) 
FROM user
Мильковский
источник
3
работает как очарование ... должен быть выбран основной ответ .. кроме некоторого исследования, что это не хорошо.
Виктор
2
Я думаю, они имеют в виду, если вы добавите COUNT (DISTINCT town) в предложение WHERE. Это потому, что это агрегатная функция, которая должна быть указана в предложении HAVING. Этот SQL-запрос вводит некоторых в заблуждение, поскольку SELECT COUNT (город DISTINCT) превращается в неявный GROUP BY, так как из-за ключевых слов COUNT и DISTINCT каждое ключевое слово само по себе также будет неявно группироваться.
А. Гринсмит
Спасибо. Upvote. Именно то, что нужно - группа + считать в одной операции и получить одну строку в результате.
Зеленый,
Черт .. Я не знал, что это возможно!
Хьюго С. Мендес
1
@milkovsky - Нет, вам не нужно это удалять. Меня просто раздражает, что этот Вопрос, а также множество Ответов разделились на решение двух разных проблем. Ваш ответ отклоняется в двух направлениях - без townстолбца, и это COUNTsне то (город вместо пользователя).
Рик Джеймс
37

Другой способ:

/* 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
Женю Ван
источник
5
нужен псевдоним, иначе не будет работать в MySQL. выберите количество (*) из () agr
amas
5

Десять не удаленных ответов; большинство не делает то, что просил пользователь. Большинство Ответов неверно истолковали вопрос, считая, что в каждом городе 58 пользователей, а не 58. Даже те немногие, которые являются правильными, не оптимальны.

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  
+----------------------------+-------+

В контексте ОП:

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

Поскольку есть только один ряд из tot, CROSS JOINон не такой объемный, как мог бы быть.

Обычный шаблон COUNT(*)вместо COUNT(town). Последнее подразумевает проверку townна ненулевое значение, что в этом контексте не требуется.

Рик Джеймс
источник
4

С Oracle вы можете использовать аналитические функции:

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

Другие ваши варианты - использовать подзапрос:

select town, count(town), (select count(town) from user) as total_count from user
group by town
Tommi
источник
что-то вроде последнего сработало бы, но я хотел посмотреть, есть ли какое-нибудь другое решение ..
Ставрос
И вы не можете использовать первый (аналитическая функция) вариант? Какую платформу базы данных вы используете?
Томми
@Stavros: последний медленный
Майкл Буэн
4

Если вы хотите сделать заказ по количеству (звучит просто, но я не могу найти ответ в стеке о том, как это сделать), вы можете сделать:

        SELECT town, count(town) as total FROM user
        GROUP BY town ORDER BY total DESC
sagits
источник
2

Вы можете использовать DISTINCT внутри COUNT, как сказал Милковский

в моем случае:

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

Это приведет к подсчету голосов за ответ, считая тот же user_id одним подсчетом

Юр П
источник
2

Я знаю, что это старый пост в 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
Маркус
источник
5
Нет ничего плохого в ответах на старые сообщения. Однако, пожалуйста, включите объяснение вашего кода, а также сам код.
Шелваку
Эквивалент MySQL ( IFNULLвместо ISNULL) приводит к различным числам для каждого города; пользователь хотел всего. Согласно Вопросу, 58, а не 174, является общим.
Рик Джеймс
1

Если вы хотите выбрать город и общее количество пользователей, вы можете использовать этот запрос ниже:

SELECT Town, (SELECT Count(*) FROM User) `Count` FROM user GROUP BY Town;
Виоленди Фирдаус
источник
Это предполагает (возможно, разумно), что там нет повторяющихся "пользователей" в User.
Рик Джеймс
1

Если вы хотите использовать опцию Select All Query With Count, попробуйте это ...

 select a.*, (Select count(b.name) from table_name as b where Condition) as totCount from table_name  as a where where Condition
Пракаш
источник
Спасибо за этот фрагмент кода, который может предоставить некоторую ограниченную, немедленную помощь. Правильное объяснение значительно улучшило бы его долгосрочную ценность, показав, почему это хорошее решение проблемы, и сделало бы его более полезным для будущих читателей с другими, похожими вопросами. Пожалуйста, измените свой ответ, чтобы добавить некоторые объяснения, в том числе предположения, которые вы сделали.
Тоби Спейт
0

Попробуйте следующий код:

select ccode, count(empno) 
from company_details 
group by ccode;
balajibran
источник
мы используем этот код, чтобы найти, сколько всего сотрудников в расчете на текущий день приходится на каждый пример ccode (балансовой единицы): count (empno) равен 1839 для ccode 1, а count (empno) равен 9421 для ccode 47.
balajibran