It is possible to do, although I make no positive guarantees about performance.
You need to find the upper and lower boundaries. This can be done by getting the max and min values, dividing each by 20, using floor / ceil to round them then multiplying by 20. Then cross join that with a sub query to generate a range of numbers (in 20s). Make sure this sub query gets a big enough range (in the example below it is generating 1000 ranges, so from 0 to 20000 max)
This will get you all the ranges. You can left join the actual data to count the actual number of values in each of those ranges.
Note that your example ranges have gone 1 to 20 and then 20 to 40. Thus any value of 20 would appear in 2 ranges. I have assumed 0 up to but not including 20 . If the values are integers you could generate ranges of 0-19, 20-39, etc.
SELECT sub1.lower_boundary, sub1.upper_boundary, COUNT(value)
FROM
(
SELECT FLOOR(MIN(value) / 20) * 20 AS min_boundary, CEIL(MAX(value) / 20) * 20 AS max_boundary
FROM sometable
) sub0
CROSS JOIN
(
SELECT (units.i + 10 * tens.i + 100 * hundreds.i) * 20 AS lower_boundary,(1 + units.i + 10 * tens.i + 100 * hundreds.i) * 20 AS upper_boundary
FROM
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) units,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) tens,
(SELECT 0 i UNION SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION SELECT 7 UNION SELECT 8 UNION SELECT 9) hundreds
) sub1
LEFT OUTER JOIN sometable a
ON a.Value >= sub1.lower_boundary
AND a.Value < sub1.upper_boundary
WHERE sub1.lower_boundary < max_boundary
AND sub1.upper_boundary > min_boundary
GROUP BY sub1.lower_boundary, sub1.upper_boundary
SQL fiddle here:-
http://www.sqlfiddle.com/#!2/cd535/3