postgresql - sql - จำนวนค่า "จริง"


98
myCol
------
 true
 true
 true
 false
 false
 null

ในตารางด้านบนถ้าฉันทำ:

select count(*), count(myCol);

ฉันเข้าใจ 6, 5

ฉันเข้าใจ5ว่ามันไม่นับรายการว่าง

ฉันจะนับจำนวนค่าจริงได้อย่างไร (3 ในตัวอย่าง)

(นี่เป็นการทำให้เข้าใจง่ายและฉันใช้นิพจน์ที่ซับซ้อนกว่านี้มากในฟังก์ชัน count)

แก้ไขสรุป: ฉันต้องการรวมจำนวนธรรมดา (*) ในแบบสอบถามดังนั้นจึงไม่สามารถใช้คำสั่ง where ได้


't' ย่อมาจาก True anf 'f' for False หรือไม่? หรือคุณกำลังมองหาบางอย่างเช่น SELECT COUNT (DISTINCT myCol)
Shamit Verma

ลองดูตัวอย่างที่สองของฉันคุณสามารถโยนWHERE myCol = trueเข้าไปที่นั่นได้ถ้าคุณต้องการและถ้าคุณลบตัวแรกออก*,มันก็จะคืนค่า
vol7ron

@Shamit ใช่ t หมายถึงจริงและ f ย่อมาจากเท็จฉันได้อัปเดตคำถามแล้ว
EoghanM

คุณอาจไม่ทำให้คำถาม / ข้อสงสัยของคุณง่ายขึ้นเช่นกัน ... ความต้องการของคุณ จำกัด ความเป็นไปได้ในการทำงานที่ดีขึ้นและผู้คนกำลังตอบสนองด้วยคำตอบที่ไม่มีประสิทธิภาพซึ่งกำลังได้รับผลกระทบอย่างไม่มีเหตุผล
vol7ron

1
@ vol7ron ในการป้องกันของฉันจะต้องมีความเรียบง่ายบางอย่างเพื่อที่จะถามคำถามที่เข้าใจได้ แต่ใช่ฉันย่อขนาดมากเกินไปเมื่อฉันโพสต์ครั้งแรก
EoghanM

คำตอบ:


136
SELECT COALESCE(sum(CASE WHEN myCol THEN 1 ELSE 0 END),0) FROM <table name>

หรือตามที่คุณค้นพบด้วยตัวคุณเอง:

SELECT count(CASE WHEN myCol THEN 1 END) FROM <table name>

นี่เป็นการแฮ็กที่ดีและได้รับคำตอบที่ถูกต้องจากฉัน ฉันจะยอมรับมันเว้นแต่จะมีใครคิดวิธีแก้ปัญหาที่สั้นกว่านี้?
EoghanM

2
ด้วยเหตุใดคุณจึงรวม (.. แล้ว 1 ELSE 0) แทนการนับ (.. แล้ว true else null)?
EoghanM

5
ไม่ ... เป็นเพียงว่าฉันไม่แน่ใจว่าค่าใดจะนับ () นับ ... และฉันรู้ว่าผลรวมนั้นเป็นเคล็ดลับ แต่ระวัง: ในความคิดที่สองฉันเชื่อว่า sum () มากกว่าค่า null เท่านั้นที่จะคืนค่า null ดังนั้นจึงควรเป็น COALESCE (sum (... ), 0) สำหรับคุณหรือกล่าวอีกนัยหนึ่งคือ count () จะดีกว่า
Daniel

1
@EoghanM ดูคำตอบสั้น ๆ เกี่ยวกับนักแสดง
Dwayne Towell

1
คุณสามารถละเว้นELSE nullเพื่อให้ได้ผลลัพธ์เดียวกัน
200_success

92

ร่ายบูลีนเป็นจำนวนเต็มและผลรวม

SELECT count(*),sum(myCol::int);

6,3คุณจะได้รับ


3
Plus1: แฮ็คได้ดี! นี่อาจเร็วกว่าวิธีแก้ปัญหาของฉันด้วยซ้ำ
Daniel

1
นี่เป็นทางออกที่ดีที่สุดและสั้นที่สุด (และมีความเท่าเทียมกันในสภาพแวดล้อมการเขียนโปรแกรมและซอฟต์แวร์อื่น ๆ ) ควรได้รับการโหวตมากกว่านี้

