1

我有两个表,我想根据其中一列中的值加入和拆分 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 收集单行上每个位置的所有平均值?我尝试按位置删除组,仅按 sampleID 分组,但我只获得第一个位置的值,其他所有值都变为 0。

任何帮助表示赞赏,谢谢!

4

2 回答 2

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
于 2013-08-23T09:18:39.013 回答
2

我添加了另一个答案,解释了查询的AVG(case ..when ... then..end)工作原理,以及为什么版本case ... when ... then AVG(..) end没有给出预期的结果。

第一条评论:查询的 ANSI SQL 标准group by如下:

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(price),
2. 然后计算 CASE WHEN ... THEN,但对于从点 1 的聚合查询返回的结果集

带有子句 AVG( case when ... then ) 的查询:
1. 首先计算表达式 CASE-WHEN-THEN 为所有表行
2. 然后对 #1 返回的结果集运行聚合查询并计算 AVG。

于 2013-08-24T19:16:05.647 回答