Як використовувати підрахунок та групувати за допомогою одного оператора select


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! Я щойно це відредагував.
Ставрос


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

саме так написала ОП? nvm, я бачу вашу різницю, ти вважаєш місто не * ....
Леслі

@Leslie - різниці між двома запитами немає. Вони повернуть той самий набір результатів. Я просто не подобається, використання *... ОП відповів на своє запитання, але не схоже, навіть перевірити це, я просто перевірка , що це правильно :) fredosaurus.com/notes-db/select/groupby.html
Одед

Знову не те, на що я сподівався, але здається, що це найкраще рішення ..;) Дякую
Ставрос

149

Ви можете використовувати COUNT(DISTINCT ...):

SELECT COUNT(DISTINCT town) 
FROM user

3
працює як шарм ... слід вибрати головну відповідь .. за винятком якогось зонда, що це не добре.
Віктор

2
Я думаю, що вони означають, якщо ви ставите COUNT (DISTINCT town) у пункті WHERE. Це тому, що це сукупна функція і її потрібно передбачити в пункті HAVING. Цей запит SQL для деяких вводить в оману, оскільки SELECT COUNT (місто DISTINCT) перетворюється на неявну групу GROUP BY, завдяки ключовим словам COUNT і DISTINCT, кожне окреме ключове слово також буде неявно групуватися.
А. Грінсміт

Дякую. Оновлення Саме те, що потрібно - згрупуйте + порахуйте в одній оп і отримайте в результаті один рядок.
Зелений

Лайно .. Я не знав, що це можливо!
Гюго С. Мендес

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. вибрати count (*) з ()
agr

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

4

Десять не видалених відповідей; більшість не роблять те, що просив користувач. Більшість відповідей неправильно читають питання, думаючи, що в кожному місті є 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на предмет недійсності, що є непотрібним у цьому контексті.


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 a.*, (Select count(b.name) from table_name as b where Condition) as totCount from table_name  as a where where Condition

Дякуємо за цей фрагмент коду, який може надати деяку обмежену, негайну допомогу. Правильне пояснення значно покращило б його довгострокове значення, показавши, чому це хороше рішення проблеми, та зробило б кориснішим майбутнім читачам інші подібні питання. Будь ласка, відредагуйте свою відповідь, щоб додати пояснення, включаючи зроблені вами припущення.
Toby Speight

0

Спробуйте наступний код:

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

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