3
'cast to int and count' ชัดเจนที่สุด แต่ก็ไม่ได้ทำให้ดีที่สุด ฉันจะไม่รับรองสิ่งนี้เพราะในขณะที่สภาพแวดล้อมจำนวนมากใช้การแทนค่า 0/1 สำหรับเท็จ / จริงหลายรายการใช้ 0 / ไม่ใช่ศูนย์รวมถึง -1 ฉันยอมรับว่ามันเป็นการ "แฮ็ก" และการแคสต์มีความเสี่ยงมากพอที่จะไม่ใช่ "แฮ็ก" จะไม่ลงคะแนน แต่อีกครั้งจะไม่รับรอง
Andrew Wolfe

86

เนื่องจาก PostgreSQL 9.4 มีFILTERอนุประโยคซึ่งช่วยให้การสืบค้นกระชับมากสามารถนับค่าที่แท้จริงได้:

select count(*) filter (where myCol)
from tbl;

ข้อความค้นหาข้างต้นเป็นตัวอย่างที่ไม่ดีซึ่งคำสั่ง WHERE แบบธรรมดาจะเพียงพอและมีไว้สำหรับการสาธิตไวยากรณ์เท่านั้น ในกรณีที่คำสั่ง FILTER เปล่งประกายคือการรวมกับมวลรวมอื่น ๆ ทำได้ง่าย:

select count(*), -- all
       count(myCol), -- non null
       count(*) filter (where myCol) -- true
from tbl;

อนุประโยคมีประโยชน์อย่างยิ่งสำหรับการรวมในคอลัมน์ที่ใช้คอลัมน์อื่นเป็นเพรดิเคตในขณะที่อนุญาตให้ดึงข้อมูลรวมที่กรองแตกต่างกันออกไปในแบบสอบถามเดียว:

select count(*),
       sum(otherCol) filter (where myCol)
from tbl;

2
นี่คือคำตอบที่ดีที่สุดสำหรับ PG> 9.4 และเร็วอย่างไม่น่าเชื่อ
Juan Ricardo

47

วิธีที่ดีที่สุดคือการใช้ฟังก์ชัน nullif

โดยทั่วไป

select
    count(nullif(myCol = false, true)),  -- count true values
    count(nullif(myCol = true, true)),   -- count false values
    count(myCol);

หรือเรียกสั้น ๆ

select
    count(nullif(myCol, true)),  -- count false values
    count(nullif(myCol, false)), -- count true values
    count(myCol);

http://www.postgresql.org/docs/9.0/static/functions-conditional.html


2
"โดยทั่วไป" ของคุณดูผิด: AFAICS nullif([boolean expression], true)จะส่งคืนfalseหาก [นิพจน์บูลีน] เป็นเท็จและnullถ้าเป็นจริงคุณจะนับค่าเท็จ nullif([boolean expression], false)ฉันคิดว่าคุณต้องการ
rjmunro

ใช่กรณี "ทั่วไป" ควรเป็นวิธีอื่น แก้ไขแล้ว. ขอบคุณ.
wrobell

1
ยูค. การแก้ไขนั้นสับสนจริงๆ AFAICS ตอนนี้จะนับค่าจริงหรือค่าว่าง ฉันคิดว่าการเรียบเรียงใหม่เพื่อให้คุณnullif([boolean expression], false)อ่านง่ายขึ้นมาก จากนั้นคุณสามารถเปลี่ยนส่วนนิพจน์บูลีนให้เป็นอะไรก็ได้ที่คุณต้องการในกรณีนี้myCol = trueจะนับค่าจริงหรือmyCol = falseนับค่าเท็จหรือname='john'นับคนที่เรียกว่าจอห์นเป็นต้น
rjmunro

20

วิธีแก้ปัญหาที่สั้นและขี้เกียจที่สุด (ไม่ต้องหล่อ) คือการใช้สูตร:

SELECT COUNT(myCol OR NULL) FROM myTable;

ลองด้วยตัวคุณเอง:

SELECT COUNT(x < 7 OR NULL)
   FROM GENERATE_SERIES(0,10) t(x);

ให้ผลลัพธ์เดียวกันกับ

SELECT SUM(CASE WHEN x < 7 THEN 1 ELSE 0 END)
   FROM GENERATE_SERIES(0,10) t(x);

