我有包含开始日期和结束日期的项目列表。项目属于用户。对于一个项目,期限可以为1 - 5年。我想找到我将从查询传递的给定日期范围之间的天数。期间始终为sysdate
,结束sysdate - 5 years
返回的天数也必须在期间范围内。
示例:
我从15.05.2015开始查询)因为我是用户,所以我需要找到所有天在2010年5月15日至2015年5月15日之间
在此期间,有2件物品属于我:
项目1)2010年1月1日 - 2010年12月31日。有效范围:15.05.2010 - 2010年12月31日= ~195天
项目2)2015年1月1日 - 2015年12月31日。有效范围:01.01.2015 - 2015年5月15日= ~170天
我需要这些日子的总和恰好在那个时期。
对于现在的查询,我只需要计算一个项目的全部范围(简化):
SELECT SUM(i.end_date - i.start_date) AS total_days
FROM items i
WHERE i.start_date >= to_date('2010-15-05', 'yyyy-mm-dd')
AND i.end_date <= to_date('2015-15-05', 'yyyy-mm-dd')
AND i.user = 'me'
所以现在这会给我一些2年期的日期,这是错误的,我应该如何更新我的选择金额以包括期间的日期?正确的结果将是195 + 170.目前我会得到365 + 365或其他东西。
答案 0 :(得分:1)
假设时间段没有重叠:
SELECT SUM(LEAST(i.end_date, DATE '2015-05-15') -
GREATEST(i.start_date, DATE '2010-05-15')
) AS total_days
FROM items i
WHERE i.start_date >= DATE '2010-05-15' AND
i.end_date <= DATE '2015-05-15' AND
i.user = 'me';
答案 1 :(得分:1)
使用案例陈述根据案例评估设定开始日期和结束日期的日期。
Select SUM(
(case when i.end_date > to_date('2015-15-05','yyyy-mm-dd') then
to_date('2015-15-05','yyyy-mm-dd') else
i.end_date end) -
(case when i.start_date< to_date('2010-15-05','yyyy-mm-dd') then
to_date('2010-15-05','yyyy-mm-dd') else
i.end_date end)) as total_days
FROM items i
WHERE i.start_date >= to_date('2010-15-05', 'yyyy-mm-dd')
AND i.end_date <= to_date('2015-15-05', 'yyyy-mm-dd')
AND i.user = 'me'
答案 2 :(得分:1)
期间始终为
sysdate
,结束sysdate - 5 years
您可以使用:SYSDATE
和SYSDATE - INTERVAL '5' YEAR
项目1)2010年1月1日 - 2010年12月31日。有效范围:15.05.2010 - 2010年12月31日 = ~195天
项目2)2015年1月1日 - 2015年12月31日。有效范围:01.01.2015 - 2015年5月15日 = ~170天
假设这些示例显示start_date
- end_date
,有效范围是您对该特定SYSDATE
的预期答案,那么您可以使用:
Oracle 11g R2架构设置:
CREATE TABLE items ( "user", start_date, end_date ) AS
SELECT 'me', DATE '2010-01-01', DATE '2010-12-31' FROM DUAL
UNION ALL SELECT 'me', DATE '2015-01-01', DATE '2015-12-31' FROM DUAL
UNION ALL SELECT 'me', DATE '2009-01-01', DATE '2009-12-31' FROM DUAL
UNION ALL SELECT 'me', DATE '2009-01-01', DATE '2016-12-31' FROM DUAL
UNION ALL SELECT 'me', DATE '2012-01-01', DATE '2012-12-31' FROM DUAL
UNION ALL SELECT 'me', DATE '2013-01-01', DATE '2013-01-01' FROM DUAL;
查询1 :
SELECT "user",
TO_CHAR( start_date, 'YYYY-MM-DD' ) AS start_date,
TO_CHAR( end_date, 'YYYY-MM-DD' ) AS end_date,
TO_CHAR( GREATEST(TRUNC(i.start_date), TRUNC(SYSDATE)-INTERVAL '5' YEAR), 'YYYY-MM-DD' ) AS valid_start,
TO_CHAR( LEAST(TRUNC(i.end_date),TRUNC(SYSDATE)), 'YYYY-MM-DD' ) AS valid_end,
LEAST(TRUNC(i.end_date),TRUNC(SYSDATE))
- GREATEST(TRUNC(i.start_date), TRUNC(SYSDATE)-INTERVAL '5' YEAR)
+ 1
AS total_days
FROM items i
WHERE i."user" = 'me'
AND TRUNC(i.start_date) <= TRUNC(SYSDATE)
AND TRUNC(i.end_date) >= TRUNC(SYSDATE) - INTERVAL '5' YEAR
<强> Results 强>:
| user | START_DATE | END_DATE | VALID_START | VALID_END | TOTAL_DAYS |
|------|------------|------------|-------------|------------|------------|
| me | 2010-01-01 | 2010-12-31 | 2010-05-21 | 2010-12-31 | 225 |
| me | 2015-01-01 | 2015-12-31 | 2015-01-01 | 2015-05-21 | 141 |
| me | 2009-01-01 | 2016-12-31 | 2010-05-21 | 2015-05-21 | 1827 |
| me | 2012-01-01 | 2012-12-31 | 2012-01-01 | 2012-12-31 | 366 |
| me | 2013-01-01 | 2013-01-01 | 2013-01-01 | 2013-01-01 | 1 |
这假设开始日期是在一天的开始(00:00),结束日期是在一天结束时(24:00) - 所以,如果开始和结束日期是相同的,那么您希望结果为1天(即00:00 - 24:00)。相反,如果您希望结果为0,则从总天数值的计算中删除+1
。
查询2 :
如果您想要所有这些有效范围的总和,并且乐于多次计算重叠范围内的日期,那么只需将其包装在SUM
聚合函数中:
SELECT SUM( LEAST(TRUNC(i.end_date),TRUNC(SYSDATE))
- GREATEST(TRUNC(i.start_date), TRUNC(SYSDATE)-INTERVAL '5' YEAR)
+ 1 )
AS total_days
FROM items i
WHERE i."user" = 'me'
AND TRUNC(i.start_date) <= TRUNC(SYSDATE)
AND TRUNC(i.end_date) >= TRUNC(SYSDATE) - INTERVAL '5' YEAR
<强> Results 强>:
| TOTAL_DAYS |
|------------|
| 2560 |
查询3 :
现在,如果您想获得该范围内所有有效天数的计数,而不是多次计算范围内的重叠,那么您可以这样做:
WITH ALL_DATES_IN_RANGE AS (
SELECT TRUNC(SYSDATE) - LEVEL + 1 AS valid_date
FROM DUAL
CONNECT BY LEVEL <= SYSDATE - (SYSDATE - INTERVAL '5' YEAR) + 1
)
SELECT COUNT(1) AS TOTAL_DAYS
FROM ALL_DATES_IN_RANGE a
WHERE EXISTS ( SELECT 'X'
FROM items i
WHERE a.valid_date BETWEEN i.start_date AND i.end_date
AND i."user" = 'me' )
<强> Results 强>:
| TOTAL_DAYS |
|------------|
| 1827 |