Verwendung von count und group by bei derselben select-Anweisung


223

Ich habe eine SQL-Auswahlabfrage, die eine Gruppe von hat. Ich möchte alle Datensätze nach der Gruppe nach Anweisung zählen. Gibt es dafür einen Weg direkt von SQL? Wenn ich beispielsweise eine Tabelle mit Benutzern habe, möchte ich die verschiedenen Städte und die Gesamtzahl der Benutzer auswählen

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

Ich möchte eine Spalte mit allen Städten und eine andere mit der Anzahl der Benutzer in allen Zeilen haben.

Ein Beispiel für das Ergebnis mit 3 Städten und insgesamt 58 Benutzern ist:

Town         Count
Copenhagen   58
NewYork      58
Athens       58

Sie meinen, Sie möchten, dass Ihre Ergebnismenge zwei Zählungen enthält, eine für Städte und eine für Benutzer?
Leslie

2
Sie möchten also eine Zeile für jede Stadt und in jeder Zeile enthält Spalte 2 die Gesamtzahl aller Benutzer? Spalte 2 hat also für jede Zeile den gleichen Wert? Wenn Sie bearbeiten, um Beispieldaten und die erforderliche Ausgabe einzuschließen, können wir Ihnen genau das geben, was Sie möchten.
AakashM

Sie haben Recht, AakashM! Ich habe es gerade bearbeitet.
Stavros


1
Vorsichtsmaßnahme für Leser: Die meisten Antworten geben keine Antwort auf die aktualisierte Abfrage.
Rick James

Antworten:


271

Dies wird tun, was Sie wollen (Liste der Städte mit der Anzahl der Benutzer in jedem):

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

Sie können die meisten Aggregatfunktionen verwenden, wenn Sie verwenden GROUP BY.

Update (nach Änderung der Frage und Kommentare)

Sie können eine Variable für die Anzahl der Benutzer deklarieren und auf die Anzahl der Benutzer festlegen und dann damit auswählen.

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

SELECT DISTINCT town, @numOfUsers
FROM user

Genau das hat das OP geschrieben? nvm, ich sehe deinen Unterschied, du zählst Town nicht * ....
Leslie

@Leslie - es gibt keinen Unterschied zwischen den beiden Abfragen. Sie geben dieselbe Ergebnismenge zurück. Ich mag die Verwendung von *... Das OP beantwortete seine eigene Frage nicht, schien sie aber nicht einmal zu testen. Ich bestätige nur, dass sie korrekt ist :) fredosaurus.com/notes-db/select/groupby.html
Oded

Wieder nicht das, was ich mir erhofft hatte, aber es scheint, dass dies die beste Lösung ist ..;) Danke
Stavros

149

Sie können verwenden COUNT(DISTINCT ...):

SELECT COUNT(DISTINCT town) 
FROM user

3
funktioniert als Zauber ... sollte die Hauptantwort gewählt werden .. außer einigen Sonden, dass dies nicht gut ist.
Victor

2
Ich denke, sie bedeuten, wenn Sie COUNT (DISTINCT town) in die WHERE-Klausel aufnehmen. Dies liegt daran, dass es sich um eine Aggregatfunktion handelt, die in der HAVING-Klausel angegeben werden muss. Diese SQL-Abfrage ist für einige irreführend, da SELECT COUNT (DISTINCT-Stadt) aufgrund der Schlüsselwörter COUNT und DISTINCT zu einem impliziten GROUP BY wird. Jedes Schlüsselwort für sich würde auch implizit gruppieren.
A. Greensmith

Vielen Dank. Upvote. Genau das, was benötigt wird - Gruppe + Zählung in einer Operation und Ergebnis einer einzelnen Zeile.
Grün

Scheiße .. Ich wusste nicht, dass das möglich ist!
Hugo S. Mendes

