postgresql - sql - số lượng giá trị `true`


97
myCol
------
 true
 true
 true
 false
 false
 null

Trong bảng trên, nếu tôi làm như sau:

select count(*), count(myCol);

tôi có 6, 5

Tôi nhận được 5vì nó không tính mục nhập rỗng.

Làm cách nào để tôi cũng đếm số lượng giá trị đúng (3 trong ví dụ)?

(Đây là một sự đơn giản hóa và tôi thực sự đang sử dụng một biểu thức phức tạp hơn nhiều trong hàm đếm)

Chỉnh sửa tóm tắt: Tôi cũng muốn bao gồm một số đơn giản (*) trong truy vấn, vì vậy không thể sử dụng mệnh đề where


Có phải 't' là viết tắt của True anf 'f' là False? Hoặc bạn đang tìm kiếm một cái gì đó như CHỌN ĐẾM (DISTINCT myCol).
Shamit Verma

hãy xem ví dụ thứ hai của tôi, bạn có thể ném WHERE myCol = truevào đó nếu bạn muốn và nếu bạn xóa cái đầu tiên, *,nó sẽ chỉ trả lại số.
vol7ron

@Shamit có t là viết tắt của true và f là viết tắt của false, tôi đã cập nhật câu hỏi
EoghanM

Bạn cũng có thể không đơn giản hóa câu hỏi / truy vấn của mình ... các yêu cầu của bạn hạn chế khả năng hoạt động tốt hơn và mọi người đang phản hồi với các câu trả lời không hiệu quả, những câu trả lời này đang bị xáo trộn mà không có lý do chính đáng.
vol7ron

1
@ vol7ron trong lời bào chữa của tôi phải có một số đơn giản hóa để đặt một câu hỏi dễ hiểu, nhưng có, tôi đã đơn giản hóa quá mức khi tôi đăng ban đầu.
EoghanM

Câu trả lời:


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

hoặc, như bạn đã tự mình tìm ra:

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

Đây là một bản hack tốt và nhận được câu trả lời phù hợp từ tôi. Tôi sẽ chấp nhận nó trừ khi ai đó đưa ra một giải pháp ngắn hơn?
EoghanM

2
ngoài ra, bất kỳ lý do nào tại sao bạn lại làm sum (.. THEN 1 ELSE 0) thay vì count (.. THEN true else null)?
EoghanM

5
Không ... chỉ là tôi không chắc giá trị nào sẽ đếm () đếm được ... và tôi biết rằng tổng đó đã thành công. Nhưng hãy cẩn thận: Tôi tin rằng sum () chỉ trên giá trị null sẽ trả về null, vì vậy nó phải là COALESCE (sum (...), 0) đối với bạn, hoặc nói cách khác, count () tốt hơn,
Daniel

1
@EoghanM, xem câu trả lời ngắn hơn liên quan đến diễn viên.
Dwayne Towell

1
Bạn thực sự có thể bỏ qua ELSE nullđể có được kết quả tương tự.
200_thành công

91

Truyền Boolean thành một số nguyên và tổng.

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

Bạn nhận được 6,3.


3
Plus1: Hack tốt! Điều này có lẽ thậm chí còn nhanh hơn giải pháp của tôi.
Daniel

1
Đây là giải pháp tốt nhất và ngắn nhất (và có tính tương đương trong nhiều môi trường lập trình và phần mềm khác). Nên up-bình chọn nhiều hơn

3
'Cast to int and count' rõ ràng là ngắn gọn nhất, nhưng điều đó không làm cho nó tốt nhất. Tôi sẽ không xác nhận điều này, bởi vì trong khi nhiều môi trường sử dụng biểu diễn 0/1 cho false / true, nhiều môi trường sử dụng 0 / khác 0, bao gồm cả -1. Tôi đồng ý rằng đó là một "vụ hack", và các lượt diễn đủ nguy hiểm khi chúng không phải là "hack". Sẽ không tán thành nhưng một lần nữa, sẽ không tán thành.
Andrew Wolfe

79

Vì PostgreSQL 9.4 có FILTERmệnh đề , cho phép truy vấn rất ngắn gọn để đếm các giá trị thực:

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

