我有一个这样的表(租):
user_rent| book_rent | rent_from | rent_to
-------------------------------------------
John Doe | Hobbit | 01.04.2018 | 18.05.2018
Jane Doe | Inferno | 12.07.2018 | 25.07.2018
Jane Doe | Hamlet | 12.07.2018 | 05.08.2018
Sara Doe | Macbeth | 01.06.2018 | 08.06.2018
Sara Doe | Othello | 08.06.2018 | 15.06.2018
我需要的是每个用户在一定时期内以其名义租借的图书的天数。有争议的期间是01.05.2018-31.07.2018
这里有三个不同的问题。
我的结果表应如下所示:
user_rent| days
-----------------
John Doe | 18
Jane Doe | 20
Sara Doe | 15
但是我听不懂:(
我将不胜感激。
编辑: 这是我的尝试,只能解决第一个问题...
SELECT USER_RENT, SUM(DIFF) DAYS
FROM
(
SELECT DISTINCT(USER_RENT), REAL_START, REAL_END, REAL_END-REAL_START+1 DIFF
FROM
(
SELECT DISTINCT(USER_RENT),
CASE WHEN RENT_FROM < '01.05.2018'
THEN TO_DATE(LAST_DAY(ADD_MONTHS(SYSDATE, -4))+1)
ELSE RENT_FROM
END REAL_START,
CASE WHEN RENT_TO > '31.07.2018'
THEN TO_DATE(LAST_DAY(ADD_MONTHS(SYSDATE, -1)))
ELSE RENT_TO
END REAL_END
FROM RENT
WHERE RENT_TO > '30.04.2018'
AND RENT_FROM < '01.08.2018'
)
)
GROUP BY USER_RENT
;
答案 0 :(得分:6)
您可以使用分层查询将日期范围扩展到所有日期:
select date '2018-05-01' + level - 1
from dual
connect by level <= date '2018-07-31' - date '2018-05-01' + 1
然后可以将其用作内联视图或CTE,并根据这些日期加入到rent
表中:
with days (day) as (
select date '2018-05-01' + level - 1
from dual
connect by level <= date '2018-07-31' - date '2018-05-01' + 1
)
select r.user_name, count(distinct d.day)
from days d
join rent r
on r.rent_from <= d.day
and r.rent_to >= d.day
group by r.user_name;
或者从12c开始,您可以使用cross apply
做同样的事情:
select r.user_name, count(distinct d.day) as days
from rent r
cross apply (
select date '2018-05-01' + level - 1 as day
from dual
connect by level <= date '2018-07-31' - date '2018-05-01' + 1
) d
where r.rent_from <= d.day
and r.rent_to >= d.day
group by r.user_name
order by r.user_name;
将示例数据与另一个CTE一起进行演示:
with rent (user_name, book, rent_from, rent_to) as (
select 'John Doe', 'Hobbit', date '2018-04-01', date '2018-05-18' from dual
union all select 'Jane Doe', 'Inferno', date '2018-07-12', date '2018-07-25' from dual
union all select 'Jane Doe', 'Hamlet', date '2018-07-12', date '2018-08-05' from dual
union all select 'Sara Doe', 'Macbeth', date '2018-06-01', date '2018-06-08' from dual
union all select 'Sara Doe', 'Othello', date '2018-06-08', date '2018-06-15' from dual
),
days (day) as (
select date '2018-05-01' + level - 1
from dual
connect by level <= date '2018-07-31' - date '2018-05-01' + 1
)
select r.user_name, count(distinct d.day) as days
from days d
join rent r
on r.rent_from <= d.day
and r.rent_to >= d.day
group by r.user_name
order by r.user_name;
USER_NAME DAYS
--------- ----------
Jane Doe 20
John Doe 18
Sara Doe 15
我已将示例中的列名称更改为合法值。