2010-03-30 241 views
2

我需要在 - 而不是一個 - 時尚平均一些值。 (如果我在列平均水平上,我可以使用avg())。我的具體應用要求我在平均時忽略NULL。這是非常簡單的邏輯,但在SQL中看起來非常困難。有沒有一個優雅的方式來做我的計算?在SQLite3中計算多列平均值

我正在使用SQLite3,它的價值。

詳細

如果您需要更多的細節,這裏就是一個例證:

我有一個調查AA表:

| q1 | q2 | q3 | ... | q144 | 
|----|-------|-------|-----|------| 
| 1 | 3  | 7  | ... | 2 | 
| 4 | 2  | NULL | ... | 1 | 
| 5 | NULL | 2  | ... | 3 | 

(這些只是一些示例值和簡單的列名稱,有效值爲1到7,NULL)

我需要計算一些平均值,如下所示:

q7 + q33 + q38 + q40 + ... + q119/11 as domain_score_1 
q10 + q11 + q34 + q35 + ... + q140/13 as domain_score_2 
... 
q2 + q5 + q13 + q25 + ... + q122/12 as domain_score_14 

......但我需要根據非空值提取出空值和平均值。因此,對於domain_score_1(其中有11個項目),我需要做的:

Input: 3, 5, NULL, 7, 2, NULL, 3, 1, 5, NULL, 1 

(3 + 5 + 7 + 2 + 3 + 1 + 5 + 1)/(11 - 3) 
27/8 
3.375 

一個簡單的算法,我在考慮是:

輸入:

3, 5, NULL, 7, 2, NULL, 3, 1, 5, NULL, 1 

凝聚每個值0如果NULL:

3, 5, 0, 7, 2, 0, 3, 1, 5, 0, 1 

總:

27 

的值轉換> 0至1和獲取非零的個數:

3, 5, 0, 7, 2, 0, 3, 1, 5, 0, 1 
1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1 
8 

除以這兩個數字

27/8 
3.375 

但是,這似乎是比這更多的編程應該採取。有沒有這樣做的優雅方式,我不知道?

更新:

除非我誤解的東西,avg()不會爲這方面的工作。我想什麼爲例做:

select avg(q7, q33, q38, ..., q119) from survey; 

輸出:

SQL error near line 3: wrong number of arguments to function avg() 
+2

我認爲DB在你的形式不被標準化,所以沒有簡單的方法來處理數據的「設置爲本」的方式。 – munissor 2010-03-30 15:40:52

+0

我已更新我的回答,以反映您對'AVG'的更新問題。 – Welbog 2010-03-30 15:49:19

+0

關於規範化問題,這是數據在當前數據庫中的存在方式。 (我沒有設計它 - 嚴格來說,有144列以上 - 但我必須選擇我的戰鬥。)我可能會咬緊牙關,寫一些東西來規範化處理。 – 2010-03-30 16:21:28

回答

4

在標準的SQL

SELECT 
(SUM(q7)+SUM(q33)+SUM(q38)+SUM(q40)+..+SUM(q119))/ 
(COUNT(q7)+COUNT(q33)+COUNT(q38)+COUNT(q40)+..+COUNT(q119)) AS domain_score1 
FROM survey 

會給你想要的,如果空SUM將合併爲0,計數將不計空值的。 (希望SQLite3符合)。

編輯:經過了http://www.sqlite.org/lang_aggfunc.html和SQLite一致;如果sum()將溢出,則可以使用total()來代替。

而且我第二次的意見重新正常化,如果你不正常化你的表設計(每當您自己的名字看到數列舉紅旗),你是不會有優雅的SQL。

+0

我最終選擇了類似於你的建議。 (對於其他人,它是'(coalesce(#{question},0)+ ...)/((當#{question}> 0 then 1 else 0 end)+ ...)')喜歡規範化,但目前並不值得 - 這可能是我們最後一次查看這些數據。 (我來回了一段時間,並認定在這種情況下黑客是一個更好的選擇。) – 2010-03-30 17:32:40

4

AVG已經忽略空和你想要做什麼:

