วิธีใช้การนับและจัดกลุ่มตามที่คำสั่ง 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! ฉันเพิ่งแก้ไขมัน
Stavros

2
คำถามที่เกี่ยวข้อง: stackoverflow.com/questions/5146978/…
milkovsky

1
คำเตือนสำหรับผู้อ่าน: คำตอบส่วนใหญ่ไม่สามารถให้คำตอบสำหรับการค้นหาได้เมื่อมีการปรับปรุง
Rick James

คำตอบ:


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

นั่นคือสิ่งที่ OP เขียนไว้? nvm ฉันเห็นความแตกต่างของคุณคุณกำลังนับ Town ไม่ใช่ * ....
Leslie

@Leslie - ไม่มีข้อแตกต่างระหว่างสองข้อความค้นหา พวกเขาจะส่งคืนชุดผลลัพธ์เดียวกัน ฉันไม่ชอบการใช้*... OP ตอบคำถามของเขาเอง แต่ดูเหมือนจะไม่ได้ทดสอบฉันแค่ตรวจสอบว่ามันถูกต้อง :) fredosaurus.com/notes-db/select/groupby.html
Oded

ไม่ใช่สิ่งที่ฉันหวังไว้ แต่ดูเหมือนว่านี่เป็นทางออกที่ดีที่สุด .. ;) ขอบคุณ
Stavros

149

คุณสามารถใช้COUNT(DISTINCT ...):

SELECT COUNT(DISTINCT town) 
FROM user

3
ทำงานเป็นเสน่ห์ ... ควรเลือกคำตอบหลัก .. ยกเว้นโพรบบางตัวที่ไม่ดี
วิกเตอร์

2
ฉันคิดว่าพวกเขาหมายถึงถ้าคุณใส่ COUNT (DISTINCT town) ใน WHERE clause นั่นเป็นเพราะมันเป็นฟังก์ชั่นรวมและจะต้องมีการระบุไว้ในข้อ HAVING แบบสอบถาม SQL นี้สร้างความเข้าใจผิดให้กับบางคนในขณะที่ SELECT COUNT (เมือง DISTINCT) กลายเป็น GROUP BY โดยปริยายเนื่องจากทั้งคำหลัก COUNT และ DISTINCT แต่ละคำหลักด้วยตนเองจะจัดกลุ่มโดยปริยาย
A. Greensmith

ขอบคุณ upvote สิ่งที่จำเป็น - กลุ่ม + นับในหนึ่ง op และรับผลลัพธ์แถวเดียว
สีเขียว

อึ .. ฉันไม่รู้ว่ามันเป็นไปได้!
Hugo S. Mendes

1
@milkovsky - ไม่คุณไม่ต้องลบมัน ฉันเพิ่งพบว่ามันระคายเคืองว่าคำถามนี้บวกหลายคำตอบได้ bifurcated เข้าไปแก้ทั้งสองแตกต่างกันปัญหา คำตอบของคุณเบี่ยงเบนไปในสองวิธี - ไม่มีtownคอลัมน์และCOUNTsเป็นสิ่งที่ผิด (เมืองแทนที่จะเป็นผู้ใช้)
Rick James

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

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

และคุณไม่สามารถใช้ตัวเลือกแรก (ฟังก์ชั่นการวิเคราะห์) หรือไม่? คุณใช้แพลตฟอร์มฐานข้อมูลใด
Tommi

@Stavros: คนสุดท้ายช้า
Michael Buen

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

ในบริบทของ OP:

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 เหมือนกับที่ milkovsky พูด

ในกรณีของฉัน:

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
ไม่มีอะไรผิดปกติในการตอบกระทู้เก่า ๆ อย่างไรก็ตามโปรดระบุคำอธิบายรหัสของคุณรวมถึงรหัสด้วย
Shelvacu

MySQL ที่เทียบเท่า ( IFNULLแทนISNULL) จะนำไปสู่ตัวเลขที่แตกต่างกันสำหรับแต่ละเมือง ผู้ใช้ต้องการผลรวม ตามคำถาม 58 ไม่ใช่ 174 เป็นผลรวม
Rick James

1

หากคุณต้องการเลือกเมืองและจำนวนผู้ใช้ทั้งหมดคุณสามารถใช้แบบสอบถามนี้ด้านล่าง:

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

นี้อนุมาน (บางทีพอสมควร) มีไม่มี "ผู้ใช้" Userที่ซ้ำกันใน
Rick James

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;

เราใช้รหัสนี้เพื่อค้นหาจำนวนพนักงานทั้งหมดสำหรับการคำนวณวันปัจจุบันในแต่ละคนและทุก ccode (รหัส บริษัท ) ตัวอย่าง: count (empno) คือ 1839 สำหรับ ccode 1 และ count (empno) คือ 9421 สำหรับ ccode 47
balajibran
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.