我想要连接两个表,并根据其中一个列中的值使用case函数进行拆分。 (我知道,听起来很奇怪,所以让我解释一下)
这是我运行单独批次的过程。每批产品都有几个样品,这些样品是在多个位置的电压读数情况下测量的。我的两个表看起来像这样:
Sample Readings
id id
BatchesID SampleID
... voltage
... location
批量运行时,一次只需一个样本,每个位置(25个位置)需要大约20个电压读数才能进入下一个。
我想一次查看一个批处理,对于每个Sample.id,我想收集所有位置的AVG(电压)。我的阅读表格如下:
SampleID location voltage
1 1 5.23
1 1 4.53
... ... ...
1 25 7.89
2 1 4.96
2 1 5.04
... ... ...
2 25 6.09
...
但我希望它看起来像:
SampleID avg_v_for_1 avg_v_for_2 ... avg_v_for_25
1 4.73 5.24 ... 6.35
2 3.87 4.76 ... 9.32
... ... ... ... ...
200 6.73 3.87 ... 8.23
基本上,我想要做的是每个单独的样本,我想在每个位置获取所有测量的平均电压并放入一行。我目前的语法是这样的:
SELECT Readings.SampleID, Sample.BatchesID
(case when location = '1' then AVG(voltage) else 0 end) avg_v_for_1,
(case when location = '2' then AVG(voltage) else 0 end) avg_v_for_2,
...
(case when location = '25' then AVG(voltage) else 0 end) avg_v_for_25
FROM DB.Readings
INNER JOIN Sample
ON Readings.SampleID = Sample.id
WHERE Sample.BatchesID = 'specific_batch_id'
GROUP BY Readings.location, Sample.id;
问题是这会产生下表:
SampleID avg_v_for_1 avg_v_for_2 ... avg_v_for_25
1 4.73 0 ... 0
1 0 4.76 ... 0
1 0 0 ... 6.73
2 3.87 0 ... 0
2 0 4.83 ... 0
...
如何让MySQL收集SINGLE行上每个位置的所有平均值?我尝试按位置删除组,只按groupID分组,但之后我只获取第一个位置的值,其他所有值都变为0.
感谢任何帮助,谢谢!
答案 0 :(得分:2)
尝试:
SELECT Readings.SampleID, Sample.BatchesID
AVG(case when location = '1' then voltage else null end) avg_v_for_1,
AVG(case when location = '2' then voltage else null end) avg_v_for_2,
...
AVG(case when location = '25' then voltage else null end) avg_v_for_25
FROM DB.Readings
........
GROUP BY sample_id
---编辑 - >使用ifnull函数将空值更改为0
SELECT Readings.SampleID, Sample.BatchesID
ifnull( AVG(case when location = '1' then voltage else null end), 0 ) avg_v_for_1,
ifnull( AVG(case when location = '2' then voltage else null end), 0 ) avg_v_for_2,
...
ifnull( AVG(case when location = '25' then voltage else null end), 0 ) avg_v_for_25
FROM DB.Readings
........
GROUP BY sample_id
答案 1 :(得分:2)
我添加了另一个答案,解释了AVG(case ..when ... then..end)
的查询是如何工作的,以及case ... when ... then AVG(..) end
的版本为什么没有给出预期的结果。
第一句话:group by
查询的ANSI SQL标准如下:
SELECT column1, column2, ... column_n, aggregate_function (expression)
FROM tables
WHERE predicates
GROUP BY column1, column2, ... column_n;
其中aggregated_function
可以是如下函数:SUM,MAX,MIN,COUNT,AVG
GROUP BY CLASUE有几个规则(限制),详情请见此链接:http://etutorials.org/SQL/Mastering+Oracle+SQL/Chapter+4.+Group+Operations/4.2+The+GROUP+BY+Clause/
其中一人说:
GROUP BY子句必须包含所有非聚合表达式
这意味着SELECT子句中的所有列必须在GROUP BY子句中列出,
例如这个查询:
SELECT col1, col2, AVG( expression )
FROM table
GROUP BY col2
是错误的,因为col1未列在GROUP BY子句中,并且此查询不适用于所有数据库(Oracle,Postgresql,MS-SQL等) - 除了MySql(为什么 - 我会告诉它更高版本)。
无论GROUP BY子句中是否列出了列,聚合函数中的表达式都可以引用表的所有列。
由于以上查询:
SELECT Readings.SampleID,
(case when location = '1' then AVG(voltage) else 0 end) avg_v_for_1
....
GROUP BY sampleId
根本不适用于所有符合ANSI SQL的数据库,此查询会产生语法错误,因为location
不在AVG函数中,但未在GROUP BY子句中列出。
问题 - 为什么此查询适用于MySql?
因为MySql实现了它自己对GROUP BY查询的扩展,请参阅此链接 - > http://dev.mysql.com/doc/refman/5.6/en/group-by-extensions.html
在MySql中,选择列表可以引用GROUP BY子句中未列出的非聚合列。对于这个扩展,我们的查询在语法上是正确的并且在MySql上运行,但是会产生意外(不需要的)结果,因为表达式的评估顺序是不同的:
1.它首先运行聚合(分组依据)查询并评估AVG(价格),
2.然后评估CASE WHEN ...那么,但是对于来自点1的聚合查询返回的结果集
带有AVG子句的查询(当......时的情况):
1.首先为所有表格行表达CASE-WHEN-THEN表达式
2.然后对#1返回的结果集运行聚合查询并计算AVG。