นี่เป็นทางออกที่ดีกว่าของฉันแน่นอน :)
Daniel

คำตอบที่ลึกซึ้งมาก
lucasarruda

7

ใน MySQL คุณสามารถทำได้เช่นกัน:

SELECT count(*) AS total
     , sum(myCol) AS countTrue --yes, you can add TRUEs as TRUE=1 and FALSE=0 !!
FROM yourTable
;

ฉันคิดว่าใน Postgres ใช้งานได้:

SELECT count(*) AS total
     , sum(myCol::int) AS countTrue --convert Boolean to Integer
FROM yourTable
;

หรือดีกว่า (เพื่อหลีกเลี่ยง :: และใช้ไวยากรณ์ SQL มาตรฐาน):

SELECT count(*) AS total
     , sum(CAST(myCol AS int)) AS countTrue --convert Boolean to Integer
FROM yourTable
;

นี่เป็นวิธีแก้ปัญหาที่ง่ายที่สุดที่ฉันเคยเห็น ^ _ ^
JiaHao Xu

7
select f1,
       CASE WHEN f1 = 't' THEN COUNT(*) 
            WHEN f1 = 'f' THEN COUNT(*) 
            END AS counts,
       (SELECT COUNT(*) FROM mytable) AS total_counts
from mytable
group by f1

หรืออาจจะเป็นแบบนี้

SELECT SUM(CASE WHEN f1 = 't' THEN 1 END) AS t,
       SUM(CASE WHEN f1 = 'f' THEN 1 END) AS f,
       SUM(CASE WHEN f1 NOT IN ('t','f') OR f1 IS NULL THEN 1 END) AS others,
       SUM(CASE WHEN f1 IS NOT NULL OR f1 IS NULL THEN 1 ELSE 0 END) AS total_count
FROM mytable;

+1 หากmyColนิพจน์เป็นบูลีนคุณสามารถแทนที่การตรวจสอบด้วยwhere (myCol)
ypercubeᵀᴹ

ขอโทษที่ฉันย่อตัวอย่างมากเกินไป: ฉันไม่สามารถใช้ where clause ได้เพราะฉันต้องการส่งคืนการนับรวมที่แสดงจำนวนแถวทั้งหมดรวมทั้งการนับค่าจริงด้วย
EoghanM

7

เพียงแค่แปลงฟิลด์บูลีนเป็นจำนวนเต็มและทำผลรวม สิ่งนี้จะใช้ได้กับ postgresql:

select sum(myCol::int) from <table name>

หวังว่าจะช่วยได้!


ไม่เร็วหรือแม่นยำกว่าโซลูชันอื่น ๆ ฉันเชื่อว่าคุณมาจาก Oracle เมื่อใช้ ints เนื่องจากบูลีนนั้นใช้งานง่ายกว่าสำหรับคุณ
Daniel

4
SELECT count(*)         -- or count(myCol)
FROM   <table name>     -- replace <table name> with your table
WHERE  myCol = true;

นี่คือวิธีที่มีฟังก์ชัน Windowing:

SELECT DISTINCT *, count(*) over(partition by myCol)
FROM   <table name>;

-- Outputs:
-- --------------
-- myCol | count
-- ------+-------
--  f    |  2
--  t    |  3
--       |  1

ขออภัยฉันไม่สามารถส่งคืนหลายแถวสำหรับตัวอย่างที่ซับซ้อนกว่าที่ฉันใช้วิธีนี้กับ
EoghanM

ใช่ แต่คุณสามารถ จำกัด WHERE myCol = trueได้ต่อไปโดยเพียงแค่การเพิ่ม ฉันให้ตัวอย่างที่สองไม่ใช่เพราะมันเร็วกว่า แต่เป็นชิ้นส่วนเพื่อการศึกษาสำหรับฟังก์ชันการหน้าต่างของ Postgres ซึ่งผู้ใช้หลายคนไม่พอใจหรือไม่รู้
vol7ron

0
select count(myCol)
from mytable
group by myCol
;

จะจัดกลุ่ม 3 สถานะที่เป็นไปได้ของบูล (เท็จ, จริง, 0) เป็นสามแถวซึ่งมีประโยชน์อย่างยิ่งเมื่อรวมกลุ่มกับคอลัมน์อื่นเช่นวัน

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