2010-03-30 324 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 - 你要重复,如果它们存在。