在Oracle中给出三个表Dates(date aDate,doUse boolean),Days(rangeId int,day int,qty int)和Range(rangeId int,startDate date)
我想加入这些,以便Range与aDate = startDate中的日期连接,其中doUse = 1,每天都是天。
给定一个范围可能会做类似这样的事情
SELECT rangeId, aDate, CASE WHEN doUse = 1 THEN qty ELSE 0 END AS qty
FROM (
SELECT aDate, doUse, SUM(doUse) OVER (ORDER BY aDate) day
FROM Dates
WHERE aDate >= :startDAte
) INNER JOIN (
SELECT rangeId, day,qty
FROM Days
WHERE rangeId = :rangeId
) USING (day)
ORDER BY day ASC
我想要做的是查询Range中的所有范围,而不仅仅是一个。
问题是连接值“day”取决于要计算的范围startDate,这给我在制定查询时遇到了一些麻烦。
请记住,日期表非常大,所以我想避免计算表中第一个日期的日期值,而每个范围天数不应超过100天左右。
编辑:示例数据
Dates Days
aDate doUse rangeId day qty
2008-01-01 1 1 1 1
2008-01-02 1 1 2 10
2008-01-03 0 1 3 8
2008-01-04 1 2 1 2
2008-01-05 1 2 2 5
Ranges
rangeId startDate
1 2008-01-02
2 2008-01-03
Result
rangeId aDate qty
1 2008-01-02 1
1 2008-01-03 0
1 2008-01-04 10
1 2008-01-05 8
2 2008-01-03 0
2 2008-01-04 2
2 2008-01-05 5
答案 0 :(得分:3)
试试这个:
SELECT rt.rangeId, aDate, CASE WHEN doUse = 1 THEN qty ELSE 0 END AS qty
FROM (
SELECT *
FROM (
SELECT r.*, t.*, SUM(doUse) OVER (PARTITION BY rangeId ORDER BY aDate) AS span
FROM (
SELECT r.rangeId, startDate, MAX(day) AS dm
FROM Range r, Days d
WHERE d.rangeid = r.rangeid
GROUP BY
r.rangeId, startDate
) r, Dates t
WHERE t.adate >= startDate
ORDER BY
rangeId, t.adate
)
WHERE
span <= dm
) rt, Days d
WHERE d.rangeId = rt.rangeID
AND d.day = GREATEST(rt.span, 1)
P上。 S.在我看来,将所有这些Dates
保留在数据库中的唯一要点是获得标记假期的连续日历。
您可以使用以下构造在Oracle中生成任意长度的日历:
SELECT :startDate + ROWNUM
FROM dual
CONNECT BY
1 = 1
WHERE rownum < :length
并且仅在Dates
中保留假期。一个简单的连接将显示哪些Dates
是假期,哪些不是。
答案 1 :(得分:1)
好的,也许我找到了办法。像这样:
SELECT irangeId, aDate + sum(case when doUse = 1 then 0 else 1) over (partionBy rangeId order by aDate) as aDate, qty
FROM Days INNER JOIN (
select irangeId, startDate + day - 1 as aDate, qty
from Range inner join Days using (irangeid)
) USING (aDate)
现在我只需要一种填写缺失日期的方法......
编辑:不,这样就意味着我会错过最后日期的doUse vaue ......