ส่งคืนการนับสำหรับหลายช่วงในคำสั่ง SELECT เดียว


9

ฉันมีตารางฐานข้อมูล Postgres fooที่มีคอลัมน์สำหรับscoreช่วงนั้นตั้งแต่ 0 - 10 ฉันต้องการให้แบบสอบถามส่งคืนจำนวนคะแนนทั้งหมดจำนวนคะแนนระหว่าง 0 ถึง 3 จำนวนคะแนนระหว่าง 4 และ 6 และจำนวนคะแนนระหว่าง 7 และ 10 สิ่งที่ชอบดังต่อไปนี้:

SELECT
  COUNT(*) as total,
  COUNT(
    SELECT * from foo where score between 0 and 3;
  ) as low,
  COUNT(
    SELECT * from foo where score between 4 and 6;
  ) as mid,
  COUNT(
    SELECT * from foo where score between 7 and 10;
  ) as high
FROM foo;

ฉันลองสิ่งนี้ แต่ได้รับข้อผิดพลาดSELECTในCOUNTข้อความสั่ง ความคิดใดที่ฉันสามารถทำได้ ฉันแน่ใจว่ามีวิธีที่ง่ายที่สุดใน Postgres ฉันไม่สามารถเข้าใจเงื่อนไขที่ถูกต้องสำหรับ Google

คำตอบ:


7

เพียงใช้SUM()ข้อความสั่งแบบมีเงื่อนไขต่อคอลัมน์สำหรับแต่ละช่วงตัวเลข ผลรวมสามารถรวมกันได้โดยใช้เพียงแค่SUM(1)สมมติว่าข้อมูลทั้งหมดในตารางอยู่ในช่วงใดช่วงหนึ่ง - ถ้าไม่ใช่ให้ จำกัด เฉพาะกับคนอื่น ๆ

select sum(case when score between 0 and 3 then 1 else 0 end) as minrange,
       sum(case when score between 4 and 6 then 1 else 0 end) as midrange,
       sum(case when score between 7 and 10 then 1 else 0 end) as maxrange,
       sum(1) as total
from foo;

การเชื่อมโยง SQL ซอ


8

FILTERข้อรวมใน Postgres 9.4+

ตั้งแต่ Postgres 9.4 มีวิธีที่สะอาดและรวดเร็ว (มาตรฐาน SQL):

SELECT count(*) FILTER (WHERE score BETWEEN 0 AND 3)  AS low
     , count(*) FILTER (WHERE score BETWEEN 4 AND 7)  AS mid
     , count(*) FILTER (WHERE score BETWEEN 8 AND 10) AS high
     , count(*)                                       AS total
FROM   foo;

totalเพิ่มขึ้นlow, midและhighเว้นแต่เป็นโมฆะหรืออื่น ๆ ที่ค่าที่มีส่วนเกี่ยวข้อง

ลิงค์:

อ่านด้านล่าง

Postgres 9.3-

มีสองสามเทคนิค:

@PhilจัดทำCASEแถลงการณ์มาตรฐาน(ยกเว้นsum(1)ซึ่งไม่ใช่วิธีมาตรฐาน) ฉันชอบที่จะใช้แบบฟอร์มที่สั้นกว่า:

SELECT count(score BETWEEN 0 AND 3  OR NULL) AS low
     , count(score BETWEEN 4 AND 6  OR NULL) AS mid
     , count(score BETWEEN 7 AND 10 OR NULL) AS high
     , count(*)                              AS total
FROM   foo;

หากค่าของคุณเป็นไปตามที่กำหนดไว้ในคำถามของคุณ (เท่านั้น0- 10เป็นไปได้) ให้ลดความซับซ้อนเพิ่มเติม:

SELECT count(score < 4 OR NULL)             AS low
     , count(score BETWEEN 4 AND 6 OR NULL) AS mid
     , count(score > 6 OR NULL)             AS high
     , count(*)                             AS total
FROM   foo;

สั้นกว่าเล็กน้อยเร็วกว่า

ความแตกต่างที่ลึกซึ้ง

มีความแตกต่างเมื่อเทียบกับsum()ในคำตอบของฟิล :

  • ที่สำคัญที่สุดตามเอกสาร :

    ควรสังเกตว่ายกเว้นcountฟังก์ชั่นเหล่านี้จะคืนค่าเป็นศูนย์เมื่อไม่มีการเลือกแถว โดยเฉพาะอย่างยิ่งsumไม่มีแถวที่ส่งคืนค่า null ไม่เป็นศูนย์อย่างที่คาดไว้ ...

  • count(*) เป็นวิธีมาตรฐานและเร็วกว่าsum(1)เล็กน้อย อีกครั้ง null กับ 0 ใช้

ทั้งการค้นหาเหล่านี้ (รวมทั้งฟิล) totalนับเป็นโมฆะค่า หากไม่พึงประสงค์ให้ใช้แทน:

count(score) AS total_not_null

SQL Fiddleใน pg 9.3
db <> ซอที่นี่ในหน้า 10

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.