您可以 运行 Oracle 的 AVG() 函数处理同一行中的值吗?
Can you run Oracle's AVG() function on values in the same row?
我有这样的数据集:
+---------+--------+--------+
| Student | Score1 | Score2 |
+---------+--------+--------+
| 1 | 23 | 40 |
| 2 | 12 | 10 |
| 3 | 54 | 90 |
+---------+--------+--------+
我想计算每行 2 个分数的平均值。从理论上讲,这非常简单 - 只需执行 (score1 + score2/2)
。但是,如果其中一个值是 NULL,我 运行 就会遇到问题,必须大量使用 NVL
。 AVG()
函数会为我处理所有这些,但这是为计算多行的平均值而设计的。有什么方法可以对同一行中的值使用 AVG?
更新
这就是我目前所拥有的,它处理了所有的可能性(据我所知)。但是,我认为必须有更清洁的方法吗?
SELECT
T1.STUDENT,
T1.SCORE1,
T1.SCORE2,
(NVL(T1.SCORE1,0) + NVL(T1.SCORE2,0))/DECODE((NVL2(t1.SCORE1,1,0) + NVL2(t1.SCORE2,1,0)),0,NULL,(NVL2(t1.SCORE1,1,0) + NVL2(t1.SCORE2,1,0))) AS AVG_SCORE
FROM STUDENTS T1;
这个怎么样:
select student,
case
when score1 is null and score2 is not null then score2
when score1 is not null and score2 is null then score1
when score1 is null and score2 is null then 0
else (score1 + score2)/2 end
from your_table
你的方法很好。我会写成:
select student,
((coalesce(score1, 0) + coalesce(score2, 0)) /
nullif(nvl2(score1, 1, 0) + nvl2(score2, 1, 0), 0)
) as score_avg
这种方法(或者你问题中的方法)的优点是容易加分。
就是说,具有基本相同名称的列表明您应该使用联结 table 而不是多个列。
另一种方法是使用 UNION ALL
将您的分数列统一为一个,然后使用普通的 AVG
/ GROUP BY
:
SELECT student, avg(score) AS score
FROM (SELECT T1.STUDENT,
T1.SCORE1 AS score
FROM STUDENTS T1
UNION ALL
SELECT T1.STUDENT,
T1.SCORE2 AS score
FROM STUDENTS T1)
GROUP BY student
ORDER BY student
这个呢?
select student, avg(scorevalue) from
(select s1.student, 1 as scorefield, s1.score1 as scorevalue from students s1
union
select s2.student, 2 as scorefield, s2.score2 as scorevalue from students s2)
group by student
我有这样的数据集:
+---------+--------+--------+
| Student | Score1 | Score2 |
+---------+--------+--------+
| 1 | 23 | 40 |
| 2 | 12 | 10 |
| 3 | 54 | 90 |
+---------+--------+--------+
我想计算每行 2 个分数的平均值。从理论上讲,这非常简单 - 只需执行 (score1 + score2/2)
。但是,如果其中一个值是 NULL,我 运行 就会遇到问题,必须大量使用 NVL
。 AVG()
函数会为我处理所有这些,但这是为计算多行的平均值而设计的。有什么方法可以对同一行中的值使用 AVG?
更新
这就是我目前所拥有的,它处理了所有的可能性(据我所知)。但是,我认为必须有更清洁的方法吗?
SELECT
T1.STUDENT,
T1.SCORE1,
T1.SCORE2,
(NVL(T1.SCORE1,0) + NVL(T1.SCORE2,0))/DECODE((NVL2(t1.SCORE1,1,0) + NVL2(t1.SCORE2,1,0)),0,NULL,(NVL2(t1.SCORE1,1,0) + NVL2(t1.SCORE2,1,0))) AS AVG_SCORE
FROM STUDENTS T1;
这个怎么样:
select student,
case
when score1 is null and score2 is not null then score2
when score1 is not null and score2 is null then score1
when score1 is null and score2 is null then 0
else (score1 + score2)/2 end
from your_table
你的方法很好。我会写成:
select student,
((coalesce(score1, 0) + coalesce(score2, 0)) /
nullif(nvl2(score1, 1, 0) + nvl2(score2, 1, 0), 0)
) as score_avg
这种方法(或者你问题中的方法)的优点是容易加分。
就是说,具有基本相同名称的列表明您应该使用联结 table 而不是多个列。
另一种方法是使用 UNION ALL
将您的分数列统一为一个,然后使用普通的 AVG
/ GROUP BY
:
SELECT student, avg(score) AS score
FROM (SELECT T1.STUDENT,
T1.SCORE1 AS score
FROM STUDENTS T1
UNION ALL
SELECT T1.STUDENT,
T1.SCORE2 AS score
FROM STUDENTS T1)
GROUP BY student
ORDER BY student
这个呢?
select student, avg(scorevalue) from
(select s1.student, 1 as scorefield, s1.score1 as scorevalue from students s1
union
select s2.student, 2 as scorefield, s2.score2 as scorevalue from students s2)
group by student