Truy vấn ở trên là một ví dụ tồi trong đó mệnh đề WHERE đơn giản là đủ và chỉ để trình bày cú pháp. Khi mệnh đề FILTER tỏa sáng là nó dễ dàng kết hợp với các tập hợp khác:

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

Mệnh đề đặc biệt hữu ích cho các tổng hợp trên một cột sử dụng một cột khác làm vị từ, đồng thời cho phép tìm nạp các tổng hợp được lọc khác nhau trong một truy vấn:

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

2
Đây là câu trả lời tốt nhất cho PG> 9.4 và là cực kỳ nhanh chóng
Juan Ricardo

47

có lẽ, cách tiếp cận tốt nhất là sử dụng hàm nullif.

nói chung

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

hay nói ngắn gọn là

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
"Nói chung" của bạn có vẻ sai: AFAICS, nullif([boolean expression], true)sẽ trả về falsenếu [biểu thức boolean] là sai và nullnếu nó là đúng, vì vậy bạn sẽ đếm các giá trị sai. Tôi nghĩ bạn muốn nullif([boolean expression], false).
rjmunro

vâng, trường hợp "chung chung" nên ngược lại. đã sửa. cảm ơn.
wrobell,

1
Yuk. Việc sửa chữa đó thực sự khó hiểu. AFAICS, bây giờ nó sẽ đếm các giá trị true hoặc null. Tôi nghĩ rằng việc diễn đạt lại nó để bạn luôn có sẽ nullif([boolean expression], false)giúp bạn đọc dễ dàng hơn nhiều. Sau đó bạn có thể thay đổi một phần biểu thức boolean được bất cứ điều gì bạn thích, trong trường hợp này myCol = trueđể đếm giá trị đích thực, hoặc myCol = falseđể đếm giá trị sai, hoặc name='john'để đếm người ta gọi john, vv
rjmunro

19

Giải pháp ngắn nhất và lười nhất (không ép kiểu) sẽ là sử dụng công thức:

SELECT COUNT(myCol OR NULL) FROM myTable;

Hãy tự mình thử:

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

cho cùng một kết quả hơn

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

Đây chắc chắn là một giải pháp đẹp hơn so với tôi :)
Daniel

Câu trả lời rất sâu sắc.
lucasarruda

7

Trong MySQL, bạn cũng có thể làm điều này:

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

Tôi nghĩ rằng trong Postgres, điều này hoạt động:

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

hoặc tốt hơn (để tránh :: và sử dụng cú pháp SQL chuẩn):

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

Đây là giải pháp đơn giản nhất mà tôi từng thấy ^ _ ^
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

Hoặc có thể điều này

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 Nếu myColbiểu thức là boolean, bạn có thể thay thế séc bằngwhere (myCol)
ypercubeᵀᴹ

xin lỗi, tôi đã đơn giản hóa quá mức ví dụ của mình: Tôi không thể sử dụng mệnh đề where vì tôi cũng muốn trả về tổng số đại diện cho tổng số hàng, cũng như tổng số các giá trị thực.
EoghanM

7

Đơn giản chỉ cần chuyển đổi trường boolean thành số nguyên và tính tổng. Điều này sẽ hoạt động trên postgresql:

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

Hy vọng rằng sẽ giúp!


Nó không nhanh hơn cũng không chính xác hơn các giải pháp khác. Tôi tin rằng bạn đến từ Oracle khi sử dụng ints vì boolean trực quan hơn cho bạn.
Daniel

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

Đây là một cách với chức năng Windowing:

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

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

xin lỗi, tôi không thể trả về nhiều hàng cho ví dụ phức tạp hơn mà tôi đang áp dụng giải pháp này.
EoghanM

Có, nhưng bạn có thể hạn chế thêm bằng cách thêm WHERE myCol = true. Tôi cung cấp ví dụ thứ hai không phải vì nó nhanh hơn mà là một phần giáo dục cho các chức năng cửa sổ của Postgres, điều mà nhiều người dùng không thoải mái hoặc không biết về nó.
vol7ron

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

sẽ nhóm 3 trạng thái có thể có của bool (false, true, 0) thành ba hàng, đặc biệt tiện lợi khi nhóm cùng với một cột khác như ngày

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.