1
@milkovsky - Nein, du musst es nicht löschen. Ich finde es nur irritierend, dass diese Frage und die vielen Antworten dazu geführt haben, zwei verschiedene Probleme zu lösen . Ihre Antwort weicht auf zwei Arten ab - keine townSpalte, und es ist COUNTsdas Falsche (Stadt statt Benutzer).
Rick James

37

Der andere Weg ist:

/* 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
braucht Alias ​​sonst würde nicht in MySQL funktionieren.
Wählen

4

Mit Oracle können Sie Analysefunktionen verwenden:

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

Sie können auch eine Unterabfrage verwenden:

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

so etwas wie das letzte würde funktionieren, aber ich wollte sehen, ob es eine andere Lösung gibt ..
Stavros

Und können Sie nicht die erste Option (Analysefunktion) verwenden? Welche Datenbankplattform verwenden Sie?
Tommi

@ Stavros: Der letzte ist langsam
Michael Buen

4

Wenn Sie nach Anzahl bestellen möchten (klingt einfach, aber ich kann auf dem Stapel keine Antwort darauf finden, wie das geht), können Sie Folgendes tun:

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

4

Zehn nicht gelöschte Antworten; Die meisten tun nicht das, wonach der Benutzer gefragt hat. In den meisten Antworten wurde die Frage falsch verstanden, da angenommen wurde, dass in jeder Stadt 58 Benutzer statt insgesamt 58 Benutzer vorhanden sind . Selbst die wenigen, die richtig sind, sind nicht 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  
+----------------------------+-------+

Im Kontext des OP:

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

Da es nur eine Zeile von gibt tot, CROSS JOINist die nicht so umfangreich, wie es sonst sein könnte.

Das übliche Muster ist COUNT(*)statt COUNT(town). Letzteres impliziert, dass geprüft townwird , ob es nicht null ist, was in diesem Zusammenhang nicht erforderlich ist.


2

Sie können DISTINCT innerhalb des COUNT verwenden, wie es Milkovsky gesagt hat

in meinem Fall:

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

Dadurch wird die Anzahl der Antwortstimmen ermittelt, die als dieselbe Benutzer-ID wie eine Anzahl betrachtet werden


2

Ich weiß, dass dies ein alter Beitrag in SQL Server ist:

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
Es ist nichts Falsches daran, alte Beiträge zu beantworten. Bitte fügen Sie jedoch eine Erläuterung Ihres Codes sowie den Code selbst bei.
Shelvacu

Das MySQL-Äquivalent ( IFNULLanstelle von ISNULL) führt zu unterschiedlichen Zahlen für jede Stadt. Der Benutzer wollte die Summe. Nach der Frage ist 58, nicht 174, die Summe.
Rick James

1

Wenn Sie die Stadt und die Gesamtzahl der Benutzer auswählen möchten, können Sie die folgende Abfrage verwenden:

SELECT Town, (SELECT Count(*) FROM User) `Count` FROM user GROUP BY Town;

Dies setzt voraus (vielleicht vernünftigerweise), dass es keine doppelten "Benutzer" gibt User.
Rick James

1

Wenn Sie die Option Alle Abfragen mit Zählung auswählen verwenden möchten, versuchen Sie Folgendes ...

 select a.*, (Select count(b.name) from table_name as b where Condition) as totCount from table_name  as a where where Condition

Vielen Dank für dieses Code-Snippet, das möglicherweise nur begrenzte und sofortige Hilfe bietet. Eine richtige Erklärung würde ihren langfristigen Wert erheblich verbessern, indem sie zeigt, warum dies eine gute Lösung für das Problem ist, und es für zukünftige Leser mit anderen, ähnlichen Fragen nützlicher machen. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, einschließlich der von Ihnen getroffenen Annahmen.
Toby Speight

0

Versuchen Sie den folgenden Code:

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

Wir verwenden diesen Code, um herauszufinden, wie viele Mitarbeiter für die heutige Berechnung in jedem Code (Buchungskreis) berechnet wurden. Beispiel: Anzahl (empno) ist 1839 für Code 1 und Anzahl (empno) ist 9421 für Code 47.
balajibran
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.