Postgresql
從 count() 確定百分比而沒有強制轉換問題
我正在嘗試執行以下查詢以提供
patients
表中具有該refinst
列值的行的百分比。我一直得到0的結果。select (count (refinst) / (select count(*) from patients) * 100) as "Formula" from patients;
該表有 15556 行,並
select count(refinst) from patients
告訴我其中 1446 行在列中有值refinst
。我想從查詢中得到的響應是 30.62(1446/15556*100=30.62XXXXX
四捨五入到小數點後兩位)。我很確定它與計數結果的數據類型有關(我假設是整數)。如果我將一個整數除以一個整數並且結果小於 0,它會被截斷為 0 對嗎?如果是這種情況,有人可以告訴我如何將計數結果轉換為小數點後 2 位的數字,以便結果也將四捨五入到小數點後 2 位?
我確信有比多個計數語句更好的方法來編寫此程式碼。我正在尋找一種處理器效率更高的方法來編寫這個查詢。
SELECT (count(refinst) * 100)::numeric / NULLIF(count(*), 0) AS refinst_pct -- count(refinst) * 100.0 / NULLIF(count(*), 0) AS refinst_pct -- simpler FROM patients;
- 不要使用子選擇。兩個聚合都可以從同一個查詢派生。更便宜。
- 此外,這不是視窗函式的情況,因為您想要計算單個結果,而不是每行一個結果。
- 轉換為任何支持小數位數的數字類型,例如@a_horse 已經解釋過。
因為你想要
round()
兩個小數位數,我建議**numeric
**(這與 Postgres 中的相同decimal
)。在計算中輸入一個
值 就足夠了,最好是第一個。Postgres 自動選擇不失去資訊的類型。 或者,更簡單:因為我們無論如何都要相乘,所以使用一個由於小數點()而自動強制轉換為的數字常量。numeric``100.0
- 在除法之前乘以通常是個好主意。這通常可以最大限度地減少舍入誤差並且更便宜。
在這種情況下,第一個乘法 (
count(refinst) * 100
) 可以用廉價而精確的integer
算術計算。只有這樣我們才能轉換numeric
為下一個並除以下一個integer
(我們不會額外轉換)。
NULLIF(count(*), 0)
防止被零除(引發異常)。如果根本沒有行,我們將 NULL 作為(未知)百分比。四捨五入為兩位小數:
SELECT round((count(refinst) * 100)::numeric / NULLIF(count(*), 0), 2) AS refinst_pct FROM patients;
您需要將除法中涉及的每個數字轉換為支持小數的類型:
select (count(refinst)::decimal / (select count(*) from patients)::decimal) * 100 as "Formula" from patients;
您可能還想嘗試使用視窗函式而不是標量子查詢。它可能會更快:
select (count(refinst)::decimal / (count(*) over ())::decimal) * 100 as "Formula" from patients;