Cách sử dụng số lượng và nhóm theo cùng một câu lệnh chọn


223

Tôi có một truy vấn chọn sql có một nhóm bởi. Tôi muốn đếm tất cả các hồ sơ sau khi nhóm bằng tuyên bố. Có cách nào cho điều này trực tiếp từ sql? Ví dụ: có một bảng với người dùng tôi muốn chọn các thị trấn khác nhau và tổng số người dùng

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

Tôi muốn có một cột với tất cả các thị trấn và một thị trấn khác với số lượng người dùng trong tất cả các hàng.

Một ví dụ về kết quả có tổng cộng 3 thị trấn và 58 người dùng là:

Town         Count
Copenhagen   58
NewYork      58
Athens       58

bạn có nghĩa là bạn muốn kết quả của bạn được đặt có 2 lần đếm cho thị trấn và một cho người dùng?
Leslie

2
Vì vậy, bạn muốn một hàng cho mỗi thị trấn và trong mỗi hàng, cột 2 chứa tổng số người dùng? Vậy cột 2 có cùng giá trị cho mỗi hàng? Nếu bạn chỉnh sửa để bao gồm dữ liệu mẫu và đầu ra cần thiết, chúng tôi sẽ có thể cung cấp cho bạn chính xác những gì bạn muốn.
AakashM

Bạn nói đúng AakashM! Tôi chỉ chỉnh sửa nó.
Stavros

2
Câu hỏi liên quan: stackoverflow.com/questions/5146978/
Mạnh

1
Hãy cẩn thận với độc giả: Hầu hết các câu trả lời không cung cấp câu trả lời cho truy vấn như đã cập nhật.
Rick James

Câu trả lời:


271

Điều này sẽ làm những gì bạn muốn (danh sách các thị trấn, với số lượng người dùng ở mỗi):

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

Bạn có thể sử dụng hầu hết các hàm tổng hợp khi sử dụng GROUP BY.

Cập nhật (thay đổi câu hỏi và bình luận)

Bạn có thể khai báo một biến cho số lượng người dùng và đặt nó thành số lượng người dùng sau đó chọn với số đó.

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

SELECT DISTINCT town, @numOfUsers
FROM user

Đó chính xác là những gì OP đã viết? nvm, tôi thấy sự khác biệt của bạn, bạn đang đếm Town không * ....
Leslie

@Leslie - không có sự khác biệt giữa hai truy vấn. Họ sẽ trả lại cùng một tập kết quả. Tôi chỉ không thích việc sử dụng *... OP đã trả lời câu hỏi của chính anh ta, nhưng dường như thậm chí không kiểm tra nó, tôi chỉ xác nhận rằng đó là chính xác :) fredoaurus.com/notes-db/select/groupby.html
Oded

Một lần nữa không phải là những gì tôi hy vọng, nhưng có vẻ như đây là giải pháp tốt nhất ..;) Cảm ơn
Stavros

149

Bạn có thể sử dụng COUNT(DISTINCT ...):

SELECT COUNT(DISTINCT town) 
FROM user

3
hoạt động như một cơ duyên ... nên được chọn câu trả lời chính .. ngoại trừ một số thăm dò rằng điều này là không tốt.
Victor

2
Tôi nghĩ chúng có nghĩa là nếu bạn đặt COUNT (thị trấn DISTINCT) trong mệnh đề WHERE. Đó là bởi vì nó là một hàm tổng hợp và cần được cung cấp trong mệnh đề HAVING. Truy vấn SQL này gây hiểu nhầm cho một số người vì CHỌN COUNT (thị trấn DISTINCT) biến thành NHÓM ẩn, do cả hai từ khóa COUNT và DISTINCT, mỗi từ khóa cũng sẽ tự nhóm.
A. Greensmith

Cảm ơn. Upvote. Chính xác những gì cần thiết - nhóm + đếm trong một op và nhận được một hàng duy nhất trong kết quả.
Xanh

Chết tiệt .. Tôi không biết điều đó là có thể!
Hugo S. Mendes

