2011-06-27 91 views
4

我有用戶表。每個用戶都有一個國家。我想要的是獲得所有國家的用戶數量和百分比/總數的列表。到目前爲止,我所擁有的是:%到PostgreSQL的總量沒有子查詢

SELECT 
country_id, 
COUNT(*) AS total, 
((COUNT(*) * 100)/(SELECT COUNT(*) FROM users WHERE cond1 = true AND cond2 = true AND cond3 = true)::decimal) AS percent 
FROM users 
WHERE cond1 = true AND cond2 = true AND cond3 = true 
GROUP BY contry_id 

這兩個查詢的條件都是相同的。我試圖在沒有子查詢的情況下執行此操作,但是我無法獲得每個國家/地區的總用戶數。有沒有辦法做到這一點沒有子查詢?我正在使用PostgreSQL。任何幫助,高度讚賞。 在此先感謝

回答

2

我不是PostgreSQL用戶,但是,一般的解決辦法是使用窗口功能。

閱讀上如何使用這個在http://developer.postgresql.org/pgdocs/postgres/tutorial-window.html

最好的解釋,我可以用它來形容,那就是:基本上它可以讓你通過在一個領域做一組沒有group by子句。

我相信這可能做的伎倆:

SELECT 
    country_id, 
    COUNT(*) OVER (country_id) 
    ((COUNT(*) OVER (country_id)) * 100)/COUNT(*) OVER())::decimal) as percent 
FROM 
    users 
WHERE 
    cond1 = true AND cond2 = true AND cond3 = true 
+1

謝謝!不過,我現在已經升級我的PostgreSQL:d – fanjabi

+0

其實這個查詢將產生每行1個輸出行的用戶表,所以你需要一個GROUP BY。看到我的答案。 – peufeu

+1

@peufeu:我從未寫過窗口函數,也沒有測試過。似乎我需要閱讀更多的語法。 – Nightwolf

8

我猜你想消除子查詢的原因是爲了避免掃描用戶表的兩倍。記住總數是每個國家的總數。

WITH c AS (SELECT country_id, count(*) AS cnt FROM users WHERE cond1=... GROUP BY country_id) 
SELECT *, 100.0*cnt/(SELECT sum(cnt) FROM c) AS percent FROM c; 

此查詢使用每個國家/地區的統計信息構建一個小型CTE。它只會掃描一次用戶表,並生成一個小的結果集(每個國家只有一行)。

總(SELECT SUM(CNT)FROM c)的這個小的結果集只計算一次,因此它可以忽略不計使用時間。

你也可以使用一個窗口函數:

SELECT country_id, cnt, 100.0*cnt/(sum(cnt) OVER()) AS percent 
FROM (SELECT country_id, count(*) as cnt from users group by country_id) foo; 

(這是一樣的nightwolf與去除笑錯誤查詢)

兩個查詢花費大約在同一時間。

+0

謝謝!會不會給它一個嘗試,直到升級;) – fanjabi

+0

嗯...我得到一個錯誤: '錯誤:語法錯誤或接近 「用C」 LINE 1與C AS(SELECT ^ **** ******錯誤********** 錯誤:在「WITH c」處或附近出現語法錯誤 SQL狀態:42601 字符:1' – fanjabi

+0

對於WITH cte's,您需要8.4版本表表達式)和窗口函數... – peufeu