的AVG()函數返回平均值所有非空X在一個組中。看起來不像數字的字符串和BLOB值被解釋爲0.只要至少有一個非NULL輸入,即使所有輸入都是整數,avg()的結果也總是浮點值。當且僅當沒有非NULL輸入時,avg()的結果爲NULL。

http://www.sqlite.org/lang_aggfunc.html

所以,你大概可以帶你每個域有值,並將其加載到另一個表,然後只需運行該表上的平均水平。或者,您也可以將廣泛的表格轉換爲平均值,然後運行平均值。


AVG適用於列而不是行。因此,如果您未使用表格,則可以使用AVG,而不會遇到您面臨的問題。讓我們看一個小例子:

你有一個表,它看起來像這樣:

ID | q1 | q2 | q3 
---------------------- 
1 | 1 | 2 | NULL 
2 | NULL| 2 | 56 

你要平均Q1和Q2在一起,因爲他們是在同一個域中,但他們是獨立的列,所以你不能。但是,如果你改變了你的表是這樣的:通過ID,如果你想每個ID的平均

SELECT AVG(value) 
FROM Table 
WHERE question IN (1,2) 

,你可以組:

ID | question | value 
----------------------- 
1 | 1  | 1 
1 | 2  | 2 
1 | 3  | NULL 
2 | 1  | NULL 
2 | 2  | 2 
2 | 3  | 56 

然後,你可以輕鬆拍攝的兩個問題的平均而不是全球平均水平:

SELECT ID, AVG(value) 
FROM Table 
WHERE question IN (1,2) 
GROUP BY ID 
+0

除非我誤解,'avg()'解決了另一個問題。我正在更新這個問題。 – 2010-03-30 15:41:20

+0

它確實解決了一個不同的問題,所以我建議您將問題轉換爲AVG通過重新分配表來解決的問題。 – Welbog 2010-03-30 15:43:37

+0

啊,我錯過了。感謝您的更新 - 它看起來像我在找什麼。 – 2010-03-30 15:52:04

1

使用單獨的表來存儲不同問題的調查分數(假設q是因爲問題)。像下面

SurveyTable(SurveyId, ...) 
SurveyRatings(SurveyId, QuestionId, Rating) 

之後,你可以像

SELECT avg(Rating) WHERE SurveyId=? 
2

這將是一個可怕的查詢運行查詢,但你可以做這樣的東西:

SELECT AVG(q) FROM 
((SELECT q7 AS q FROM survey) UNION ALL 
(SELECT q33 FROM survey) UNION ALL 
(SELECT q38 FROM survey) UNION ALL 
... 
(SELECT q119 FROM survey)) 

該功能可將您的列到行並使用AVG()函數。

當然,你可能想這只是一個特定的調查記錄,所以不要忘記在WHERE子句:

SELECT AVG(q) FROM 
((SELECT q7 AS q FROM survey WHERE survey_id = 1) UNION ALL 
(SELECT q33 FROM survey WHERE survey_id = 1) UNION ALL 
(SELECT q38 FROM survey WHERE survey_id = 1) UNION ALL 
... 
(SELECT q119 FROM survey WHERE survey_id = 1)) 

你得輕鬆了不少時間,如果你歸一Q列到他們的自己的表格,每行一個問題,以及參考調查。調查和問題之間有一對多的關係。

+2

'AVG'由SQL標準定義,在計算列的平均值時忽略空值。此外,SQLite的文檔清楚地表明'AVG'忽略NULL,所以即使它不是標準,它仍然適用於此。所以請停止傳播這樣的錯誤信息。 – Welbog 2010-03-30 16:09:59

+1

正如你所說,修復了AVG()的工作原理。 – 2010-03-30 20:55:14

0

用途:

SELECT AVG(x.answer) 
    FROM (SELECT s.q7 AS answer 
      FROM SURVEY s 
     UNION ALL 
     SELECT s.q33 
      FROM SURVEY s 
     UNION ALL  
     SELECT s.q38 
     FROM SURVEY s 
     ... 
     UNION ALL 
     SELECT s.q119 
     FROM SURVEY s) x 

不要使用UNION - 你要重複,如果它們存在。