postgresql-sql-「true」値の数


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

上記の表で、私が行う場合:

select count(*), count(myCol);

私は得る 6, 5

5nullエントリをカウントしないので、取得します。

真の値の数もカウントするにはどうすればよいですか(例では3)?

(これは単純化であり、実際にはcount関数内ではるかに複雑な式を使用しています)

概要の編集:クエリにプレーンなcount(*)も含めたいので、where句を使用できません


't'はTrueを表し、 'f'はFalseを表しますか?または、SELECT COUNT(DISTINCT myCol)のようなものを探していますか?
Shamit Verma

私の2番目の例を見てWHERE myCol = trueください。必要に応じてそこにをスローでき*,ます。最初の例を削除すると、数値が返されます。
vol7ron、2011年

@Shamit ye​​s tはtrueを表し、fはfalseを表します。質問を更新しました
EoghanM

あなたの質問/クエリを単純化しない方がよいかもしれません...あなたの要件はより良いパフォーマンスの可能性を制限し、人々は非効率的な答えで応答しています。
vol7ron、2011年

1
私の弁護では、@ vol7ronがわかりやすい質問をするためにいくつかの簡略化が必要ですが、はい、私が最初に投稿したときは、単純化しすぎました。
EoghanM 2011年

回答:


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 2011年

2
また、count(.. THEN true else else null)の代わりにsum(.. THEN 1 ELSE 0)を実行した理由は何ですか?
EoghanM 2011年

5
いいえ...どの値がcount()でカウントされるのかわからなかっただけです...そしてその合計がトリックを行うことを知っていました。しかし注意してください:考え直して、null値のみのsum()はnullを返すと私は信じています。したがって、それはCOALESCE(sum(...)、0)である必要があります。つまり、count()の方が優れています。
ダニエル

1
@EoghanM、キャストに関する短い回答をご覧ください。
ドウェイントーウェル、2014年

1
実際に省略ELSE nullして同じ結果を得ることができます。
200_成功2016年

91

ブール値を整数にキャストして合計します。

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

あなたが得る6,3


3
Plus1:素敵なハック!これはおそらく私のソリューションよりもさらに高速です。
ダニエル

1
これは最善かつ最短のソリューションです(他の多くのプログラミング環境やソフトウェアと同等です)。もっと投票する必要があります

3
「intとcountへのキャスト」は明らかに最も簡潔ですが、それが最善とは限りません。多くの環境ではfalse / trueに0/1表現を使用しますが、多くの場合、-1を含めて0 / non-zeroを使用するため、これを支持することはしません。私はそれが「ハック」であることに同意し、キャストは「ハック」でない場合には十分危険です。反対票を投じないが、再び支持しない。
Andrew Wolfe

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の最良の答えであり、信じられないほど高速です
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は、[ブール式]がfalseの場合nullif([boolean expression], true)に返されfalsenulltrueの場合に返されるため、false値をカウントします。あなたが欲しいと思うnullif([boolean expression], false)
rjmunro 2015

うん、「一般的な」ケースは逆になります。修繕。ありがとう。
wrobell 2015

1
ゆく。その修正は本当に混乱しています。AFAICS、trueまたはnull値をカウントするようになりました。いつも持っているように言い換えると、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);

これは間違いなく私のものより良い解決策です:)
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句を使用できません。
EoghanM 2011年

7

ブールフィールドを整数に変換し、合計を実行するだけです。これはpostgresqlで動作します:

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

お役に立てば幸いです。


他のソリューションよりも高速でも正確でもありません。intをブール値として使用する方が直感的である場合、あなたはOracleから来たと思います。
ダニエル

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 2011年

はい。ただし、を追加するだけでさらに制限できますWHERE myCol = true。2番目の例を提供したのは、それがより高速であるからではなく、多くのユーザーが慣れていないか、知らないPostgresのウィンドウ処理機能の教育的な部分として提供しました。
vol7ron 2011年

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

ブールの3つの可能な状態(false、true、0)を3つの行にグループ化し、日などの別の列と一緒にグループ化する場合に特に便利です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.