postgresql - sql - кількість "справжніх" значень


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

У наведеній вище таблиці, якщо я це роблю:

select count(*), count(myCol);

я отримав 6, 5

Я отримую, 5оскільки це не враховує нульовий запис.

Як я також можу порахувати кількість справжніх значень (3 у прикладі)?

(Це спрощення, і я насправді використовую набагато складніший вираз у функції count)

Редагувати підсумок: Я також хочу включити у запит звичайний підрахунок (*), тому не можу використовувати речення where


Чи означає 't' значення True і f 'значення False? Або ви шукаєте щось на кшталт ВИБРАТИ КІЛЬКУ (ВІДМІСТИТИ myCol).
Шаміт Верма

погляньте на мій другий приклад, ви можете кинути WHERE myCol = trueтуди, якщо хочете, і якщо ви видалите перший, *,він просто поверне номер.
vol7ron

@Shamit yes t означає true, а f означає false, я оновив питання
EoghanM

Ви також можете не спрощувати своє запитання / запит ... Ваші вимоги обмежують кращі можливості продуктивності, і люди відповідають неефективними відповідями, які натрапляють без поважних причин.
vol7ron

1
@ vol7ron на мій захист має бути деяким спрощенням, щоб задати зрозуміле запитання, але так, я спростив, коли спочатку розміщував повідомлення.
EoghanM

Відповіді:


132
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
також, будь-яка причина, чому ви зробили суму (.. ПОТІМ ІНШЕ 0) замість підрахунку (.. ПОТІМ істина ще нуль)?
EoghanM

5
Ні ... просто я не був впевнений, які значення будуть враховуватися (), і я знав, що ця сума зробила трюк. Але будьте обережні: якщо добре подумати, я вважаю, що sum () лише для нульових значень поверне нуль, тому для вас це має бути COALESCE (сума (...), 0), або, іншими словами, краще count (),
Даніель

1
@EoghanM, див. Коротшу відповідь за участю акторів.
Дуейн Тауелл

1
Ви можете насправді опустити, ELSE nullщоб отримати той самий результат.
200_usccess

91

Приведіть булеве значення до цілого і суми.

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

Ви отримуєте 6,3.


3
Плюс1: Гарний хак! Це, мабуть, навіть швидше, ніж моє рішення.
Даніель

1
Це найкраще та найкоротше рішення (і має еквіваленти в багатьох інших середовищах програмування та програмному забезпеченні). Потрібно проголосувати більше

3
Очевидно, що `` акторський склад для зарахування та підрахунку '' є найбільш стислим, але це не робить його найкращим. Я б не схвалював це, тому що, хоча багато середовищ використовують подання 0/1 для false / true, багато хто використовує 0 / ненульове значення, включаючи -1. Я згоден, що це "хак", і касти досить хитрі, коли вони не "хаки". Не буде проти, але знову ж таки, не підтримає.
Ендрю Вульф

79

Починаючи з 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 і неймовірно швидка
Хуан Рікардо

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якщо [логічний вираз] має значення false, а nullякщо воно істинне, то ви будете рахувати хибні значення. Я думаю, ти хочеш nullif([boolean expression], false).
rjmunro

так, "загальний" випадок повинен бути навпаки. виправлений. Дякую.
Вробелл

1
Юк. Це виправлення дійсно бентежить. AFAICS, тепер він буде рахувати справжні або нульові значення. Я думаю, що перефразуючи його так, щоб у вас завжди було, nullif([boolean expression], false)це набагато легше читати. Потім ви можете змінити частину булевого виразу на будь-яке, що вам подобається, в цьому випадку myCol = trueпідрахувати справжні значення, або myCol = falseпідрахувати помилкові значення, або name='john'підрахувати людей, яких називають Джон тощо
rjmunro

19

Найкоротшим і ледачим рішенням (без кастингу) буде використання формули:

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);

Це, безумовно, приємніше рішення, ніж моє :)
Даніель

Дуже прониклива відповідь.
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, оскільки я також хочу повернути загальну кількість, що представляє загальну кількість рядків, а також кількість справжніх значень.
EoghanM

7

Просто перетворіть булеве поле в ціле число і складіть суму. Це буде працювати на postgresql:

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

Сподіваюся, що це допомагає!


Це не швидше і не точніше, ніж інші рішення. Я вважаю, що ви походите з Oracle, коли використання ints, оскільки логічне значення для вас є більш інтуїтивним.
Даніель

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

Ось спосіб із функцією вікон:

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 можливі стани bool (false, true, 0) у три рядки, особливо зручно при групуванні з іншим стовпцем, як день

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.