Comment utiliser count et group by par la même instruction select

223

J'ai une requête SQL Select qui a un groupe par. Je veux compter tous les enregistrements après l'instruction group by. Existe-t-il un moyen pour cela directement à partir de SQL? Par exemple, ayant une table avec des utilisateurs, je veux sélectionner les différentes villes et le nombre total d'utilisateurs

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

Je veux avoir une colonne avec toutes les villes et une autre avec le nombre d'utilisateurs dans toutes les lignes.

Un exemple du résultat pour avoir 3 villes et 58 utilisateurs au total est:

Town         Count
Copenhagen   58
NewYork      58
Athens       58
Stavros
la source
vous voulez dire que votre jeu de résultats doit avoir 2 comptes, un pour les villes et un pour les utilisateurs?
Leslie
2
Vous voulez donc une ligne pour chaque ville, et dans chaque ligne, la colonne 2 contient le nombre total de tous les utilisateurs? La colonne 2 a donc la même valeur pour chaque ligne? Si vous modifiez pour inclure des exemples de données et la sortie requise, nous serons en mesure de vous donner exactement ce que vous voulez.
AakashM
Vous avez raison AakashM! Je viens de le modifier.
Stavros
2
Question connexe: stackoverflow.com/questions/5146978/…
milkovsky
1
Avertissement aux lecteurs: la plupart des réponses ne fournissent pas de réponse à la requête mise à jour.
Rick James

Réponses:

271

Cela fera ce que vous voulez (liste des villes, avec le nombre d'utilisateurs dans chacune):

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

Vous pouvez utiliser la plupart des fonctions d'agrégation lors de l'utilisation GROUP BY.

Mise à jour (suite au changement de question et commentaires)

Vous pouvez déclarer une variable pour le nombre d'utilisateurs et la définir sur le nombre d'utilisateurs, puis sélectionner avec cela.

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

SELECT DISTINCT town, @numOfUsers
FROM user
Oded
la source
c'est exactement ce que le PO a écrit? nvm, je vois votre différence, vous ne comptez pas la ville * ....
Leslie
@Leslie - il n'y a aucune différence entre les deux requêtes. Ils renverront le même jeu de résultats. Je n'aime tout simplement pas l'utilisation de *... L'OP a répondu à sa propre question, mais ne semble même pas le tester, je valide juste qu'il est correct :) fredosaurus.com/notes-db/select/groupby.html
Oded
Encore une fois pas ce que j'espérais, mais il semble que ce soit la meilleure solution ..;) Merci
Stavros
149

Vous pouvez utiliser COUNT(DISTINCT ...):

SELECT COUNT(DISTINCT town) 
FROM user
milkovsky
la source
3
fonctionne comme un charme ... devrait être choisi la réponse principale .. sauf quelques sondages que ce n'est pas bon.
Victor
2
Je pense qu'ils signifient que si vous mettez COUNT (DISTINCT town) dans la clause WHERE. En effet, il s'agit d'une fonction d'agrégation et doit être fournie dans la clause HAVING. Cette requête SQL est trompeuse pour certains car SELECT COUNT (ville DISTINCT) se transforme en un GROUP BY implicite, en raison des mots-clés COUNT et DISTINCT, chaque mot-clé à lui seul se regrouperait également implicitement.
A. Greensmith
Merci. Upvote. Exactement ce qui est nécessaire - grouper + compter en une seule opération et obtenir une seule ligne de résultat.
Vert
Merde .. Je ne savais pas que c'était possible!
Hugo S.Mendes
1
@milkovsky - Non, vous n'avez pas à le supprimer. Je trouve juste irritant que cette question ainsi que les nombreuses réponses aient bifurqué pour résoudre deux problèmes différents . Votre réponse s'écarte de deux manières - pas de towncolonne, et c'est COUNTsla mauvaise chose (ville au lieu d'utilisateur).
Rick James
37

L'autre façon est:

/* 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
ZhenYu Wang
la source
5
nécessite un alias sinon ne fonctionnerait pas dans mysql. sélectionnez le nombre (*) de () agr
amas
4

Avec Oracle, vous pouvez utiliser des fonctions analytiques:

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

Vos autres options sont d'utiliser une sous-requête:

select town, count(town), (select count(town) from user) as total_count from user
group by town
Tommi
la source
quelque chose comme le dernier fonctionnerait, mais je voulais voir s'il y avait une autre solution ..
Stavros
Et ne pouvez-vous pas utiliser la première option (fonction analytique)? Quelle plateforme de base de données utilisez-vous?
Tommi
@Stavros: Le dernier est lent
Michael Buen
4

Si vous souhaitez commander par nombre (cela semble simple mais je ne trouve pas de réponse sur la pile de la façon de le faire), vous pouvez le faire:

        SELECT town, count(town) as total FROM user
        GROUP BY town ORDER BY total DESC
sagits
la source
4

Dix réponses non supprimées; la plupart ne font pas ce que l'utilisateur a demandé. La plupart des réponses ont mal interprété la question en pensant qu'il y avait 58 utilisateurs dans chaque ville au lieu de 58 au total. Même les quelques correctes ne sont pas optimales.

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

Dans le contexte du PO:

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

Puisqu'il n'y a qu'une seule ligne tot, le CROSS JOINn'est pas aussi volumineux qu'il pourrait l'être autrement.

Le modèle habituel est COUNT(*)au lieu de COUNT(town). Cette dernière implique de vérifier townqu'elle n'est pas nulle, ce qui n'est pas nécessaire dans ce contexte.

Rick James
la source
2

Vous pouvez utiliser DISTINCT à l'intérieur du COUNT comme ce que dit milkovsky

dans mon cas:

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

Cela va tirer le nombre de votes de réponse considéré comme le même user_id qu'un seul compte

Jur P
la source
2

Je sais que c'est une ancienne publication dans 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
Marcus
la source
5
Il n'y a rien de mal à répondre aux anciens messages. Cependant, veuillez inclure une explication de votre code ainsi que le code lui-même.
Shelvacu
L'équivalent MySQL ( IFNULLau lieu de ISNULL) conduit à des nombres différents pour chaque ville; l'utilisateur voulait le total. Selon la question, 58, et non 174, est le total.
Rick James
1

Si vous souhaitez sélectionner la ville et le nombre total d'utilisateurs, vous pouvez utiliser cette requête ci-dessous:

SELECT Town, (SELECT Count(*) FROM User) `Count` FROM user GROUP BY Town;
Violendy Firdaus
la source
Cela suppose (peut-être raisonnablement) qu'il n'y a pas d '"utilisateurs" en double dans User.
Rick James
1

si vous souhaitez utiliser l'option Sélectionner toutes les requêtes avec nombre, essayez ceci ...

 select a.*, (Select count(b.name) from table_name as b where Condition) as totCount from table_name  as a where where Condition
Prakash
la source
Merci pour cet extrait de code, qui pourrait fournir une aide limitée et immédiate. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi c'est une bonne solution au problème, et la rendrait plus utile aux futurs lecteurs avec d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez faites.
Toby Speight
0

Essayez le code suivant:

select ccode, count(empno) 
from company_details 
group by ccode;
balajibran
la source
nous utilisons ce code pour trouver le nombre total d'employés pour le calcul actuel dans chaque exemple de ccode (société): count (empno) est 1839 pour ccode 1 et count (empno) est 9421 pour ccode 47.
balajibran