วิธีการนับการเกิดขึ้นของค่าคอลัมน์อย่างมีประสิทธิภาพใน SQL?


166

ฉันมีตารางนักเรียน:

id | age
--------
0  | 25
1  | 25
2  | 23

ฉันต้องการสอบถามนักเรียนทุกคนและคอลัมน์เพิ่มเติมที่นับจำนวนนักเรียนอายุเท่ากัน:

id | age | count
----------------
0  | 25  | 2
1  | 25  | 2
2  | 23  | 1

วิธีที่มีประสิทธิภาพที่สุดในการทำเช่นนี้คืออะไร? ฉันกลัวว่าย่อยแบบสอบถามจะช้าและฉันสงสัยว่าถ้ามีวิธีที่ดีกว่า มีอะไรบ้าง

คำตอบ:


256

สิ่งนี้น่าจะใช้ได้:

SELECT age, count(age) 
  FROM Students 
 GROUP by age

หากคุณต้องการรหัสเช่นกันคุณสามารถรวมข้างต้นเป็นแบบสอบถามย่อยเช่น:

SELECT S.id, S.age, C.cnt
  FROM Students  S
       INNER JOIN (SELECT age, count(age) as cnt
                     FROM Students 
                    GROUP BY age) C ON S.age = C.age

2
สำหรับแบบสอบถามที่สองตัวเลือกด้านนอกควรอยู่ใน C.cnt เนื่องจากไม่มี S.cnt มิฉะนั้นคุณจะได้รับข้อผิดพลาด: ชื่อคอลัมน์ไม่ถูกต้อง 'cnt'
KM

1
ข้อผิดพลาดในการให้สำหรับฉันเมื่อฉันใช้เลือก case_id, นับ (pgm_code) จากกลุ่ม pgm โดย pgm_code; มันบอกว่าไม่ใช่กลุ่มโดยการแสดงออก
Rishabh Agarwal

26

หากคุณกำลังใช้งาน Oracle คุณสมบัติที่เรียกว่าการวิเคราะห์จะทำเคล็ดลับ ดูเหมือนว่านี้:

select id, age, count(*) over (partition by age) from students;

หากคุณไม่ได้ใช้ Oracle คุณจะต้องเข้าร่วมนับใหม่:

select a.id, a.age, b.age_count
  from students a
  join (select age, count(*) as age_count
          from students
         group by age) b
    on a.age = b.age

2
FYI บน SQL Server 2005 แบบสอบถามที่สองทำงานเกือบครึ่งหนึ่งของค่าดำเนินการ (ใช้SET SHOWPLAN_ALL ON ) เป็นครั้งแรก ฉันคิดว่าครั้งแรกจะดีกว่านี้ แต่โรงเรียนเก่าเข้าร่วมชนะ
กม.

1
"โรงเรียนเก่าเข้าร่วมเอาชนะมัน" เพียงเพราะ TOTAL ROW COUNT ที่จะดำเนินการแตกต่าง ในแบบสอบถามที่สองมีการฝังกลุ่มตามที่อาจลดจำนวนแถวอย่างมาก ลองเพิ่ม DISTINCT ลงในข้อความค้นหาแรก: "เลือกรหัส DISTINCT, อายุ, นับ (*) บน (แบ่งพาร์ติชันตามอายุ) จากนักเรียน" - ที่ควรเทียบเคียงได้
quetzalcoatl

19

นี่คือทางออกอื่น อันนี้ใช้ไวยากรณ์ที่ง่ายมาก ตัวอย่างแรกของโซลูชันที่ยอมรับไม่ทำงานบน Microsoft SQL เวอร์ชันเก่ากว่า (เช่น 2000)

SELECT age, count(*)
FROM Students 
GROUP by age
ORDER BY age

1
หากคุณจัดกลุ่มตามอายุคุณจะได้รับหนึ่งรายการสำหรับอายุ 25 ด้วยการนับ 2 เท่านั้น (เมื่อพวกเขาต้องการ 2 รายการที่มีการนับ 2 และแยก id ของตัวอย่างที่ให้ไว้)?
Ian

1
เอียนขอบคุณสำหรับความคิดเห็น คุณดำเนินการอ้างสิทธิ์ของคุณกับฐานข้อมูล MS SQL 2000 หรือไม่
เดเมียน

7

ฉันจะทำสิ่งที่ชอบ:

select
 A.id, A.age, B.count 
from 
 students A, 
 (select age, count(*) as count from students group by age) B
where A.age=B.age;


1

และถ้าข้อมูลในคอลัมน์ "อายุ" มีบันทึกที่คล้ายกัน (เช่นหลายคนอายุ 25 ปีและอีก 32 คนเป็นต้น) จะทำให้เกิดความสับสนในการนับจำนวนนักเรียนแต่ละคนให้ถูกต้อง เพื่อหลีกเลี่ยงมันฉันเข้าร่วมตารางในรหัสนักศึกษาเช่นกัน

SELECT S.id, S.age, C.cnt
FROM Students S 
INNER JOIN (SELECT id, age, count(age) as cnt  FROM Students GROUP BY student,age) 
C ON S.age = C.age *AND S.id = C.id*
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.