2

my_objには、2つの整数フィールドがあります。

(value_a integer, value_b integer);

私は何回計算しようとしますvalue_a = value_b、そして私はこの比率をパーセントで表現したいと思います。これは私が試したコードです:

select sum(case when o.value_a = o.value_b then 1 else 0 end) as nb_ok,
       sum(case when o.value_a != o.value_b then 1 else 0 end) as nb_not_ok,
       compute_percent(nb_ok,nb_not_ok)
from  my_obj as o
group by o.property_name;

compute_percent単純に行うstored_procedureです(a * 100) / (a + b)

しかし、PostgreSQLは列nb_okが存在しないと文句を言います。
どのようにそれを適切に行いますか?

Ubuntu12.04でPostgreSQL9.1を使用しています。

4

3 に答える 3

3

この質問には、見た目以上のものがあります。

シンプルバージョン

これははるかに高速で簡単です。

SELECT property_name
      ,(count(value_a = value_b OR NULL) * 100) / count(*) AS pct
FROM   my_obj
GROUP  BY 1;

結果:

property_name | pct
--------------+----
 prop_1       | 17
 prop_2       | 43

どのように?

  • このための関数はまったく必要ありません。

  • value_b(最初から始める必要はありませんが)カウントして合計を計算する代わりに、合計に使用count(*)します。より速く、より簡単に。

  • これは、値がないことを前提としていNULLます。つまり、両方の列が定義されていNOT NULLます。質問に情報がありません。
    そうでない場合、元のクエリはおそらくあなたが思っていることをしていないでしょう。いずれかの値がNULLの場合、バージョンはその行をまったくカウントしません。この方法で、ゼロ除算の例外を引き起こすこともできます。
    このバージョンはNULLでも機能します。count(*)値に関係なく、すべての行のカウントを生成します。

  • カウントの仕組みは次のとおりです。

     TRUE  OR NULL = TRUE
     FALSE OR NULL = NULL
    

    count()NULL値を無視します。Voilá。

  • 演算子の優先順位は、の=前にバインドすることを決定しORます。かっこを追加して、わかりやすくすることができます。

    count ((value_a = value_b) OR FALSE)
    
  • あなたはで同じことをすることができます

    count NULLIF(<expression>, FALSE)
    
  • の結果タイプcount()bigintデフォルトです。
    除算bigint / bigintは、小数桁を切り捨てます

小数桁を含める

(小数桁で)を使用100.0して、計算を強制しnumeric、それによって小数桁を保持します。
あなたはこれで使用したいかもしれませんround()

SELECT property_name
      ,round((count(value_a = value_b OR NULL) * 100.0) / count(*), 2) AS pct
FROM   my_obj
GROUP  BY 1;

結果:

property_name | pct
--------------+-------
 prop_1       | 17.23
 prop_2       | 43.09

余談ですが、私はの代わり
に使用します。PostgreSQLでは引用符で囲まれていない大文字と小文字が混在する識別子を使用しないでください。私はこの愚かさから来る絶望的な質問をあまりにも多く見ました。私が何について話しているのか疑問に思われる場合は、マニュアルの「識別子とキーワード」の章をお読みください。value_avalueA

于 2013-03-27T02:22:30.707 に答える
2

おそらく最も簡単な方法は、with句を使用することです。

WITH data 
     AS (SELECT Sum(CASE WHEN o.valuea = o.valueb THEN 1 ELSE 0 END) AS nbOk, 
                Sum(CASE WHEN o.valuea != o.valueb THEN 1 ELSE 0 END) AS nbNotOk, 
         FROM   my_obj AS o 
         GROUP  BY o.property_name) 
SELECT nbok, 
       nbnotok, 
       Compute_percent(nbok, nbnotok) 
FROM   data
于 2013-03-26T18:32:02.117 に答える
1

このバージョンも試してみてください。

WITH all(count) as (SELECT COUNT(*)
                    FROM my_obj),
     matching(count) as (SELECT COUNT(*)
                         FROM my_obj
                         WHERE valueA = valueB)
SELECT nbOk, nbNotOk, Compute_percent(nbOk, nbNotOk)
FROM (SELECT matching.count as nbOk, all.count - matching.count as nbNotOk
      FROM all
      CROSS JOIN matching) data
于 2013-03-26T18:47:28.163 に答える