web-dev-qa-db-ja.com

行のないカウントから0値を取得します

私はSELECTを持っています:

SELECT c FROM (
    SELECT "candidate_id" as id, count("candidate_id") as c
    FROM "Applicaions"
    GROUP BY "candidate_id"
) as s WHERE id= _SOME_ID_;

しかし、これはcount > 0count = 0何も返しません。どうすれば入手することができますか 0アプリケーションがない「候補者」の場合は?

「候補者」の表があります。
候補者にアプリケーションがないか、存在しない場合、私は0を取得する必要があります。

編集

私が今持っています:

SELECT COALESCE ((SELECT count("candidate_id") as c
FROM "Applicaions" WHERE "candidate_id"=_SOME_ID_
GROUP BY "candidate_id"), 0);

それは完全に動作します。しかし、それをより簡単に書くことは可能ですか、これが最善の解決策ですか?インデックスを作成する必要がありますか?

21
Miko Kronn

PostgreSQLでCOALESCE関数を使用する必要があります http://developer.postgresql.org/pgdocs/postgres/functions-conditional.html

基本的に、SQLにNULLsの処理方法を伝える必要があります。つまり、NULL0を返す場合。

16
diagonalbatman

できません。

候補者にアプリケーションがない場合、候補者を読む方法はありませんcandidate_id

候補者がApplicationsテーブルに存在しなくても存在することをどのように知っていますか?

あなたのコード例では、候補はありませんであり、したがって、特定の候補がゼロのアプリケーションを持っているとは言えません。そのロジックにより、アプリケーションがゼロの候補が無限に存在します。

この情報を得るには、候補者の表が必要です... IDで候補者を求めているため、候補者が存在すると推定するつもりがなければ、

[〜#〜]編集[〜#〜]

これでCandidatesテーブルができたので、これを行うことができます:

SELECT c.ID, (SELECT COUNT(a.*) FROM Applications a WHERE a.candidate_id = c.ID) 
FROM Candidate c
WHERE ....
5
Matthew

this related one の著者がこの質問を知ったのは、ここを読んだ後は問題を解決できないと信じさせられたからです。まあ、それはできます。

この回答はほぼ2年前のものですが、最終的な質問はまだ保留されていました。

クエリ

それをより簡単に書くことは可能ですか、これが最善の解決策ですか?

シングルIDをテストするには、見つけたクエリが適切です。簡略化できます:

_SELECT coalesce((SELECT count(candidate_id)
FROM   "Applications" WHERE candidate_id = _SOME_ID_), 0) AS c;
_
  • WHERE条件は単一の_candidate_id_に制限され、SELECTリストには単一の集約関数があります。 _GROUP BY candidate_id_は冗長でした。

  • 列のエイリアスはCOALESCE()によって飲み込まれました。結果の列に名前を付ける場合は、エイリアスを最後に移動します。

  • 通常の小文字の識別子には二重引用符は必要ありません。

別の、よりきれいな(IMHO)フォームは_LEFT JOIN_を使用することです:

_SELECT count(a.candidate_id) AS c
FROM  (SELECT _SOME_ID_ AS candidate_id) x
LEFT   JOIN "Applicaions" a USING (candidate_id)
_

これは複数のIDでもうまく機能します:

_WITH x(candidate_id) AS (
   VALUES
     (123::bigint)
    ,(345)
    ,(789)
   )
SELECT x.candidate_id, count(a.candidate_id) AS c
FROM   x
LEFT   JOIN "Applicaions" a USING (candidate_id)
GROUP  BY x.candidate_id;
_
  • _LEFT JOIN_は通常、複数のWHERE句またはIN式よりも長いリストの方が高速です。

または、テーブルのすべての行 "候補"の場合:

_SELECT x.candidate_id, count(a.candidate_id) AS c
FROM   "Candidates" x
LEFT   JOIN "Applications" a USING (candidate_id)
GROUP  BY x.candidate_id;
_

インデックス

インデックスを作成する必要がありますか?

読み取りパフォーマンスが重要であり、テーブルに数行以上の行が含まれている場合間違いなく次の形式のインデックスが必要です。

_CREATE INDEX foo_idx ON "Applications" (candidate_id);
_

これは_"Candidates".candidate_id_を参照する外部キー列のようですので、おそらく最初はそれを持っているはずです。

3

おそらく:

SELECT CASE c WHEN NULL THEN 0 ELSE c END
    FROM (
    SELECT "candidate_id" as id, count("candidate_id") as c
    FROM "Applicaions"
    GROUP BY "candidate_id"
) as s WHERE id= _SOME_ID_;

「何もない」が本当にNULLであると仮定

2
farfromhome

このステートメントは使用できません:

SELECT count("candidate_id") as c
FROM "Applicaions" WHERE "candidate_id"=_SOME_ID_
GROUP BY "candidate_id"

Count()が返され、サブクエリは必要ありません。

編集:マシューPKは正しいですし、アンディPatonはより良い答えを持っています;)

1
Marek Tuchalski

次のようなものを試すことができます(候補テーブルがあり、テーブル/列名の私の仮定が正しいと仮定します)。

SELECT c FROM (
 SELECT "Candidate"."candidate_id" as id, 
 count("Applications"."candidate_id") as c
 FROM "Candidate" LEFT JOIN "Applications" 
 ON "Applications"."candidate_id"="Candidate"."id"     
GROUP BY "Candidate"."candidate_id" ) as s WHERE id= _SOME_ID_;
1
wllmsaccnt