问题
I have the following table data:
value
1
5
10.5
12
36
I want to map these values into:
range avg
0-21 (1 + 5 + 10.5 + 12) / 4
21.001-34 0
34.001-64 36
64 + 0
Basically map each value to ranges and calculate the avg of all values in each range.
I tried to do:
select
case
when avggeneral between 0 and 21 then ' 0-21'
when avggeneral between 21.00001 and 34 then ' 21-34'
when avggeneral between 34.00001 and 64 then ' 34-64'
else '64+'
end as 'range',
AVG(*) as 'avg'
from table
but this doesn't work... I don't know how to make the static ranges...
How can I do that in MySQL?
Methology should be: 1. Map values into these groups ( 0-21, 21-34 etc..) 2. calulate AVG in each group.
Desired output for above example is this:
range avg
0-21 7.125
21.001-34 0
34.001-64 36
64 + 0
The range
column is static. Always with 5 rows.
The avg
column is dynamic.. the values there are the actual AVGs of value
column.
回答1:
You could build a list of ranges using UNION ALL
and LEFT JOIN
with it:
SELECT CONCAT(IFNULL(ranges.min, '∞'), '-', IFNULL(ranges.max, '∞')) AS `range`, avg(value) AS avg
FROM (
SELECT 0 AS min, 21 AS max UNION ALL
SELECT 21, 34 UNION ALL
SELECT 34, 64 UNION ALL
SELECT 64, NULL
) AS ranges
LEFT JOIN t ON (ranges.min IS NULL OR value >= ranges.min) AND
(ranges.max IS NULL OR value < ranges.max)
GROUP BY ranges.min, ranges.max
Note that the above query will put 20.9999
inside [0-21)
and 21.0000
inside [21-34)
range.
回答2:
You can use UNION to get the desired result like below :
select '0-21' as Range1, coalesce(avg(avggeneral),0) as AVG from Table1
where avggeneral > 0 and avggeneral <= 21
union
select '21-34' as Range1, coalesce(avg(avggeneral),0) as AVG from Table1
where avggeneral > 21 and avggeneral <= 34
union
select '34-64' as Range1, coalesce(avg(avggeneral),0) as AVG from Table1
where avggeneral > 34 and avggeneral <= 64
union
select '64+' as Range1, coalesce(avg(avggeneral),0) as AVG from Table1
where avggeneral > 64
SQL HERE
回答3:
You don't really need to use those decimals.
Because for example, if the "value" equals 21, then the CASE
would already return the 0-21 range before evaluating the next WHEN
.
But you still need to group on the range.
And to return all the ranges, whether or not they are missing, you could left join to a sub-query with the ranges.
SELECT Ranges.`range`, COALESCE(AVG(Q.`value`), 0) as `avg`
FROM
(
SELECT 0 as `class`, ' 0-21' as `range`
UNION ALL SELECT 21, '21-34'
UNION ALL SELECT 34, '34-64'
UNION ALL SELECT 64, '64+'
) Ranges
LEFT JOIN
(
SELECT
`value`,
case
when `value` between 0 and 21 then 0
when `value` between 21 and 34 then 21
when `value` between 34 and 64 then 34
when `value` > 64 then 64
end as rangeclass
FROM test
) Q ON Q.rangeclass = Ranges.`class`
GROUP BY Ranges.`class`, Ranges.`range`
ORDER BY Ranges.`class`
db<>fiddle here
来源:https://stackoverflow.com/questions/53593388/mysql-how-to-get-avg-of-values-into-specific-range