我的表格中包含以下数据
Group Start Date End Date
A 01/01/01 01/03/01
A 01/01/01 01/02/01
A 01/03/01 01/04/01
B 01/01/01 01/01/01
ETC
我希望制作一个能够计算每一天的视图,就像这样
Group Date Count
A 01/01/01 2
A 01/02/01 2
A 01/03/01 2
A 01/04/01 1
B 01/01/01 1
我正在使用Oracle 9,我完全不知道如何处理这个问题,并且我正在寻找让我入门的任何想法。
注意:生成一个表来保存日期是不切实际的,因为我的最终产品必须分解为分钟。
答案 0 :(得分:3)
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
秒内完成。
有关详细信息,请参阅我的博客中的此条目:
答案 1 :(得分:2)
您可以使用这些SO中描述的方法:
基本上:使用生成的日历和GROUP BY列的子集连接。
SQL> WITH DATA AS (
2 SELECT 'A' grp, to_date('01/01/01') start_date, to_date('01/03/01') end_date FROM DUAL
3 UNION ALL SELECT 'A', to_date('01/01/01'), to_date('01/02/01') FROM DUAL
4 UNION ALL SELECT 'A', to_date('01/03/01'), to_date('01/04/01') FROM DUAL
5 UNION ALL SELECT 'B', to_date('01/01/01'), to_date('01/01/01') FROM DUAL
6 ), calendar AS (
7 SELECT to_date('01/01/01') + ROWNUM - 1 d
8 FROM dual
9 CONNECT BY LEVEL <= to_date('01/04/01') - to_date('01/01/01') + 1
10 )
11 SELECT data.grp, calendar.d, COUNT(*) cnt
12 FROM data
13 JOIN calendar ON calendar.d BETWEEN data.start_date AND data.end_date
14 GROUP BY data.grp, calendar.d;
GRP D CNT
--- ----------- ----------
A 04/01/2001 1
A 02/01/2001 2
B 01/01/2001 1
A 03/01/2001 2
A 01/01/2001 2
答案 2 :(得分:1)
通常我用数字表解决这类问题:
WITH Dates AS (
SELECT DateAdd(d, Numbers.Number - 1, '1/1/2001') AS Date
FROM Numbers
WHERE Numbers.Number BETWEEN 1 AND 100000 -- Arbitrary date range
)
SELECT GroupData.Group, Dates.Date, COUNT(*)
FROM Dates
LEFT JOIN GroupData
ON Dates.Date BETWEEN GroupData.StartDate AND GroupData.EndDate
GROUP BY GroupData.Group, Dates.Date
ORDER BY GroupData.Group, Dates.Date