1
@milkovsky - Không, bạn không cần phải xóa nó. Tôi chỉ thấy khó chịu khi Câu hỏi này cộng với nhiều Câu trả lời đã phân chia thành hai vấn đề khác nhau . Câu trả lời của bạn đi lệch theo hai cách - không có towncột và đó COUNTslà điều sai (thị trấn thay vì người dùng).
Rick James

37

Một cách khác là:

/* 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
cần bí danh nếu không sẽ không hoạt động trong mysql. chọn tính (*) từ () agr
amas

4

Với Oracle, bạn có thể sử dụng các chức năng phân tích:

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

Các tùy chọn khác của bạn là sử dụng truy vấn con:

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

một cái gì đó giống như cái cuối cùng sẽ hoạt động, nhưng tôi muốn xem liệu có giải pháp nào khác không ..
Stavros

Và bạn không thể sử dụng tùy chọn (chức năng phân tích) đầu tiên? Bạn đang sử dụng nền tảng cơ sở dữ liệu nào?
Tommi

@Stavros: Cái cuối cùng chậm
Michael Buen

4

Nếu bạn muốn đặt hàng theo số lượng (nghe có vẻ đơn giản nhưng tôi không thể tìm thấy câu trả lời về cách làm điều đó), bạn có thể làm:

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

4

Mười câu trả lời không bị xóa; hầu hết không làm những gì người dùng yêu cầu. Hầu hết các câu trả lời đọc sai câu hỏi vì nghĩ rằng có 58 người dùng ở mỗi thị trấn thay vì tổng cộng 58 người. Ngay cả số ít là chính xác cũng không tối ưu.

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

Trong bối cảnh của OP:

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

Vì chỉ có một hàng từ tot, nên CROSS JOINnó không quá đồ sộ như nó có thể.

Các mô hình thông thường là COUNT(*)thay vì COUNT(town). Cái sau ngụ ý việc kiểm tra townkhông phải là null, điều này là không cần thiết trong bối cảnh này.


2

Bạn có thể sử dụng DISTINCT bên trong COUNT như những gì milkovsky nói

trong trường hợp của tôi:

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

Điều này sẽ kéo tổng số phiếu trả lời được coi là cùng user_id như một lần đếm


2

Tôi biết đây là một bài viết cũ, trong 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
Không có gì sai khi trả lời bài viết cũ. Tuy nhiên, vui lòng bao gồm một lời giải thích về mã của bạn cũng như chính mã đó.
Shelvacu

Tương đương với MySQL ( IFNULLthay vì ISNULL) dẫn đến các số khác nhau cho mỗi thị trấn; người dùng muốn tổng số. Theo Câu hỏi, 58, không phải 174, là tổng số.
Rick James

1

Nếu bạn muốn chọn thị trấn và tổng số người dùng, bạn có thể sử dụng truy vấn này bên dưới:

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

Giả định này (có lẽ là hợp lý) không có "người dùng" trùng lặp User.
Rick James

1

nếu bạn muốn sử dụng Chọn tất cả truy vấn với tùy chọn đếm, hãy thử ...

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

Cảm ơn bạn vì đoạn mã này, có thể cung cấp một số trợ giúp hạn chế, ngay lập tức. Một lời giải thích phù hợp sẽ cải thiện đáng kể giá trị lâu dài của nó bằng cách chỉ ra lý do tại sao đây là một giải pháp tốt cho vấn đề và sẽ giúp nó hữu ích hơn cho những người đọc tương lai với những câu hỏi tương tự khác. Vui lòng chỉnh sửa câu trả lời của bạn để thêm một số giải thích, bao gồm các giả định bạn đã thực hiện.
Toby Speight

0

Hãy thử đoạn mã sau:

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

chúng tôi sử dụng mã này để tìm tổng số nhân viên cho calc ngày nay trong mỗi ví dụ về mã (mã công ty): Count (empno) là 1839 cho mã 1 và đếm (empno) là 9421 cho mã 47.
balajibran
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.