Как использовать 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

что-то вроде последнего сработало бы, но я хотел посмотреть, есть ли какое-нибудь другое решение ..
Ставрос

И вы не можете использовать первый (аналитическая функция) вариант? Какую платформу базы данных вы используете?
Томми

@Stavros: последний медленный
Майкл Буэн

4

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

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

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;

мы используем этот код, чтобы найти, сколько всего сотрудников в расчете на текущий день приходится на каждый пример ccode (балансовой единицы): count (empno) равен 1839 для ccode 1, а count (empno) равен 9421 для ccode 47.
balajibran
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.