regexp_substrを使用すればそれほど悪くはありません:
CREATE TABLE tablet (durationhm VARCHAR2(20));
INSERT INTO tablet VALUES ('5 hrs 5 min');
INSERT INTO tablet VALUES ('2 hrs 20 min');
INSERT INTO tablet VALUES ('1 hrs 29 min');
INSERT INTO tablet VALUES ('1 hrs 45 min');
INSERT INTO tablet VALUES ('4 hrs 10 min');
INSERT INTO tablet VALUES ('3 hrs 35 min');
INSERT INTO tablet VALUES ('1 min');
INSERT INTO tablet VALUES ('32 min');
INSERT INTO tablet VALUES ('1 hrs 16 min');
COMMIT;
SELECT (NVL(regexp_substr(durationhm, '([0-9]+) hrs', 1, 1, NULL, 1), 0) * 60
+ NVL(regexp_substr(durationhm, '([0-9]+) min', 1, 1, NULL, 1), 0)) AS number_of_minutes
FROM tablet;
NUMBER_OF_MINUTES
----------------------
305
140
89
105
250
215
1
32
76
SELECT AVG(NVL(regexp_substr(durationhm, '([0-9]+) hrs', 1, 1, NULL, 1), 0) * 60
+ NVL(regexp_substr(durationhm, '([0-9]+) min', 1, 1, NULL, 1), 0)) AS average_time
FROM tablet;
AVERAGE_TIME
----------------------
134,777777777777777777777777777777777778
SQLFiddle で確認してください: http://sqlfiddle.com/#!4/ad58c/1
編集: 申し訳ありませんが、#of_hours hrs #of_minutes min の形式で回答を得たいと思っていませんでした。見栄えが悪くなりますが、機能します (現時点では、見栄えの良いクエリを作成する方法がわかりません)。
SELECT
CASE
WHEN average_time >= 60 THEN trunc(average_time / 60) || ' hrs'
||
CASE
WHEN MOD(average_time, 60) = 0 THEN NULL
ELSE ' ' || MOD(average_time, 60) || ' min'
END
ELSE MOD(average_time, 60) || ' min'
END AS average_formatted
FROM (
SELECT TRUNC(AVG(NVL(regexp_substr(durationhm, '([0-9]+) hrs', 1, 1, NULL, 1), 0) * 60
+ NVL(regexp_substr(durationhm, '([0-9]+) min', 1, 1, NULL, 1), 0))) AS average_time
FROM tablet
);
さて、別の可能性を思いつきました(醜いですが):
SELECT
RTRIM(DECODE(TRUNC(average_time / 60), 0, NULL, trunc(average_time / 60) || ' hrs ') ||
DECODE(MOD(average_time, 60), 0, NULL, MOD(average_time, 60) || ' min'))
AS average_formatted
FROM (
SELECT TRUNC(AVG(NVL(regexp_substr(durationhm, '([0-9]+) hrs', 1, 1, NULL, 1), 0) * 60
+ NVL(regexp_substr(durationhm, '([0-9]+) min', 1, 1, NULL, 1), 0))) AS average_time
FROM tablet
);