WITH q AS
(
SELECT (
SELECT MIN(start_date)
FROM mytable
) + level - 1 AS mydate
FROM dual
CONNECT BY
level <= (
SELECT MAX(end_date) - MIN(start_date)
FROM mytable
)
)
SELECT group, mydate,
(
SELECT COUNT(*)
FROM mytable mi
WHERE mi.group = mo.group
AND q BETWEEN mi.start_date AND mi.end_date
)
FROM q
CROSS JOIN
(
SELECT DISTINCT group
FROM mytable
) mo
更新:
分析関数を利用した、より優れた高速クエリ。
主な考え方は、各日付を含む範囲の数は、その日付より前に開始された範囲の数と、その日付より前に終了した範囲の数の差であるということです。
SELECT cur_date,
grouper,
SUM(COALESCE(scnt, 0) - COALESCE(ecnt, 0)) OVER (PARTITION BY grouper ORDER BY cur_date) AS ranges
FROM (
SELECT (
SELECT MIN(start_date)
FROM t_range
) + level - 1 AS cur_date
FROM dual
CONNECT BY
level <=
(
SELECT MAX(end_date)
FROM t_range
) -
(
SELECT MIN(start_date)
FROM t_range
) + 1
) dates
CROSS JOIN
(
SELECT DISTINCT grouper AS grouper
FROM t_range
) groups
LEFT JOIN
(
SELECT grouper AS sgrp, start_date, COUNT(*) AS scnt
FROM t_range
GROUP BY
grouper, start_date
) starts
ON sgrp = grouper
AND start_date = cur_date
LEFT JOIN
(
SELECT grouper AS egrp, end_date, COUNT(*) AS ecnt
FROM t_range
GROUP BY
grouper, end_date
) ends
ON egrp = grouper
AND end_date = cur_date - 1
ORDER BY
grouper, cur_date
このクエリは1
で完了します 1,000,000
の2番目 行。
詳細については、ブログのこのエントリを参照してください: