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
Opdatering:
En bedre og hurtigere forespørgsel, der gør brug af analytiske funktioner.
Hovedideen er, at antallet af intervaller, der indeholder hver dato, er forskellen før antallet af intervaller, der startede før denne dato, og antallet af intervaller, der sluttede før den.
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
Denne forespørgsel afsluttes i 1
sekund på 1,000,000
rækker.
Se dette indlæg i min blog for flere detaljer: